Giving Analysis Servers it's own FlutterWebManager (#598)

diff --git a/benchmark/bench.dart b/benchmark/bench.dart
index ab6bd13..bf23ce1 100644
--- a/benchmark/bench.dart
+++ b/benchmark/bench.dart
@@ -13,18 +13,13 @@
 import 'package:dart_services/src/bench.dart';
 import 'package:dart_services/src/common.dart';
 import 'package:dart_services/src/compiler.dart';
-import 'package:dart_services/src/flutter_web.dart';
 
 void main(List<String> args) async {
   final json = args.contains('--json');
 
   final harness = BenchmarkHarness(asJson: json);
 
-  final flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
-  await flutterWebManager.warmup();
-
-  final compiler =
-      Compiler(SdkManager.sdk, SdkManager.flutterSdk, flutterWebManager);
+  final compiler = Compiler(SdkManager.sdk, SdkManager.flutterSdk);
 
   Logger.root.level = Level.WARNING;
   Logger.root.onRecord.listen((LogRecord record) {
diff --git a/lib/src/analysis_server.dart b/lib/src/analysis_server.dart
index 35ec013..3259650 100644
--- a/lib/src/analysis_server.dart
+++ b/lib/src/analysis_server.dart
@@ -15,6 +15,7 @@
 import 'package:pedantic/pedantic.dart';
 
 import 'common.dart';
+import 'common_server_impl.dart' show BadRequest;
 import 'flutter_web.dart';
 import 'protos/dart_services.pb.dart' as proto;
 import 'pub.dart';
@@ -35,9 +36,9 @@
 const Duration _ANALYSIS_SERVER_TIMEOUT = Duration(seconds: 35);
 
 class AnalysisServersWrapper {
-  AnalysisServersWrapper(this._flutterWebManager);
+  AnalysisServersWrapper();
 
-  final FlutterWebManager _flutterWebManager;
+  FlutterWebManager _flutterWebManager;
   DartAnalysisServerWrapper _dartAnalysisServer;
   FlutterAnalysisServerWrapper _flutterAnalysisServer;
 
@@ -57,9 +58,10 @@
   bool get isHealthy => (_restartingSince == null ||
       DateTime.now().difference(_restartingSince).inMinutes < 30);
 
-  Future<void> init() async {
+  Future<void> warmup() async {
     _logger.info('Beginning AnalysisServersWrapper init().');
     _dartAnalysisServer = DartAnalysisServerWrapper();
+    _flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
     _flutterAnalysisServer = FlutterAnalysisServerWrapper(_flutterWebManager);
 
     await _dartAnalysisServer.init();
@@ -83,19 +85,30 @@
     }));
 
     _restartingSince = null;
+
+    return Future.wait(<Future<dynamic>>[
+      _flutterWebManager.warmup(),
+      _flutterAnalysisServer.warmup(),
+      _dartAnalysisServer.warmup(),
+    ]);
   }
 
-  Future warmup() => Future.wait(<Future<dynamic>>[
-        _flutterAnalysisServer.warmup(),
-        _dartAnalysisServer.warmup(),
-      ]);
+  Future<void> _restart() async {
+    _logger.warning('Restarting');
+    await shutdown();
+    _logger.info('shutdown');
+
+    await warmup();
+    _logger.warning('Restart complete');
+  }
 
   Future<dynamic> shutdown() {
     _restartingSince = DateTime.now();
 
     return Future.wait(<Future<dynamic>>[
-      _dartAnalysisServer.shutdown(),
+      _flutterWebManager.dispose(),
       _flutterAnalysisServer.shutdown(),
+      _dartAnalysisServer.shutdown(),
     ]);
   }
 
@@ -106,23 +119,71 @@
         : _dartAnalysisServer;
   }
 
-  Future<proto.AnalysisResults> analyze(String source) =>
-      _getCorrectAnalysisServer(source).analyze(source);
+  Future<proto.AnalysisResults> analyze(String source) => _perfLogAndRestart(
+      source,
+      () => _getCorrectAnalysisServer(source).analyze(source),
+      'analysis',
+      'Error during analyze on "$source"');
 
   Future<proto.CompleteResponse> complete(String source, int offset) =>
-      _getCorrectAnalysisServer(source).complete(source, offset);
+      _perfLogAndRestart(
+          source,
+          () => _getCorrectAnalysisServer(source).complete(source, offset),
+          'completions',
+          'Error during complete on "$source" at $offset');
 
   Future<proto.FixesResponse> getFixes(String source, int offset) =>
-      _getCorrectAnalysisServer(source).getFixes(source, offset);
+      _perfLogAndRestart(
+          source,
+          () => _getCorrectAnalysisServer(source).getFixes(source, offset),
+          'fixes',
+          'Error during fixes on "$source" at $offset');
 
   Future<proto.AssistsResponse> getAssists(String source, int offset) =>
-      _getCorrectAnalysisServer(source).getAssists(source, offset);
+      _perfLogAndRestart(
+          source,
+          () => _getCorrectAnalysisServer(source).getAssists(source, offset),
+          'assists',
+          'Error during assists on "$source" at $offset');
 
   Future<proto.FormatResponse> format(String source, int offset) =>
-      _getCorrectAnalysisServer(source).format(source, offset);
+      _perfLogAndRestart(
+          source,
+          () => _getCorrectAnalysisServer(source).format(source, offset),
+          'format',
+          'Error during format on "$source" at $offset');
 
   Future<Map<String, String>> dartdoc(String source, int offset) =>
-      _getCorrectAnalysisServer(source).dartdoc(source, offset);
+      _perfLogAndRestart(
+          source,
+          () => _getCorrectAnalysisServer(source).dartdoc(source, offset),
+          'dartdoc',
+          'Error during dartdoc on "$source" at $offset');
+
+  Future<T> _perfLogAndRestart<T>(String source, Future<T> Function() body,
+      String action, String errorDescription) async {
+    await _checkPackageReferences(source);
+    try {
+      final watch = Stopwatch()..start();
+      final response = await body();
+      _logger.info('PERF: Computed $action in ${watch.elapsedMilliseconds}ms.');
+      return response;
+    } catch (e, st) {
+      _logger.severe(errorDescription, e, st);
+      await _restart();
+      rethrow;
+    }
+  }
+
+  /// Check that the set of packages referenced is valid.
+  Future<void> _checkPackageReferences(String source) async {
+    final imports = getAllImportsFor(source);
+
+    if (_flutterWebManager.hasUnsupportedImport(imports)) {
+      throw BadRequest(
+          'Unsupported input: ${_flutterWebManager.getUnsupportedImport(imports)}');
+    }
+  }
 }
 
 class DartAnalysisServerWrapper extends AnalysisServerWrapper {
diff --git a/lib/src/common_server_impl.dart b/lib/src/common_server_impl.dart
index 7c6c076..c383277 100644
--- a/lib/src/common_server_impl.dart
+++ b/lib/src/common_server_impl.dart
@@ -15,9 +15,7 @@
 import 'analysis_server.dart';
 import 'common.dart';
 import 'compiler.dart';
-import 'flutter_web.dart';
 import 'protos/dart_services.pb.dart' as proto;
-import 'pub.dart';
 import 'sdk_manager.dart';
 import 'server_cache.dart';
 
@@ -38,7 +36,6 @@
   final ServerContainer container;
   final ServerCache cache;
 
-  FlutterWebManager flutterWebManager;
   Compiler compiler;
   AnalysisServersWrapper analysisServers;
 
@@ -57,33 +54,17 @@
 
   Future<void> init() async {
     log.info('Beginning CommonServer init().');
-    flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
-    analysisServers = AnalysisServersWrapper(flutterWebManager);
-    compiler =
-        Compiler(SdkManager.sdk, SdkManager.flutterSdk, flutterWebManager);
+    analysisServers = AnalysisServersWrapper();
+    compiler = Compiler(SdkManager.sdk, SdkManager.flutterSdk);
 
-    await analysisServers.init();
-    log.info('Analysis servers initialized.');
-
-    await flutterWebManager.warmup();
     await compiler.warmup();
     await analysisServers.warmup();
   }
 
-  Future<void> restart() async {
-    log.warning('Restarting CommonServer');
-    await shutdown();
-    log.info('Analysis Servers shutdown');
-
-    await init();
-    log.warning('Restart complete');
-  }
-
   Future<dynamic> shutdown() {
     return Future.wait(<Future<dynamic>>[
       analysisServers.shutdown(),
       compiler.dispose(),
-      flutterWebManager.dispose(),
       Future<dynamic>.sync(cache.shutdown)
     ]).timeout(const Duration(minutes: 1));
   }
@@ -93,11 +74,7 @@
       throw BadRequest('Missing parameter: \'source\'');
     }
 
