blob: ee4cc8be9b4654c1049c1413d007fc8ab4d30d42 [file] [log] [blame]
// Copyright (c) 2019, 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.
import 'dart:async';
import 'package:build_daemon/data/build_status.dart';
import 'package:dwds/src/utilities/shared.dart';
import 'package:logging/logging.dart';
import 'package:meta/meta.dart';
import 'package:shelf/shelf.dart';
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';
import 'src/connections/app_connection.dart';
import 'src/connections/debug_connection.dart';
import 'src/handlers/asset_handler.dart';
import 'src/handlers/dev_handler.dart';
import 'src/handlers/injected_handler.dart';
import 'src/servers/devtools.dart';
import 'src/servers/extension_backend.dart';
export 'src/connections/app_connection.dart' show AppConnection;
export 'src/connections/debug_connection.dart' show DebugConnection;
typedef LogWriter = void Function(Level, String);
typedef ConnectionProvider = Future<ChromeConnection> Function();
enum ReloadConfiguration { none, hotReload, hotRestart, liveReload }
enum ModuleStrategy { requireJS, legacy }
/// The Dart Web Debug Service.
class Dwds {
final Handler handler;
final DevTools _devTools;
final DevHandler _devHandler;
Dwds._(this.handler, this._devTools, this._devHandler);
Stream<AppConnection> get connectedApps => _devHandler.connectedApps;
Future<void> stop() async {
await _devTools?.close();
await _devHandler.close();
}
Future<DebugConnection> debugConnection(AppConnection appConnection) async {
var appDebugServices = await _devHandler.loadAppServices(
appConnection.request.appId, appConnection.request.instanceId);
return DebugConnection(appDebugServices);
}
static Future<Dwds> start({
@required int applicationPort,
@required int assetServerPort,
@required String applicationTarget,
@required Stream<BuildResult> buildResults,
@required ConnectionProvider chromeConnection,
String hostname,
ReloadConfiguration reloadConfiguration,
bool serveDevTools,
LogWriter logWriter,
bool verbose,
bool enableDebugExtension,
ModuleStrategy moduleStrategy,
}) async {
hostname ??= 'localhost';
reloadConfiguration ??= ReloadConfiguration.none;
enableDebugExtension ??= false;
// `serveDevTools` is true by default when the extension is enabled.
serveDevTools = serveDevTools || enableDebugExtension;
logWriter ??= (level, message) => print(message);
verbose ??= false;
globalModuleStrategy = moduleStrategy ?? ModuleStrategy.requireJS;
var assetHandler = AssetHandler(
assetServerPort,
applicationTarget,
hostname,
applicationPort,
);
var cascade = Cascade();
var pipeline = const Pipeline();
DevTools devTools;
String extensionHostname;
int extensionPort;
ExtensionBackend extensionBackend;
if (enableDebugExtension) {
extensionBackend = await ExtensionBackend.start(hostname);
extensionHostname = extensionBackend.hostname;
extensionPort = extensionBackend.port;
}
pipeline = pipeline.addMiddleware(createInjectedHandler(reloadConfiguration,
extensionHostname: extensionHostname, extensionPort: extensionPort));
if (serveDevTools) {
devTools = await DevTools.start(hostname);
logWriter(Level.INFO,
'Serving DevTools at http://${devTools.hostname}:${devTools.port}\n');
}
var devHandler = DevHandler(
chromeConnection,
buildResults,
devTools,
assetHandler,
hostname,
verbose,
logWriter,
extensionBackend,
);
cascade = cascade.add(devHandler.handler).add(assetHandler.handler);
return Dwds._(pipeline.addHandler(cascade.handler), devTools, devHandler);
}
}