-
Notifications
You must be signed in to change notification settings - Fork 82
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
Changes from 9 commits
d50c8b0
2ce4c47
a6739fe
ca2ebc6
57d7d9e
e4eaba4
eed4edc
fc30d1b
d4b2e22
8ebb7ec
564594a
ae78219
5e9acc1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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'; | ||
|
@@ -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; | ||
|
@@ -35,6 +38,8 @@ class AppDomain extends Domain { | |
_debugService = | ||
await devHandler.startDebugService(chrome.chromeConnection, _appId); | ||
_webdevVmClient = await WebdevVmClient.create(_debugService); | ||
_vmService = _webdevVmClient.client; | ||
await _vmService.streamListen('Stdout'); | ||
sendEvent('app.debugPort', { | ||
'appId': _appId, | ||
'port': _debugService.port, | ||
|
@@ -43,6 +48,13 @@ class AppDomain extends Domain { | |
sendEvent('app.started', { | ||
'appId': _appId, | ||
}); | ||
_vmService.onStdoutEvent.listen((log) { | ||
sendEvent('app.log', { | ||
'appId': _appId, | ||
'log': utf8.decode(base64.decode(log.bytes)), | ||
}); | ||
}); | ||
|
||
// Shutdown could have been triggered while awaiting above. | ||
// ignore: invariant_booleans | ||
if (_isShutdown) dispose(); | ||
|
@@ -56,17 +68,40 @@ 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'); | ||
// TODO(grouma) - Figure out what fullRestart means in this context. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, full restart was the old name of hot restart. So, fullRestart==false is hot reload, and fullRestart==true is hot restart. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the details. I updated the code to reflect our current support. |
||
// For now we will ignore. | ||
// var fullRestart = getBoolArg(args, 'fullRestart') ?? false; | ||
var pauseAfterRestart = getBoolArg(args, 'pause') ?? false; | ||
if (pauseAfterRestart) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You may not want to throw here - we'd have to investigate. The IDEs will be sending it in when you start the app in a debug launch (as opposed to a 'run', w/o breakpoints enabled). If the IDE does pass in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Worth seeing what happens here first before doing a lot of work however. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can try this out Monday, but in VS Code we do always send pause when running in debug mode (to do what Devon describes above). The reason for this is that we need to re-send breakpoints after a hot restart (they got dropped) or hot reload (the code they were attached to may have been replaced with new code), and if we don't pause then we'll have race conditions (the code may have already run before we've sent the breakpoint). |
||
throw ArgumentError.value( | ||
pauseAfterRestart, 'pauseAfterRestart', 'Not supported.'); | ||
} | ||
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; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,13 +3,32 @@ | |
// BSD-style license that can be found in the LICENSE file. | ||
|
||
@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; | ||
|
||
|
@@ -43,5 +62,32 @@ 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"'))); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could easily pass for a different reason than the extension being called successfully (any log happening), I would check a bit more about the event if you can (check specifically for the expected print log line) |
||
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"}}]'; | ||
webdev.stdin.add(utf8.encode('$extensionCall\n')); | ||
await expectLater(webdev.stdout, | ||
emitsThrough(startsWith('[{"id":0,"result":{"code":0'))); | ||
await exitWebdev(webdev); | ||
}); | ||
}); | ||
}, tags: ['webdriver']); | ||
} |
There was a problem hiding this comment.
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?