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
|
- `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
|
- `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'
|
## 'flutter run --machine' and 'flutter attach --machine'
|
||||||
|
|
||||||
When running `flutter run --machine` or `flutter attach --machine` the following subset of the daemon is available:
|
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(appDomain = AppDomain(this));
|
||||||
_registerDomain(deviceDomain = DeviceDomain(this));
|
_registerDomain(deviceDomain = DeviceDomain(this));
|
||||||
_registerDomain(emulatorDomain = EmulatorDomain(this));
|
_registerDomain(emulatorDomain = EmulatorDomain(this));
|
||||||
|
_registerDomain(devToolsDomain = DevToolsDomain(this));
|
||||||
|
|
||||||
// Start listening.
|
// Start listening.
|
||||||
_commandSubscription = commandStream.listen(
|
_commandSubscription = commandStream.listen(
|
||||||
@ -98,6 +99,7 @@ class Daemon {
|
|||||||
AppDomain appDomain;
|
AppDomain appDomain;
|
||||||
DeviceDomain deviceDomain;
|
DeviceDomain deviceDomain;
|
||||||
EmulatorDomain emulatorDomain;
|
EmulatorDomain emulatorDomain;
|
||||||
|
DevToolsDomain devToolsDomain;
|
||||||
StreamSubscription<Map<String, dynamic>> _commandSubscription;
|
StreamSubscription<Map<String, dynamic>> _commandSubscription;
|
||||||
int _outgoingRequestId = 1;
|
int _outgoingRequestId = 1;
|
||||||
final Map<String, Completer<dynamic>> _outgoingRequestCompleters = <String, Completer<dynamic>>{};
|
final Map<String, Completer<dynamic>> _outgoingRequestCompleters = <String, Completer<dynamic>>{};
|
||||||
@ -182,6 +184,7 @@ class Daemon {
|
|||||||
void _send(Map<String, dynamic> map) => sendCommand(map);
|
void _send(Map<String, dynamic> map) => sendCommand(map);
|
||||||
|
|
||||||
Future<void> shutdown({ dynamic error }) async {
|
Future<void> shutdown({ dynamic error }) async {
|
||||||
|
await devToolsDomain?.dispose();
|
||||||
await _commandSubscription?.cancel();
|
await _commandSubscription?.cancel();
|
||||||
for (final Domain domain in _domainMap.values) {
|
for (final Domain domain in _domainMap.values) {
|
||||||
await domain.dispose();
|
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
|
Stream<Map<String, dynamic>> get stdinCommandStream => globals.stdio.stdin
|
||||||
.transform<String>(utf8.decoder)
|
.transform<String>(utf8.decoder)
|
||||||
.transform<String>(const LineSplitter())
|
.transform<String>(const LineSplitter())
|
||||||
|
@ -1731,9 +1731,7 @@ class DevtoolsLauncher {
|
|||||||
io.HttpServer _devtoolsServer;
|
io.HttpServer _devtoolsServer;
|
||||||
Future<void> launch(Uri observatoryAddress) async {
|
Future<void> launch(Uri observatoryAddress) async {
|
||||||
try {
|
try {
|
||||||
_devtoolsServer ??= await devtools_server.serveDevTools(
|
await serve();
|
||||||
enableStdinCommands: false,
|
|
||||||
);
|
|
||||||
await devtools_server.launchDevTools(
|
await devtools_server.launchDevTools(
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'reuseWindows': true,
|
'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 {
|
Future<void> close() async {
|
||||||
await _devtoolsServer?.close();
|
await _devtoolsServer?.close();
|
||||||
_devtoolsServer = null;
|
_devtoolsServer = null;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter_tools/src/android/android_workflow.dart';
|
import 'package:flutter_tools/src/android/android_workflow.dart';
|
||||||
import 'package:flutter_tools/src/base/common.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/globals.dart' as globals;
|
||||||
import 'package:flutter_tools/src/ios/ios_workflow.dart';
|
import 'package:flutter_tools/src/ios/ios_workflow.dart';
|
||||||
import 'package:flutter_tools/src/resident_runner.dart';
|
import 'package:flutter_tools/src/resident_runner.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
import 'package:quiver/testing/async.dart';
|
import 'package:quiver/testing/async.dart';
|
||||||
|
|
||||||
import '../../src/common.dart';
|
import '../../src/common.dart';
|
||||||
@ -23,11 +25,13 @@ void main() {
|
|||||||
Daemon daemon;
|
Daemon daemon;
|
||||||
NotifyingLogger notifyingLogger;
|
NotifyingLogger notifyingLogger;
|
||||||
BufferLogger bufferLogger;
|
BufferLogger bufferLogger;
|
||||||
|
DevtoolsLauncher mockDevToolsLauncher;
|
||||||
|
|
||||||
group('daemon', () {
|
group('daemon', () {
|
||||||
setUp(() {
|
setUp(() {
|
||||||
bufferLogger = BufferLogger.test();
|
bufferLogger = BufferLogger.test();
|
||||||
notifyingLogger = NotifyingLogger(verbose: false, parent: bufferLogger);
|
notifyingLogger = NotifyingLogger(verbose: false, parent: bufferLogger);
|
||||||
|
mockDevToolsLauncher = MockDevToolsLauncher();
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDown(() {
|
tearDown(() {
|
||||||
@ -299,6 +303,33 @@ void main() {
|
|||||||
await output.close();
|
await output.close();
|
||||||
await input.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 {
|
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 _isConnectedEvent(Map<String, dynamic> map) => map['event'] == 'daemon.connected';
|
||||||
|
|
||||||
|
bool _isDevToolsEvent(Map<String, dynamic> map) => map['event'] == 'devtools.serve';
|
||||||
|
|
||||||
class MockFuchsiaWorkflow extends FuchsiaWorkflow {
|
class MockFuchsiaWorkflow extends FuchsiaWorkflow {
|
||||||
MockFuchsiaWorkflow({ this.canListDevices = true });
|
MockFuchsiaWorkflow({ this.canListDevices = true });
|
||||||
|
|
||||||
@ -455,3 +488,5 @@ class MockIOSWorkflow extends IOSWorkflow {
|
|||||||
@override
|
@override
|
||||||
final bool canListDevices;
|
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 MockStream extends Mock implements Stream<List<int>> {}
|
||||||
|
|
||||||
|
class MockDevToolsServer extends Mock implements HttpServer {}
|
||||||
|
class MockInternetAddress extends Mock implements InternetAddress {}
|
||||||
|
|
||||||
class AlwaysTrueBotDetector implements BotDetector {
|
class AlwaysTrueBotDetector implements BotDetector {
|
||||||
const AlwaysTrueBotDetector();
|
const AlwaysTrueBotDetector();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user