Unverified Commit 7cbec567 authored by Helin Shiah's avatar Helin Shiah Committed by GitHub

Add daemon handler to start devtools (#62608)

parent f06ee8dd
......@@ -252,6 +252,12 @@ The returned `params` will contain:
- `emulatorName` - the name of the emulator created; this will have been auto-generated if you did not supply one
- `error` - when `success`=`false`, a message explaining why the creation of the emulator failed
### devtools domain
#### devtools.serve
The `serve()` command starts a DevTools server if one isn't already running and prints out the host and port of the server.
## 'flutter run --machine' and 'flutter attach --machine'
When running `flutter run --machine` or `flutter attach --machine` the following subset of the daemon is available:
......
......@@ -82,6 +82,7 @@ class Daemon {
_registerDomain(appDomain = AppDomain(this));
_registerDomain(deviceDomain = DeviceDomain(this));
_registerDomain(emulatorDomain = EmulatorDomain(this));
_registerDomain(devToolsDomain = DevToolsDomain(this));
// Start listening.
_commandSubscription = commandStream.listen(
......@@ -98,6 +99,7 @@ class Daemon {
AppDomain appDomain;
DeviceDomain deviceDomain;
EmulatorDomain emulatorDomain;
DevToolsDomain devToolsDomain;
StreamSubscription<Map<String, dynamic>> _commandSubscription;
int _outgoingRequestId = 1;
final Map<String, Completer<dynamic>> _outgoingRequestCompleters = <String, Completer<dynamic>>{};
......@@ -182,6 +184,7 @@ class Daemon {
void _send(Map<String, dynamic> map) => sendCommand(map);
Future<void> shutdown({ dynamic error }) async {
await devToolsDomain?.dispose();
await _commandSubscription?.cancel();
for (final Domain domain in _domainMap.values) {
await domain.dispose();
......@@ -886,6 +889,29 @@ class DeviceDomain extends Domain {
}
}
class DevToolsDomain extends Domain {
DevToolsDomain(Daemon daemon) : super(daemon, 'devtools') {
registerHandler('serve', serve);
}
DevtoolsLauncher _devtoolsLauncher;
Future<void> serve([ Map<String, dynamic> args ]) async {
_devtoolsLauncher ??= DevtoolsLauncher.instance;
final HttpServer server = await _devtoolsLauncher.serve();
sendEvent('devtools.serve', <String, dynamic>{
'host': server.address.host,
'port': server.port,
});
}
@override
Future<void> dispose() async {
await _devtoolsLauncher?.close();
}
}
Stream<Map<String, dynamic>> get stdinCommandStream => globals.stdio.stdin
.transform<String>(utf8.decoder)
.transform<String>(const LineSplitter())
......
......@@ -1731,9 +1731,7 @@ class DevtoolsLauncher {
io.HttpServer _devtoolsServer;
Future<void> launch(Uri observatoryAddress) async {
try {
_devtoolsServer ??= await devtools_server.serveDevTools(
enableStdinCommands: false,
);
await serve();
await devtools_server.launchDevTools(
<String, dynamic>{
'reuseWindows': true,
......@@ -1748,6 +1746,17 @@ class DevtoolsLauncher {
}
}
Future<io.HttpServer> serve() async {
try {
_devtoolsServer ??= await devtools_server.serveDevTools(
enableStdinCommands: false,
);
} on Exception catch (e, st) {
globals.printTrace('Failed to serve DevTools: $e\n$st');
}
return _devtoolsServer;
}
Future<void> close() async {
await _devtoolsServer?.close();
_devtoolsServer = null;
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'dart:async';
import 'dart:io';
import 'package:flutter_tools/src/android/android_workflow.dart';
import 'package:flutter_tools/src/base/common.dart';
......@@ -13,6 +14,7 @@ import 'package:flutter_tools/src/fuchsia/fuchsia_workflow.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/ios/ios_workflow.dart';
import 'package:flutter_tools/src/resident_runner.dart';
import 'package:mockito/mockito.dart';
import 'package:quiver/testing/async.dart';
import '../../src/common.dart';
......@@ -23,11 +25,13 @@ void main() {
Daemon daemon;
NotifyingLogger notifyingLogger;
BufferLogger bufferLogger;
DevtoolsLauncher mockDevToolsLauncher;
group('daemon', () {
setUp(() {
bufferLogger = BufferLogger.test();
notifyingLogger = NotifyingLogger(verbose: false, parent: bufferLogger);
mockDevToolsLauncher = MockDevToolsLauncher();
});
tearDown(() {
......@@ -299,6 +303,33 @@ void main() {
await output.close();
await input.close();
});
testUsingContext('devtools.serve command should return host and port', () async {
final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
daemon = Daemon(
commands.stream,
responses.add,
notifyingLogger: notifyingLogger,
);
final HttpServer mockDevToolsServer = MockDevToolsServer();
final InternetAddress mockInternetAddress = MockInternetAddress();
when(mockDevToolsServer.address).thenReturn(mockInternetAddress);
when(mockInternetAddress.host).thenReturn('127.0.0.1');
when(mockDevToolsServer.port).thenReturn(1234);
when(mockDevToolsLauncher.serve()).thenAnswer((_) async => mockDevToolsServer);
commands.add(<String, dynamic>{'id': 0, 'method': 'devtools.serve'});
final Map<String, dynamic> response = await responses.stream.firstWhere(_isDevToolsEvent);
expect(response['params'], isNotEmpty);
expect(response['params']['host'], equals('127.0.0.1'));
expect(response['params']['port'], equals(1234));
await responses.close();
await commands.close();
}, overrides: <Type, Generator>{
DevtoolsLauncher: () => mockDevToolsLauncher,
});
});
testUsingContext('notifyingLogger outputs trace messages in verbose mode', () async {
......@@ -435,6 +466,8 @@ bool _notEvent(Map<String, dynamic> map) => map['event'] == null;
bool _isConnectedEvent(Map<String, dynamic> map) => map['event'] == 'daemon.connected';
bool _isDevToolsEvent(Map<String, dynamic> map) => map['event'] == 'devtools.serve';
class MockFuchsiaWorkflow extends FuchsiaWorkflow {
MockFuchsiaWorkflow({ this.canListDevices = true });
......@@ -455,3 +488,5 @@ class MockIOSWorkflow extends IOSWorkflow {
@override
final bool canListDevices;
}
class MockDevToolsLauncher extends Mock implements DevtoolsLauncher {}
......@@ -741,6 +741,9 @@ class MockStdIn extends Mock implements IOSink {
class MockStream extends Mock implements Stream<List<int>> {}
class MockDevToolsServer extends Mock implements HttpServer {}
class MockInternetAddress extends Mock implements InternetAddress {}
class AlwaysTrueBotDetector implements BotDetector {
const AlwaysTrueBotDetector();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment