Add daemon handler to start devtools (#62608)
This commit is contained in:
parent
f06ee8dd8d
commit
7cbec567de
@ -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();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user