Chromium Code Reviews| Index: lib/src/isolate.dart |
| diff --git a/lib/src/isolate.dart b/lib/src/isolate.dart |
| index d9363daa37947af26664dde7e475026e8286fba8..e8a495f2c8ec16d643838b6af9ddbd881850e7a2 100644 |
| --- a/lib/src/isolate.dart |
| +++ b/lib/src/isolate.dart |
| @@ -68,6 +68,20 @@ class VMIsolateRef { |
| Stream<VMBreakpoint> get onBreakpointAdded => _onBreakpointAdded; |
| Stream<VMBreakpoint> _onBreakpointAdded; |
| + /// A broadcast stream that emits custom events posted via `postEvent` from |
| + /// the `dart:developer` package. |
| + Stream<VMExtensionEvent> get onExtensionEvent => _onExtensionEvent; |
| + Stream<VMExtensionEvent> _onExtensionEvent; |
| + |
| + /// A broadcast stream that emits custom events posted via `postEvent` from |
| + /// the `dart:developer` package, limited to specific [kind]. |
| + /// |
| + /// If [prefix] is `true`, then [kind] is matched to the event kind as a |
| + /// prefix. |
| + Stream<VMExtensionEvent> selectExtensionEvents(String kind, |
| + {bool prefix: false}) => |
| + transform(_onExtensionEvent, new _VMExtensionEventSelector(kind, prefix)); |
|
nweiz
2016/02/17 21:35:41
I'd rather this just be an anonymous function.
yjbanov
2016/02/17 23:51:43
Done.
|
| + |
| /// A broadcast stream that emits this isolate's standard output. |
| /// |
| /// This is only usable for embedders that provide access to `dart:io`. |
| @@ -86,6 +100,11 @@ class VMIsolateRef { |
| Stream<List<int>> get stderr => _stderr; |
| Stream<List<int>> _stderr; |
| + /// A broadcast stream that emits the name of VM service extensions |
| + Stream<String> get onServiceExtensionAdded => |
| + _onServiceExtensionAdded; |
| + Stream<String> _onServiceExtensionAdded; |
| + |
| /// A future that fires when the isolate exits. |
| /// |
| /// If the isolate has already exited, this will complete immediately. |
| @@ -126,6 +145,11 @@ class VMIsolateRef { |
| sink.add(new VMIsolateRef._(_scope, json["isolate"])); |
| }); |
| + _onServiceExtensionAdded = _transform(_scope.streams.isolate, (json, sink) { |
| + if (json["kind"] != "ServiceExtensionAdded") return; |
| + sink.add(json["extensionRPC"]); |
| + }); |
| + |
| _onPauseOrResume = _transform(_scope.streams.debug, (json, sink) { |
| var event = newVMPauseEvent(_scope, json); |
| if (event != null) sink.add(event); |
| @@ -146,6 +170,11 @@ class VMIsolateRef { |
| if (json["kind"] != "WriteEvent") return; |
| sink.add(CryptoUtils.base64StringToBytes(json["bytes"])); |
| }); |
| + |
| + _onExtensionEvent = _transform(_scope.streams.extension, (json, sink) { |
| + sink.add( |
| + new VMExtensionEvent._(json['extensionKind'], json['extensionData'])); |
| + }); |
| } |
| /// Like [transform], but only calls [handleData] for events related to this |
| @@ -264,6 +293,37 @@ class VMIsolateRef { |
| } |
| } |
| + /// Returns a future that completes once extension with the given [name] is |
| + /// available. |
| + /// |
| + /// This works whether the extension is already registered or has yet to be |
| + /// registered. |
| + Future waitForExtension(String name) async { |
| + return _scope.getInState(_scope.streams.isolate, () async { |
| + var extensions = (await load()).extensionRPCs; |
| + return extensions.contains(name); |
| + }, (Map json) { |
| + return json["kind"] == "ServiceExtensionAdded" && |
| + json["extensionRPC"] == name; |
| + }).then((_) => null); |
| + } |
| + |
| + /// Makes a raw RPC to a VM service extension registered in this isolate |
| + /// corresponding to the ID [number]. |
| + /// |
| + /// [method] must correspond to a VM service extension installed on the VM |
| + /// isolate and it must begin with prefix "ext.". |
| + /// |
| + /// [params] are passed to the extension handler and must be serializable to |
| + /// a JSON string. |
| + Future<Object> invokeExtension(String method, [Map<String, String> params]) { |
| + if (!method.startsWith('ext.')) { |
| + throw new ArgumentError.value(method, 'method', |
| + 'must begin with "ext." prefix'); |
| + } |
| + return _scope.sendRequest(method, params); |
| + } |
| + |
| bool operator ==(other) => other is VMIsolateRef && |
| other._scope.isolateId == _scope.isolateId; |
| @@ -297,6 +357,9 @@ class VMIsolate extends VMIsolateRef { |
| /// All breakpoints currently registered for this isolate. |
| final List<VMBreakpoint> breakpoints; |
| + /// The list of service extension RPCs that are registered for this isolate. |
| + final List<String> extensionRPCs; |
|
nweiz
2016/02/17 21:35:41
Nit: Following the Dart style guide, this should b
yjbanov
2016/02/17 23:51:43
Done.
|
| + |
| VMIsolate._(Scope scope, Map json) |
| : startTime = new DateTime.fromMillisecondsSinceEpoch( |
| // Prior to v3.0, this was emitted as a double rather than an int. |
| @@ -308,6 +371,9 @@ class VMIsolate extends VMIsolateRef { |
| breakpoints = new UnmodifiableListView(json["breakpoints"] |
| .map((breakpoint) => newVMBreakpoint(scope, breakpoint)) |
| .toList()), |
| + extensionRPCs = json["extensionRPCs"] != null |
| + ? new UnmodifiableListView(json["extensionRPCs"]) |
| + : const <String>[], // it's null when no extensions are registered |
|
nweiz
2016/02/17 21:35:41
Hmm, this is not what's documented. I've filed htt
yjbanov
2016/02/17 23:51:43
Done.
|
| super._(scope, json); |
| } |
| @@ -365,4 +431,32 @@ class VMStep { |
| const VMStep._(this._value); |
| String toString() => _value; |
| -} |
| +} |
| + |
| +/// An event posted via `postEvent` from the `dart:developer` package. |
| +class VMExtensionEvent { |
| + /// Event kind. |
| + final String kind; |
| + |
| + /// Event data. |
| + final Map data; |
| + |
| + VMExtensionEvent._(this.kind, this.data); |
| +} |
| + |
| +/// Stream data handler that picks extension events based on event kind. |
| +class _VMExtensionEventSelector { |
| + /// The kind of events the subscriber is interested in. |
| + final String kind; |
| + |
| + /// Whether [kind] must match as prefix. |
| + final bool prefix; |
| + |
| + _VMExtensionEventSelector(this.kind, this.prefix); |
| + |
| + call(VMExtensionEvent event, EventSink<VMExtensionEvent> sink) { |
| + if (event.kind == kind || (prefix && event.kind.startsWith(kind))) { |
| + sink.add(event); |
| + } |
| + } |
| +} |