-    return _perfLogAndRestart(
-        request.source,
-        () => analysisServers.analyze(request.source),
-        'analysis',
-        'Error during analyze on "${request.source}"');
+    return analysisServers.analyze(request.source);
   }
 
   Future<proto.CompileResponse> compile(proto.CompileRequest request) {
@@ -125,11 +102,7 @@
       throw BadRequest('Missing parameter: \'offset\'');
     }
 
-    return _perfLogAndRestart(
-        request.source,
-        () => analysisServers.complete(request.source, request.offset),
-        'completions',
-        'Error during complete on "${request.source}" at ${request.offset}');
+    return analysisServers.complete(request.source, request.offset);
   }
 
   Future<proto.FixesResponse> fixes(proto.SourceRequest request) {
@@ -140,11 +113,7 @@
       throw BadRequest('Missing parameter: \'offset\'');
     }
 
-    return _perfLogAndRestart(
-        request.source,
-        () => analysisServers.getFixes(request.source, request.offset),
-        'fixes',
-        'Error during fixes on "${request.source}" at ${request.offset}');
+    return analysisServers.getFixes(request.source, request.offset);
   }
 
   Future<proto.AssistsResponse> assists(proto.SourceRequest request) {
@@ -155,11 +124,7 @@
       throw BadRequest('Missing parameter: \'offset\'');
     }
 
