| Index: lib/src/isolate.dart
|
| diff --git a/lib/src/isolate.dart b/lib/src/isolate.dart
|
| index d9363daa37947af26664dde7e475026e8286fba8..dc16b96ee7b4ded8c290ec16ed82404d89c428fb 100644
|
| --- a/lib/src/isolate.dart
|
| +++ b/lib/src/isolate.dart
|
| @@ -68,6 +68,25 @@ 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,
|
| + (VMExtensionEvent event, EventSink<VMExtensionEvent> sink) {
|
| + if (event.kind == kind || (prefix && event.kind.startsWith(kind))) {
|
| + sink.add(event);
|
| + }
|
| + });
|
| +
|
| /// A broadcast stream that emits this isolate's standard output.
|
| ///
|
| /// This is only usable for embedders that provide access to `dart:io`.
|
| @@ -86,6 +105,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 +150,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 +175,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 +298,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 +362,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;
|
| +
|
| 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 +376,8 @@ class VMIsolate extends VMIsolateRef {
|
| breakpoints = new UnmodifiableListView(json["breakpoints"]
|
| .map((breakpoint) => newVMBreakpoint(scope, breakpoint))
|
| .toList()),
|
| + // The returned list is null when no extensions are registered
|
| + extensionRpcs = new UnmodifiableListView(json["extensionRPCs"] ?? []),
|
| super._(scope, json);
|
| }
|
|
|
| @@ -365,4 +435,15 @@ 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);
|
| +}
|
|
|