Use Cloud Run for all Dart Services (#623)

diff --git a/example/pubspec.lock b/example/pubspec.lock
index 1a2ffbc..99b1034 100644
--- a/example/pubspec.lock
+++ b/example/pubspec.lock
@@ -49,14 +49,14 @@
       name: build
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.5.1"
+    version: "1.6.0"
   build_config:
     dependency: transitive
     description:
       name: build_config
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.4.3"
+    version: "0.4.5"
   build_daemon:
     dependency: transitive
     description:
@@ -70,28 +70,28 @@
       name: build_modules
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "3.0.0"
+    version: "3.0.2"
   build_resolvers:
     dependency: transitive
     description:
       name: build_resolvers
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.4.3"
+    version: "1.5.1"
   build_runner:
     dependency: "direct dev"
     description:
       name: build_runner
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.10.6"
+    version: "1.10.11"
   build_runner_core:
     dependency: transitive
     description:
       name: build_runner_core
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "6.1.1"
+    version: "6.1.5"
   build_web_compilers:
     dependency: "direct dev"
     description:
@@ -126,7 +126,7 @@
       name: checked_yaml
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.0.2"
+    version: "1.0.4"
   cli_util:
     dependency: transitive
     description:
@@ -147,7 +147,7 @@
       name: codemirror
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.5.21+5.58.0"
+    version: "0.5.23+5.59.1"
   collection:
     dependency: transitive
     description:
@@ -343,7 +343,7 @@
       name: pubspec_parse
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.1.5"
+    version: "0.1.7"
   quiver:
     dependency: transitive
     description:
@@ -427,7 +427,7 @@
       name: timing
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.1.1+2"
+    version: "0.1.1+3"
   typed_data:
     dependency: transitive
     description:
diff --git a/lib/services_dev.dart b/lib/services_dev.dart
index c535398..d1aeaf5 100644
--- a/lib/services_dev.dart
+++ b/lib/services_dev.dart
@@ -23,8 +23,11 @@
 
 void main(List<String> args) {
   final parser = ArgParser();
-  parser.addOption('port', abbr: 'p', defaultsTo: '8080');
-  parser.addOption('server-url', defaultsTo: 'http://localhost');
+  parser
+    ..addOption('port', abbr: 'p', defaultsTo: '8080')
+    ..addOption('server-url', defaultsTo: 'http://localhost')
+    ..addOption('proxy-target',
+        help: 'URL base to proxy compilation requests to');
 
   final result = parser.parse(args);
   final port = int.tryParse(result['port'] as String);
@@ -40,14 +43,15 @@
     if (record.stackTrace != null) print(record.stackTrace);
   });
 