-    return _perfLogAndRestart(
-        request.source,
-        () => analysisServers.getAssists(request.source, request.offset),
-        'assists',
-        'Error during assists on "${request.source}" at ${request.offset}');
+    return analysisServers.getAssists(request.source, request.offset);
   }
 
   Future<proto.FormatResponse> format(proto.SourceRequest request) {
@@ -167,14 +132,10 @@
       throw BadRequest('Missing parameter: \'source\'');
     }
 
-    return _perfLogAndRestart(
-        request.source,
-        () => analysisServers.format(request.source, request.offset ?? 0),
-        'format',
-        'Error during format on "${request.source}" at ${request.offset}');
+    return analysisServers.format(request.source, request.offset ?? 0);
   }
 
-  Future<proto.DocumentResponse> document(proto.SourceRequest request) {
+  Future<proto.DocumentResponse> document(proto.SourceRequest request) async {
     if (!request.hasSource()) {
       throw BadRequest('Missing parameter: \'source\'');
     }
@@ -182,14 +143,10 @@
       throw BadRequest('Missing parameter: \'offset\'');
     }
 
-    return _perfLogAndRestart(
-        request.source,
-        () async => proto.DocumentResponse()
-          ..info.addAll(
-              await analysisServers.dartdoc(request.source, request.offset) ??
-                  <String, String>{}),
-        'dartdoc',
-        'Error during document on "${request.source}" at ${request.offset}');
+    return proto.DocumentResponse()
+      ..info.addAll(
+          await analysisServers.dartdoc(request.source, request.offset) ??
+              <String, String>{});
   }
 
   Future<proto.VersionResponse> version(proto.VersionRequest _) =>
@@ -210,8 +167,6 @@
     bool returnSourceMap = false,
   }) async {
     try {
-      await _checkPackageReferencesInitFlutterWeb(source);
-
       final sourceHash = _hashSource(source);
       final memCacheKey = '%%COMPILE:v0'
           ':returnSourceMap:$returnSourceMap:source:$sourceHash';
@@ -269,8 +224,6 @@
 
   Future<proto.CompileDDCResponse> _compileDDC(String source) async {
     try {
-      await _checkPackageReferencesInitFlutterWeb(source);
-
       final sourceHash = _hashSource(source);
       final memCacheKey = '%%COMPILE_DDC:v0:source:$sourceHash';
 
@@ -321,34 +274,6 @@
 
   Future<void> _setCache(String query, String result) =>
       cache.set(query, result, expiration: _standardExpiration);
-
-  /// Check that the set of packages referenced is valid.
-  ///
-  /// If there are uses of package:flutter, ensure that support there is
-  /// initialized.
-  Future<void> _checkPackageReferencesInitFlutterWeb(String source) async {
-    final imports = getAllImportsFor(source);
-
-    if (flutterWebManager.hasUnsupportedImport(imports)) {
-      throw BadRequest(
-          'Unsupported input: ${flutterWebManager.getUnsupportedImport(imports)}');
-    }
-  }
-
-  Future<T> _perfLogAndRestart<T>(String source, Future<T> Function() body,
-      String action, String errorDescription) async {
-    await _checkPackageReferencesInitFlutterWeb(source);
-    try {
-      final watch = Stopwatch()..start();
-      final response = await body();
-      log.info('PERF: Computed $action in ${watch.elapsedMilliseconds}ms.');
-      return response;
-    } catch (e, st) {
-      log.severe(errorDescription, e, st);
-      await restart();
-      rethrow;
-    }
-  }
 }
 
 String _printCompileProblem(CompilationProblem problem) => problem.message;
diff --git a/lib/src/compiler.dart b/lib/src/compiler.dart
index 280bcb3..b45fd9a 100644
--- a/lib/src/compiler.dart
+++ b/lib/src/compiler.dart
@@ -28,20 +28,22 @@
   final String _dartdevcPath;
   final BazelWorkerDriver _ddcDriver;
 
-  Compiler(this._sdk, this._flutterSdk, this._flutterWebManager)
+  Compiler(this._sdk, this._flutterSdk)
       : _dartdevcPath = path.join(_flutterSdk.sdkPath, 'bin', 'dartdevc'),
         _ddcDriver = BazelWorkerDriver(
             () => Process.start(
                   path.join(_flutterSdk.sdkPath, 'bin', 'dartdevc'),
                   <String>['--persistent_worker'],
                 ),
-            maxWorkers: 1);
+            maxWorkers: 1),
+        _flutterWebManager = FlutterWebManager(_flutterSdk);
 
   bool importsOkForCompile(Set<String> imports) {
     return !_flutterWebManager.hasUnsupportedImport(imports);
   }
 
-  Future<CompilationResults> warmup({bool useHtml = false}) {
+  Future<CompilationResults> warmup({bool useHtml = false}) async {
+    await _flutterWebManager.warmup();
     return compile(useHtml ? sampleCodeWeb : sampleCode);
   }
 
@@ -186,7 +188,10 @@
     }
   }
 
-  Future<void> dispose() => _ddcDriver.terminateWorkers();
+  Future<void> dispose() async {
+    await _flutterWebManager.dispose();
+    return _ddcDriver.terminateWorkers();
+  }
 }
 
 /// The result of a dart2js compile.
