Skip to content

App Domain .callServiceExtension .restart .log #212

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Mar 18, 2019
8 changes: 7 additions & 1 deletion example/web/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
// 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:convert';
import 'dart:developer';

void main() {
print('Hello World!');
registerExtension('ext.print', (_, __) async {
print('Hello World');
return ServiceExtensionResponse.result(json.encode({'success': true}));
});
}
50 changes: 42 additions & 8 deletions webdev/lib/src/daemon/app_domain.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:dwds/service.dart';
import 'package:vm_service_lib/vm_service_lib.dart';

import '../serve/chrome.dart';
import '../serve/debugger/webdev_vm_client.dart';
Expand All @@ -17,6 +19,7 @@ import 'utilites.dart';
/// A collection of method and events relevant to the running application.
class AppDomain extends Domain {
String _appId;
VmService _vmService;
WebdevVmClient _webdevVmClient;
DebugService _debugService;
bool _isShutdown = false;
Expand All @@ -35,14 +38,23 @@ class AppDomain extends Domain {
_debugService =
await devHandler.startDebugService(chrome.chromeConnection, _appId);
_webdevVmClient = await WebdevVmClient.create(_debugService);
_vmService = _webdevVmClient.client;
sendEvent('app.started', {
'appId': _appId,
});
await _vmService.streamListen('Stdout');
_vmService.onStdoutEvent.listen((log) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: move this next to the streamListen?

sendEvent('app.log', {
'appId': _appId,
'log': utf8.decode(base64.decode(log.bytes)),
});
});
sendEvent('app.debugPort', {
'appId': _appId,
'port': _debugService.port,
'wsUri': _debugService.wsUri,
});
sendEvent('app.started', {
'appId': _appId,
});

// Shutdown could have been triggered while awaiting above.
// ignore: invariant_booleans
if (_isShutdown) dispose();
Expand All @@ -56,17 +68,39 @@ class AppDomain extends Domain {
_initialize(serverManager);
}

Future<String> _callServiceExtension(Map<String, dynamic> args) {
throw UnimplementedError();
Future<Map<String, dynamic>> _callServiceExtension(
Map<String, dynamic> args) async {
var appId = getStringArg(args, 'appId', required: true);
if (_appId != appId) throw ArgumentError.value(appId, 'appId', 'Not found');
var methodName = getStringArg(args, 'methodName', required: true);
var params = args['params'] != null
? (args['params'] as Map<String, dynamic>)
: <String, dynamic>{};
var response =
await _vmService.callServiceExtension(methodName, args: params);
return response.json;
}

Future<String> _restart(Map<String, dynamic> args) async {
throw UnimplementedError();
Future<Map<String, dynamic>> _restart(Map<String, dynamic> args) async {
var appId = getStringArg(args, 'appId', required: true);
if (_appId != appId) throw ArgumentError.value(appId, 'appId', 'Not found');
var fullRestart = getBoolArg(args, 'fullRestart') ?? false;
if (!fullRestart) {
throw ArgumentError.value(
fullRestart, 'fullRestart', 'We do not support hot reload yet.');
}
// TODO(grouma) - Support pauseAfterRestart.
// var pauseAfterRestart = getBoolArg(args, 'pause') ?? false;
var response = await _vmService.callServiceExtension('hotRestart');
return {
'code': response.type == 'Success' ? 0 : 1,
'message': response.toString()
};
}

Future<bool> _stop(Map<String, dynamic> args) async {
var appId = getStringArg(args, 'appId', required: true);
if (_appId != appId) throw ArgumentError("app '$appId' not found");
if (_appId != appId) throw ArgumentError.value(appId, 'appId', 'Not found');
var chrome = await Chrome.connectedInstance;
await chrome.close();
return true;
Expand Down
6 changes: 3 additions & 3 deletions webdev/lib/src/serve/debugger/webdev_vm_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ import 'package:vm_service_lib/vm_service_lib.dart';
// A client of the vm service that registers some custom extensions like
// hotRestart.
class WebdevVmClient {
final VmService _client;
final VmService client;
final StreamController<Map<String, Object>> _requestController;
final StreamController<Map<String, Object>> _responseController;

WebdevVmClient(
this._client, this._requestController, this._responseController);
this.client, this._requestController, this._responseController);

Future<void> close() async {
await _requestController.close();
await _responseController.close();
_client.dispose();
client.dispose();
}

static Future<WebdevVmClient> create(DebugService debugService) async {
Expand Down
50 changes: 50 additions & 0 deletions webdev/test/daemon/app_domain_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,31 @@
@Timeout(Duration(minutes: 2))
@Tags(['requires-edge-sdk'])

import 'dart:async';
import 'dart:convert';

@Tags(['requires-edge-sdk'])
import 'package:test/test.dart';
import 'package:test_process/test_process.dart';

import '../test_utils.dart';
import 'utils.dart';

Future<String> _getAppId(TestProcess webdev) async {
var appId = '';
while (await webdev.stdout.hasNext) {
var line = await webdev.stdout.next;
if (line.startsWith('[{"event":"app.started"')) {
line = line.substring(1, line.length - 1);
var message = json.decode(line) as Map<String, dynamic>;
appId = message['params']['appId'] as String;
break;
}
}
assert(appId.isNotEmpty);
return appId;
}

void main() {
String exampleDirectory;

Expand Down Expand Up @@ -43,5 +63,35 @@ void main() {
await exitWebdev(webdev);
});
});

group('Methods', () {
test('.callServiceExtension', () async {
var webdev =
await runWebDev(['daemon'], workingDirectory: exampleDirectory);
var appId = await _getAppId(webdev);
var extensionCall = '[{"method":"app.callServiceExtension","id":0,'
'"params" : { "appId" : "$appId", "methodName" : "ext.print"}}]';
webdev.stdin.add(utf8.encode('$extensionCall\n'));
// The example app sets up a service extension for printing.
await expectLater(
webdev.stdout,
emitsThrough(
startsWith('[{"event":"app.log","params":{"appId":"$appId",'
'"log":"Hello World\\n"}}')));
await exitWebdev(webdev);
});

test('.restart', () async {
var webdev =
await runWebDev(['daemon'], workingDirectory: exampleDirectory);
var appId = await _getAppId(webdev);
var extensionCall = '[{"method":"app.restart","id":0,'
'"params" : { "appId" : "$appId", "fullRestart" : true}}]';
webdev.stdin.add(utf8.encode('$extensionCall\n'));
await expectLater(webdev.stdout,
emitsThrough(startsWith('[{"id":0,"result":{"code":0')));
await exitWebdev(webdev);
});
});
}, tags: ['webdriver']);
}
31 changes: 17 additions & 14 deletions webdev/test/daemon/daemon_domain_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,24 @@ void main() {
});
});

