Split out analysis_servers (#599)

diff --git a/lib/src/analysis_server.dart b/lib/src/analysis_server.dart
index 3259650..a91ee05 100644
--- a/lib/src/analysis_server.dart
+++ b/lib/src/analysis_server.dart
@@ -12,10 +12,8 @@
 import 'package:analysis_server_lib/analysis_server_lib.dart';
 import 'package:logging/logging.dart';
 import 'package:path/path.dart' as path;
-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,157 +33,6 @@
 // Use very long timeouts to ensure that the server has enough time to restart.
 const Duration _ANALYSIS_SERVER_TIMEOUT = Duration(seconds: 35);
 
-class AnalysisServersWrapper {
-  AnalysisServersWrapper();
-
-  FlutterWebManager _flutterWebManager;
-  DartAnalysisServerWrapper _dartAnalysisServer;
-  FlutterAnalysisServerWrapper _flutterAnalysisServer;
-
-  bool get running =>
-      _dartAnalysisServer.analysisServer != null &&
-      _flutterAnalysisServer.analysisServer != null;
-
-  // If non-null, this value indicates that the server is starting/restarting
-  // and holds the time at which that process began. If null, the server is
-  // ready to handle requests.
-  DateTime _restartingSince = DateTime.now();
-
-  bool get isRestarting => (_restartingSince != null);
-
-  // If the server has been trying and failing to restart for more than a half
-  // hour, something is seriously wrong.
-  bool get isHealthy => (_restartingSince == null ||
-      DateTime.now().difference(_restartingSince).inMinutes < 30);
-
-  Future<void> warmup() async {
-    _logger.info('Beginning AnalysisServersWrapper init().');
-    _dartAnalysisServer = DartAnalysisServerWrapper();
-    _flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
-    _flutterAnalysisServer = FlutterAnalysisServerWrapper(_flutterWebManager);
-
-    await _dartAnalysisServer.init();
-    _logger.info('Dart analysis server initialized.');
-
-    await _flutterAnalysisServer.init();
-    _logger.info('Flutter analysis server initialized.');
-
-    unawaited(_dartAnalysisServer.onExit.then((int code) {
-      _logger.severe('dartAnalysisServer exited, code: $code');
-      if (code != 0) {
-        exit(code);
-      }
-    }));
-
-    unawaited(_flutterAnalysisServer.onExit.then((int code) {
-      _logger.severe('flutterAnalysisServer exited, code: $code');
-      if (code != 0) {
-        exit(code);
-      }
-    }));
-
-    _restartingSince = null;
-
-    return Future.wait(<Future<dynamic>>[
-      _flutterWebManager.warmup(),
-      _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>>[
-      _flutterWebManager.dispose(),
-      _flutterAnalysisServer.shutdown(),
-      _dartAnalysisServer.shutdown(),
-    ]);
-  }
-
-  AnalysisServerWrapper _getCorrectAnalysisServer(String source) {
-    final imports = getAllImportsFor(source);
-    return _flutterWebManager.usesFlutterWeb(imports)
-        ? _flutterAnalysisServer
-        : _dartAnalysisServer;
-  }
-
-  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) =>
-      _perfLogAndRestart(
-          source,
-          () => _getCorrectAnalysisServer(source).complete(source, offset),
-          'completions',
-          'Error during complete on "$source" at $offset');
-
-  Future<proto.FixesResponse> getFixes(String source, int offset) =>
-      _perfLogAndRestart(
-          source,
-          () => _getCorrectAnalysisServer(source).getFixes(source, offset),
-          'fixes',
-          'Error during fixes on "$source" at $offset');
-
-  Future<proto.AssistsResponse> getAssists(String source, int offset) =>
-      _perfLogAndRestart(
-          source,
-          () => _getCorrectAnalysisServer(source).getAssists(source, offset),
-          'assists',
-          'Error during assists on "$source" at $offset');
-
-  Future<proto.FormatResponse> format(String source, int 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) =>
-      _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 {
   Directory _tempProject;
   DartAnalysisServerWrapper() : super(SdkManager.sdk.sdkPath);
diff --git a/lib/src/analysis_servers.dart b/lib/src/analysis_servers.dart
new file mode 100644
index 0000000..766d80d
--- /dev/null
+++ b/lib/src/analysis_servers.dart
@@ -0,0 +1,172 @@
+// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// A wrapper around an analysis server instance
+library services.analysis_servers;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:logging/logging.dart';
+import 'package:pedantic/pedantic.dart';
+
+import 'analysis_server.dart';
+import 'common_server_impl.dart' show BadRequest;
+import 'flutter_web.dart';
+import 'protos/dart_services.pb.dart' as proto;
+import 'pub.dart';
+import 'sdk_manager.dart';
+
+final Logger _logger = Logger('analysis_servers');
+
+class AnalysisServersWrapper {
+  AnalysisServersWrapper();
+
+  FlutterWebManager _flutterWebManager;
+  DartAnalysisServerWrapper _dartAnalysisServer;
+  FlutterAnalysisServerWrapper _flutterAnalysisServer;
+
+  bool get running =>
+      _dartAnalysisServer.analysisServer != null &&
+      _flutterAnalysisServer.analysisServer != null;
+
+  // If non-null, this value indicates that the server is starting/restarting
+  // and holds the time at which that process began. If null, the server is
+  // ready to handle requests.
+  DateTime _restartingSince = DateTime.now();
+
+  bool get isRestarting => (_restartingSince != null);
+
+  // If the server has been trying and failing to restart for more than a half
+  // hour, something is seriously wrong.
+  bool get isHealthy => (_restartingSince == null ||
+      DateTime.now().difference(_restartingSince).inMinutes < 30);
+
+  Future<void> warmup() async {
+    _logger.info('Beginning AnalysisServersWrapper init().');
+    _dartAnalysisServer = DartAnalysisServerWrapper();
+    _flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
+    _flutterAnalysisServer = FlutterAnalysisServerWrapper(_flutterWebManager);
+
+    await _dartAnalysisServer.init();
+    _logger.info('Dart analysis server initialized.');
+
+    await _flutterAnalysisServer.init();
+    _logger.info('Flutter analysis server initialized.');
+
+    unawaited(_dartAnalysisServer.onExit.then((int code) {
+      _logger.severe('dartAnalysisServer exited, code: $code');
+      if (code != 0) {
+        exit(code);
+      }
+    }));
+
+    unawaited(_flutterAnalysisServer.onExit.then((int code) {
+      _logger.severe('flutterAnalysisServer exited, code: $code');
+      if (code != 0) {
+        exit(code);
+      }
+    }));
+
+    _restartingSince = null;
+
+    return Future.wait(<Future<dynamic>>[
+      _flutterWebManager.warmup(),
+      _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>>[
+      _flutterWebManager.dispose(),
+      _flutterAnalysisServer.shutdown(),
+      _dartAnalysisServer.shutdown(),
+    ]);
+  }
+
+  AnalysisServerWrapper _getCorrectAnalysisServer(String source) {
+    final imports = getAllImportsFor(source);
+    return _flutterWebManager.usesFlutterWeb(imports)
+        ? _flutterAnalysisServer
+        : _dartAnalysisServer;
+  }
+
+  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) =>
+      _perfLogAndRestart(
+          source,
+          () => _getCorrectAnalysisServer(source).complete(source, offset),
+          'completions',
+          'Error during complete on "$source" at $offset');
+
+  Future<proto.FixesResponse> getFixes(String source, int offset) =>
+      _perfLogAndRestart(
+          source,
+          () => _getCorrectAnalysisServer(source).getFixes(source, offset),
+          'fixes',
+          'Error during fixes on "$source" at $offset');
+
+  Future<proto.AssistsResponse> getAssists(String source, int offset) =>
+      _perfLogAndRestart(
+          source,
+          () => _getCorrectAnalysisServer(source).getAssists(source, offset),
+          'assists',
+          'Error during assists on "$source" at $offset');
+
+  Future<proto.FormatResponse> format(String source, int 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) =>
+      _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)}');
+    }
+  }
+}
diff --git a/lib/src/common_server_impl.dart b/lib/src/common_server_impl.dart
index c383277..e523307 100644
--- a/lib/src/common_server_impl.dart
+++ b/lib/src/common_server_impl.dart
@@ -12,7 +12,7 @@
 import 'package:pedantic/pedantic.dart';
 
 import '../version.dart';
-import 'analysis_server.dart';
+import 'analysis_servers.dart';
 import 'common.dart';
 import 'compiler.dart';
 import 'protos/dart_services.pb.dart' as proto;
diff --git a/test/flutter_analysis_server_test.dart b/test/flutter_analysis_server_test.dart
index 92cfaee..9791eca 100644
--- a/test/flutter_analysis_server_test.dart
+++ b/test/flutter_analysis_server_test.dart
@@ -6,6 +6,7 @@
 
 import 'package:dart_services/src/common.dart';
 import 'package:dart_services/src/analysis_server.dart';
+import 'package:dart_services/src/analysis_servers.dart';
 import 'package:dart_services/src/common_server_impl.dart';
 import 'package:dart_services/src/common_server_api.dart';
 import 'package:dart_services/src/flutter_web.dart';