diff --git a/test/compiler_test.dart b/test/compiler_test.dart
index 2f39158..2f92115 100644
--- a/test/compiler_test.dart
+++ b/test/compiler_test.dart
@@ -6,7 +6,6 @@
 
 import 'package:dart_services/src/common.dart';
 import 'package:dart_services/src/compiler.dart';
-import 'package:dart_services/src/flutter_web.dart';
 import 'package:dart_services/src/sdk_manager.dart';
 import 'package:test/test.dart';
 
@@ -14,18 +13,14 @@
 
 void defineTests() {
   Compiler compiler;
-  FlutterWebManager flutterWebManager;
 
   group('compiler', () {
     setUpAll(() async {
       await SdkManager.sdk.init();
       await SdkManager.flutterSdk.init();
 
-      flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
-      await flutterWebManager.warmup();
-
-      compiler =
-          Compiler(SdkManager.sdk, SdkManager.flutterSdk, flutterWebManager);
+      compiler = Compiler(SdkManager.sdk, SdkManager.flutterSdk);
+      await compiler.warmup();
     });
 
     tearDownAll(() async {
diff --git a/test/flutter_analysis_server_test.dart b/test/flutter_analysis_server_test.dart
index ece0438..92cfaee 100644
--- a/test/flutter_analysis_server_test.dart
+++ b/test/flutter_analysis_server_test.dart
@@ -233,21 +233,16 @@
 
   group('Flutter SDK analysis_server with analysis servers', () {
     AnalysisServersWrapper analysisServersWrapper;
-    FlutterWebManager flutterWebManager;
 
     setUp(() async {
       await SdkManager.flutterSdk.init();
-      flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
-      await flutterWebManager.warmup();
 
-      analysisServersWrapper = AnalysisServersWrapper(flutterWebManager);
-      await analysisServersWrapper.init();
+      analysisServersWrapper = AnalysisServersWrapper();
       await analysisServersWrapper.warmup();
     });
 
     tearDown(() async {
       await analysisServersWrapper.shutdown();
-      await flutterWebManager.dispose();
     });
 
     test('analyze counter app', () async {
diff --git a/tool/fuzz_driver.dart b/tool/fuzz_driver.dart
index 6059e17..7516dda 100644
--- a/tool/fuzz_driver.dart
+++ b/tool/fuzz_driver.dart
@@ -16,7 +16,6 @@
 import 'package:dart_services/src/common.dart';
 import 'package:dart_services/src/common_server_impl.dart';
 import 'package:dart_services/src/compiler.dart' as comp;
-import 'package:dart_services/src/flutter_web.dart';
 import 'package:dart_services/src/sdk_manager.dart';
 import 'package:dart_services/src/server_cache.dart';
 import 'package:dart_services/src/protos/dart_services.pb.dart' as proto;
@@ -122,8 +121,6 @@
 
   print('SdKPath: $sdkPath');
 
-  final flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
-
   container = MockContainer();
   cache = MockCache();
   commonServerImpl = CommonServerImpl(container, cache);
@@ -136,8 +133,7 @@
   await analysisServer.warmup();
 
   print('Warming up compiler');
-  compiler =
-      comp.Compiler(SdkManager.sdk, SdkManager.flutterSdk, flutterWebManager);
+  compiler = comp.Compiler(SdkManager.sdk, SdkManager.flutterSdk);
   await compiler.warmup();
   print('SetupTools done');
 }