test('.version', () async {
var webdev =
await runWebDev(['daemon'], workingDirectory: exampleDirectory);
webdev.stdin.add(utf8.encode('[{"method":"daemon.version","id":0}]\n'));
await expectLater(
webdev.stdout, emitsThrough(equals('[{"id":0,"result":"0.4.2"}]')));
await exitWebdev(webdev);
});
group('Methods', () {
test('.version', () async {
var webdev =
await runWebDev(['daemon'], workingDirectory: exampleDirectory);
webdev.stdin.add(utf8.encode('[{"method":"daemon.version","id":0}]\n'));
await expectLater(
webdev.stdout, emitsThrough(equals('[{"id":0,"result":"0.4.2"}]')));
await exitWebdev(webdev);
});

test('.shutdown', () async {
var webdev =
await runWebDev(['daemon'], workingDirectory: exampleDirectory);
webdev.stdin.add(utf8.encode('[{"method":"daemon.shutdown","id":0}]\n'));
await expectLater(webdev.stdout, emitsThrough(equals('[{"id":0}]')));
expect(await webdev.exitCode, equals(0));
test('.shutdown', () async {
var webdev =
await runWebDev(['daemon'], workingDirectory: exampleDirectory);
webdev.stdin
.add(utf8.encode('[{"method":"daemon.shutdown","id":0}]\n'));
await expectLater(webdev.stdout, emitsThrough(equals('[{"id":0}]')));
expect(await webdev.exitCode, equals(0));
});
});
}, tags: ['webdriver']);
}