-  EndpointsServer.serve(port).then((EndpointsServer server) {
+  EndpointsServer.serve(port, result['proxy-target'].toString())
+      .then((EndpointsServer server) {
     _logger.info('Listening on port ${server.port}');
   });
 }
 
 class EndpointsServer {
-  static Future<EndpointsServer> serve(int port) {
-    final endpointsServer = EndpointsServer._(port);
+  static Future<EndpointsServer> serve(int port, String proxyTarget) {
+    final endpointsServer = EndpointsServer._(port, proxyTarget);
 
     return shelf
         .serve(endpointsServer.handler, InternetAddress.anyIPv4, port)
@@ -59,6 +63,7 @@
 
   final int port;
   HttpServer server;
+  final String proxyTarget;
 
   Pipeline pipeline;
   Handler handler;
@@ -66,11 +71,13 @@
   CommonServerApi commonServerApi;
   FlutterWebManager flutterWebManager;
 
-  EndpointsServer._(this.port) {
-    final commonServerImpl = CommonServerImpl(
-      _ServerContainer(),
-      _Cache(),
-    );
+  EndpointsServer._(this.port, this.proxyTarget) {
+    final commonServerImpl = (proxyTarget != null && proxyTarget.isNotEmpty)
+        ? CommonServerImplProxy(proxyTarget)
+        : CommonServerImpl(
+            _ServerContainer(),
+            _Cache(),
+          );
     commonServerApi = CommonServerApi(commonServerImpl);
     commonServerImpl.init();
 
diff --git a/lib/services_gae.dart b/lib/services_gae.dart
index 8c234c5..9d59760 100644
--- a/lib/services_gae.dart
+++ b/lib/services_gae.dart
@@ -30,7 +30,6 @@
 
 void main(List<String> args) {
   final parser = ArgParser()
-    ..addFlag('dark-launch', help: 'Dark launch proxied compilation requests')
     ..addOption('proxy-target',
         help: 'URL base to proxy compilation requests to')
     ..addOption('port',
@@ -55,16 +54,13 @@
   });
   log.info('''Initializing dart-services:
     --port: $gaePort
-    --dark-launch: ${results['dark-launch']}
     --proxy-target: ${results['proxy-target']}
     sdkPath: ${SdkManager.sdk?.sdkPath}
     \$REDIS_SERVER_URI: ${io.Platform.environment['REDIS_SERVER_URI']}
     \$GAE_VERSION: ${io.Platform.environment['GAE_VERSION']}
   ''');
 
-  final server = GaeServer(
-      io.Platform.environment['REDIS_SERVER_URI'],
-      results['dark-launch'].toString().toLowerCase() == 'true',
+  final server = GaeServer(io.Platform.environment['REDIS_SERVER_URI'],
       results['proxy-target'].toString());
   server.start(gaePort);
 }
@@ -74,25 +70,27 @@
 
   CommonServerImpl commonServerImpl;
   CommonServerApi commonServerApi;
+  bool proxying = false;
 
-  GaeServer(this.redisServerUri, bool darkLaunch, String proxyTarget) {
+  GaeServer(this.redisServerUri, String proxyTarget) {
     hierarchicalLoggingEnabled = true;
     recordStackTraceAtLevel = Level.SEVERE;
 
     _logger.level = Level.ALL;
 
-    commonServerImpl = CommonServerImpl(
-      GaeServerContainer(),
-      redisServerUri == null
-          ? InMemoryCache()
-          : RedisCache(
-              redisServerUri,
-              io.Platform.environment['GAE_VERSION'],
-            ),
-    );
     if (proxyTarget != null && proxyTarget.isNotEmpty) {
-      commonServerImpl =
-          CommonServerImplProxy(commonServerImpl, darkLaunch, proxyTarget);
+      commonServerImpl = CommonServerImplProxy(proxyTarget);
+      proxying = true;
+    } else {
+      commonServerImpl = CommonServerImpl(
+        GaeServerContainer(),
+        redisServerUri == null
+            ? InMemoryCache()
+            : RedisCache(
+                redisServerUri,
+                io.Platform.environment['GAE_VERSION'],
+              ),
+      );
     }
     commonServerApi = CommonServerApi(commonServerImpl);
   }
@@ -130,7 +128,9 @@
 
   Future _processReadinessRequest(io.HttpRequest request) async {
     _logger.info('Processing readiness check');
-    if (!commonServerImpl.isRestarting &&
+    if (proxying) {
+      request.response.statusCode = io.HttpStatus.ok;
+    } else if (!commonServerImpl.isRestarting &&
         DateTime.now().isBefore(_serveUntil)) {
       request.response.statusCode = io.HttpStatus.ok;
     } else {
@@ -143,7 +143,10 @@
 
   Future _processLivenessRequest(io.HttpRequest request) async {
     _logger.info('Processing liveness check');
-    if (!commonServerImpl.isHealthy || DateTime.now().isAfter(_serveUntil)) {
+    if (proxying) {
+      request.response.statusCode = io.HttpStatus.ok;
+    } else if (!commonServerImpl.isHealthy ||
+        DateTime.now().isAfter(_serveUntil)) {
       _logger.severe('CommonServer is no longer healthy.'
           ' Intentionally failing health check.');
       request.response.statusCode = io.HttpStatus.serviceUnavailable;
diff --git a/lib/src/common_server_impl.dart b/lib/src/common_server_impl.dart
index 7b78e03..f55234c 100644
--- a/lib/src/common_server_impl.dart
+++ b/lib/src/common_server_impl.dart
@@ -11,6 +11,7 @@
 import 'package:http/http.dart' as http;
 import 'package:logging/logging.dart';
 import 'package:pedantic/pedantic.dart';
+import 'package:protobuf/protobuf.dart' as $pb;
 
 import '../version.dart';
 import 'analysis_servers.dart';
@@ -34,141 +35,127 @@
 }
 
 class CommonServerImplProxy implements CommonServerImpl {
-  const CommonServerImplProxy(
-      this._wrapped, this._darkLaunch, this._proxyTarget);
-  final CommonServerImpl _wrapped;
+  const CommonServerImplProxy(this._proxyTarget);
   final String _proxyTarget;
-  final bool _darkLaunch;
+
+  Future<R> _postToProxy<R extends $pb.GeneratedMessage>(
+      String url, $pb.GeneratedMessage request, R responseProto) async {
+    final proxyResponse = http.post(url,
+        headers: {'Content-Type': 'application/json; charset=utf-8'},
+        body: _jsonEncoder.convert(request.toProto3Json()));
+
+    return proxyResponse.then((response) async {
+      if (response.statusCode == 200) {
+        return responseProto
+          ..mergeFromProto3Json(JsonDecoder().convert(response.body));
+      } else {
+        final err = proto.BadRequest.create()
+          ..mergeFromProto3Json(JsonDecoder().convert(response.body));
+        throw BadRequest(err.error.message);
+      }
+    });
+  }
 
   @override
-  Future<String> _checkCache(String query) => _wrapped._checkCache(query);
+  Future<proto.AnalysisResults> analyze(proto.SourceRequest request) {
+    final url = '${_proxyTarget}api/dartservices/v2/analyze';
+    return _postToProxy(url, request, proto.AnalysisResults.create());
+  }
 
   @override
-  Future<proto.CompileDDCResponse> _compileDDC(String source) =>
-      _wrapped._compileDDC(source);
-
-  @override
-  Future<proto.CompileResponse> _compileDart2js(String source,
-          {bool returnSourceMap = false}) =>
-      _wrapped._compileDart2js(source, returnSourceMap: returnSourceMap);
-
-  @override
-  Future<void> _setCache(String query, String result) =>
-      _wrapped._setCache(query, result);
-
-  @override
-  bool get analysisServersRunning => _wrapped.analysisServersRunning;
-
-  @override
-  Future<proto.AnalysisResults> analyze(proto.SourceRequest request) =>
-      _wrapped.analyze(request);
-
-  @override
-  Future<proto.AssistsResponse> assists(proto.SourceRequest request) =>
-      _wrapped.assists(request);
+  Future<proto.AssistsResponse> assists(proto.SourceRequest request) {
+    final url = '${_proxyTarget}api/dartservices/v2/assists';
+    return _postToProxy(url, request, proto.AssistsResponse.create());
+  }
 
   @override
   Future<proto.CompileResponse> compile(proto.CompileRequest request) {
     final url = '${_proxyTarget}api/dartservices/v2/compile';
-    final proxyResponse = http.post(url,
-        headers: {'Content-Type': 'application/json; charset=utf-8'},
-        body: _jsonEncoder.convert(request.toProto3Json()));
-    if (_darkLaunch) {
-      proxyResponse.then((response) {
-        log.info(
-            'compile: Proxied request returned status code: ${response.statusCode}');
-      });
-      return _wrapped.compile(request);
-    } else {
-      return proxyResponse.then((response) async {
-        if (response.statusCode == 200) {
-          return proto.CompileResponse.create()
-            ..mergeFromProto3Json(JsonDecoder().convert(response.body));
-        } else {
-          final err = proto.BadRequest.create()
-            ..mergeFromProto3Json(JsonDecoder().convert(response.body));
-          throw BadRequest(err.error.message);
-        }
-      });
-    }
+    return _postToProxy(url, request, proto.CompileResponse.create());
   }
 
   @override
   Future<proto.CompileDDCResponse> compileDDC(proto.CompileDDCRequest request) {
     final url = '${_proxyTarget}api/dartservices/v2/compileDDC';
-    final proxyResponse = http.post(url,
-        headers: {'Content-Type': 'application/json; charset=utf-8'},
-        body: _jsonEncoder.convert(request.toProto3Json()));
-    if (_darkLaunch) {
-      proxyResponse.then((response) {
-        log.info(
-            'compileDDC: Proxied request returned status code: ${response.statusCode}');
-      });
-      return _wrapped.compileDDC(request);
-    } else {
-      return proxyResponse.then((response) async {
-        if (response.statusCode == 200) {
-          return proto.CompileDDCResponse.create()
-            ..mergeFromProto3Json(JsonDecoder().convert(response.body));
-        } else {
-          final err = proto.BadRequest.create()
-            ..mergeFromProto3Json(JsonDecoder().convert(response.body));
-          throw BadRequest(err.error.message);
-        }
-      });
-    }
+    return _postToProxy(url, request, proto.CompileDDCResponse.create());
   }
 
   @override
-  Future<proto.CompleteResponse> complete(proto.SourceRequest request) =>
-      _wrapped.complete(request);
+  Future<proto.CompleteResponse> complete(proto.SourceRequest request) {
+    final url = '${_proxyTarget}api/dartservices/v2/complete';
+    return _postToProxy(url, request, proto.CompleteResponse.create());
+  }
 
   @override
-  Future<proto.DocumentResponse> document(proto.SourceRequest request) =>
-      _wrapped.document(request);
+  Future<proto.DocumentResponse> document(proto.SourceRequest request) {
+    final url = '${_proxyTarget}api/dartservices/v2/document';
+    return _postToProxy(url, request, proto.DocumentResponse.create());
+  }
 
   @override
-  Future<proto.FixesResponse> fixes(proto.SourceRequest request) =>
-      _wrapped.fixes(request);
+  Future<proto.FixesResponse> fixes(proto.SourceRequest request) {
+    final url = '${_proxyTarget}api/dartservices/v2/fixes';
+    return _postToProxy(url, request, proto.FixesResponse.create());
+  }
 
   @override
-  Future<proto.FormatResponse> format(proto.SourceRequest request) =>
-      _wrapped.format(request);
+  Future<proto.FormatResponse> format(proto.SourceRequest request) {
+    final url = '${_proxyTarget}api/dartservices/v2/format';
+    return _postToProxy(url, request, proto.FormatResponse.create());
+  }
 
   @override
-  Future<void> init() => _wrapped.init();
+  Future<proto.VersionResponse> version(proto.VersionRequest request) {
+    final url = '${_proxyTarget}api/dartservices/v2/version';
+    return _postToProxy(url, request, proto.VersionResponse.create());
+  }
 
   @override
-  bool get isHealthy => _wrapped.isHealthy;
+  Future<String> _checkCache(String query) => null;
 
   @override
-  bool get isRestarting => _wrapped.isRestarting;
+  Future<proto.CompileDDCResponse> _compileDDC(String source) => null;
 
   @override
-  Future shutdown() => _wrapped.shutdown();
+  Future<proto.CompileResponse> _compileDart2js(String source,
+          {bool returnSourceMap = false}) =>
+      null;
 
   @override
-  Future<proto.VersionResponse> version(proto.VersionRequest request) =>
-      _wrapped.version(request);
+  Future<void> _setCache(String query, String result) => null;
 
   @override
-  AnalysisServersWrapper get _analysisServers => _wrapped._analysisServers;
+  bool get analysisServersRunning => true;
 
   @override
-  Compiler get _compiler => _wrapped._compiler;
+  Future<void> init() => null;
 
   @override
-  ServerCache get _cache => _wrapped._cache;
+  bool get isHealthy => true;
 
   @override
-  ServerContainer get _container => _wrapped._container;
+  bool get isRestarting => false;
 
   @override
-  set _analysisServers(AnalysisServersWrapper __analysisServers) =>
-      _wrapped._analysisServers = __analysisServers;
+  Future shutdown() => null;
 
   @override
-  set _compiler(Compiler __compiler) => _wrapped._compiler = __compiler;
+  AnalysisServersWrapper get _analysisServers => null;
+
+  @override
+  Compiler get _compiler => null;
+
+  @override
+  ServerCache get _cache => null;
+
+  @override
+  ServerContainer get _container => null;
+
+  @override
+  set _analysisServers(AnalysisServersWrapper analysisServers) => null;
+
+  @override
+  set _compiler(Compiler compiler) => null;
 }
 
 final JsonEncoder _jsonEncoder = const JsonEncoder.withIndent('  ');
diff --git a/tool/grind.dart b/tool/grind.dart
index cbc8060..ec825cd 100644
--- a/tool/grind.dart
+++ b/tool/grind.dart
@@ -41,6 +41,18 @@
       arguments: ['bin/server_dev.dart', '--port', '8082']);
 }
 
+@Task()
+@Depends(buildStorageArtifacts)
+Future<void> serveWithProxyTarget() async {
+  await runWithLogging(Platform.executable, arguments: [
+    'bin/server_dev.dart',
+    '--port',
+    '8082',
+    '--proxy-target',
+    'https://dart-service-cloud-run-hdjctvyqtq-uc.a.run.app/'
+  ]);
+}
+
 final _dockerVersionMatcher = RegExp(r'^FROM google/dart-runtime:(.*)$');
 
 @Task('Update the docker and SDK versions')