Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:async'; | 5 import 'dart:async'; |
| 6 import 'dart:collection'; | 6 import 'dart:collection'; |
| 7 | 7 |
| 8 import 'package:async/async.dart'; | 8 import 'package:async/async.dart'; |
| 9 import 'package:crypto/crypto.dart'; | 9 import 'package:crypto/crypto.dart'; |
| 10 import 'package:json_rpc_2/json_rpc_2.dart' as rpc; | 10 import 'package:json_rpc_2/json_rpc_2.dart' as rpc; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 61 /// A broadcast stream that emits a [VMPauseEvent] whenever this isolate is | 61 /// A broadcast stream that emits a [VMPauseEvent] whenever this isolate is |
| 62 /// paused or resumed. | 62 /// paused or resumed. |
| 63 Stream<VMPauseEvent> get onPauseOrResume => _onPauseOrResume; | 63 Stream<VMPauseEvent> get onPauseOrResume => _onPauseOrResume; |
| 64 Stream<VMPauseEvent> _onPauseOrResume; | 64 Stream<VMPauseEvent> _onPauseOrResume; |
| 65 | 65 |
| 66 /// A broadcast stream that emits a [VMBreakpoint] whenever a breakpoint is | 66 /// A broadcast stream that emits a [VMBreakpoint] whenever a breakpoint is |
| 67 /// added. | 67 /// added. |
| 68 Stream<VMBreakpoint> get onBreakpointAdded => _onBreakpointAdded; | 68 Stream<VMBreakpoint> get onBreakpointAdded => _onBreakpointAdded; |
| 69 Stream<VMBreakpoint> _onBreakpointAdded; | 69 Stream<VMBreakpoint> _onBreakpointAdded; |
| 70 | 70 |
| 71 /// A broadcast stream that emits custom events posted via `postEvent` from | |
| 72 /// the `dart:developer` package. | |
| 73 Stream<VMExtensionEvent> get onExtensionEvent => _onExtensionEvent; | |
| 74 Stream<VMExtensionEvent> _onExtensionEvent; | |
| 75 | |
| 76 /// A broadcast stream that emits custom events posted via `postEvent` from | |
| 77 /// the `dart:developer` package, limited to specific [kind]. | |
| 78 /// | |
| 79 /// If [prefix] is `true`, then [kind] is matched to the event kind as a | |
| 80 /// prefix. | |
| 81 Stream<VMExtensionEvent> selectExtensionEvents(String kind, | |
| 82 {bool prefix: false}) => | |
| 83 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.
| |
| 84 | |
| 71 /// A broadcast stream that emits this isolate's standard output. | 85 /// A broadcast stream that emits this isolate's standard output. |
| 72 /// | 86 /// |
| 73 /// This is only usable for embedders that provide access to `dart:io`. | 87 /// This is only usable for embedders that provide access to `dart:io`. |
| 74 /// | 88 /// |
| 75 /// Note that as of the VM service version 3.0, this stream doesn't emit | 89 /// Note that as of the VM service version 3.0, this stream doesn't emit |
| 76 /// strings passed to the `print()` function unless the host process's | 90 /// strings passed to the `print()` function unless the host process's |
| 77 /// standard output is actively being drained (see [sdk#24351][]). | 91 /// standard output is actively being drained (see [sdk#24351][]). |
| 78 /// | 92 /// |
| 79 /// [sdk#24351]: https://github.com/dart-lang/sdk/issues/24351 | 93 /// [sdk#24351]: https://github.com/dart-lang/sdk/issues/24351 |
| 80 Stream<List<int>> get stdout => _stdout; | 94 Stream<List<int>> get stdout => _stdout; |
| 81 Stream<List<int>> _stdout; | 95 Stream<List<int>> _stdout; |
| 82 | 96 |
| 83 /// A broadcast stream that emits this isolate's standard error. | 97 /// A broadcast stream that emits this isolate's standard error. |
| 84 /// | 98 /// |
| 85 /// This is only usable for embedders that provide access to `dart:io`. | 99 /// This is only usable for embedders that provide access to `dart:io`. |
| 86 Stream<List<int>> get stderr => _stderr; | 100 Stream<List<int>> get stderr => _stderr; |
| 87 Stream<List<int>> _stderr; | 101 Stream<List<int>> _stderr; |
| 88 | 102 |
| 103 /// A broadcast stream that emits the name of VM service extensions | |
| 104 Stream<String> get onServiceExtensionAdded => | |
| 105 _onServiceExtensionAdded; | |
| 106 Stream<String> _onServiceExtensionAdded; | |
| 107 | |
| 89 /// A future that fires when the isolate exits. | 108 /// A future that fires when the isolate exits. |
| 90 /// | 109 /// |
| 91 /// If the isolate has already exited, this will complete immediately. | 110 /// If the isolate has already exited, this will complete immediately. |
| 92 Future get onExit => _onExitMemo.runOnce(() async { | 111 Future get onExit => _onExitMemo.runOnce(() async { |
| 93 try { | 112 try { |
| 94 await _scope.getInState(_scope.streams.isolate, () async { | 113 await _scope.getInState(_scope.streams.isolate, () async { |
| 95 try { | 114 try { |
| 96 await load(); | 115 await load(); |
| 97 return null; | 116 return null; |
| 98 } on VMSentinelException catch (_) { | 117 } on VMSentinelException catch (_) { |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 119 name = json["name"] { | 138 name = json["name"] { |
| 120 _onGC = _transform(_scope.streams.gc, (json, sink) { | 139 _onGC = _transform(_scope.streams.gc, (json, sink) { |
| 121 if (json["kind"] == "GC") sink.add(null); | 140 if (json["kind"] == "GC") sink.add(null); |
| 122 }); | 141 }); |
| 123 | 142 |
| 124 _onUpdate = _transform(_scope.streams.isolate, (json, sink) { | 143 _onUpdate = _transform(_scope.streams.isolate, (json, sink) { |
| 125 if (json["kind"] != "IsolateUpdate") return; | 144 if (json["kind"] != "IsolateUpdate") return; |
| 126 sink.add(new VMIsolateRef._(_scope, json["isolate"])); | 145 sink.add(new VMIsolateRef._(_scope, json["isolate"])); |
| 127 }); | 146 }); |
| 128 | 147 |
| 148 _onServiceExtensionAdded = _transform(_scope.streams.isolate, (json, sink) { | |
| 149 if (json["kind"] != "ServiceExtensionAdded") return; | |
| 150 sink.add(json["extensionRPC"]); | |
| 151 }); | |
| 152 | |
| 129 _onPauseOrResume = _transform(_scope.streams.debug, (json, sink) { | 153 _onPauseOrResume = _transform(_scope.streams.debug, (json, sink) { |
| 130 var event = newVMPauseEvent(_scope, json); | 154 var event = newVMPauseEvent(_scope, json); |
| 131 if (event != null) sink.add(event); | 155 if (event != null) sink.add(event); |
| 132 }); | 156 }); |
| 133 | 157 |
| 134 _onBreakpointAdded = _transform(_scope.streams.debug, (json, sink) { | 158 _onBreakpointAdded = _transform(_scope.streams.debug, (json, sink) { |
| 135 if (json["kind"] != "BreakpointAdded") return; | 159 if (json["kind"] != "BreakpointAdded") return; |
| 136 sink.add(newVMBreakpoint(_scope, json["breakpoint"])); | 160 sink.add(newVMBreakpoint(_scope, json["breakpoint"])); |
| 137 }); | 161 }); |
| 138 | 162 |
| 139 _stdout = _transform(_scope.streams.stdout, (json, sink) { | 163 _stdout = _transform(_scope.streams.stdout, (json, sink) { |
| 140 if (json["kind"] != "WriteEvent") return; | 164 if (json["kind"] != "WriteEvent") return; |
| 141 var bytes = CryptoUtils.base64StringToBytes(json["bytes"]); | 165 var bytes = CryptoUtils.base64StringToBytes(json["bytes"]); |
| 142 sink.add(bytes); | 166 sink.add(bytes); |
| 143 }); | 167 }); |
| 144 | 168 |
| 145 _stderr = _transform(_scope.streams.stderr, (json, sink) { | 169 _stderr = _transform(_scope.streams.stderr, (json, sink) { |
| 146 if (json["kind"] != "WriteEvent") return; | 170 if (json["kind"] != "WriteEvent") return; |
| 147 sink.add(CryptoUtils.base64StringToBytes(json["bytes"])); | 171 sink.add(CryptoUtils.base64StringToBytes(json["bytes"])); |
| 148 }); | 172 }); |
| 173 | |
| 174 _onExtensionEvent = _transform(_scope.streams.extension, (json, sink) { | |
| 175 sink.add( | |
| 176 new VMExtensionEvent._(json['extensionKind'], json['extensionData'])); | |
| 177 }); | |
| 149 } | 178 } |
| 150 | 179 |
| 151 /// Like [transform], but only calls [handleData] for events related to this | 180 /// Like [transform], but only calls [handleData] for events related to this |
| 152 /// isolate. | 181 /// isolate. |
| 153 Stream _transform(Stream<Map> stream, handleData(Map json, StreamSink sink)) { | 182 Stream _transform(Stream<Map> stream, handleData(Map json, StreamSink sink)) { |
| 154 return transform(stream, (json, sink) { | 183 return transform(stream, (json, sink) { |
| 155 if (json["isolate"]["id"] != _scope.isolateId) return; | 184 if (json["isolate"]["id"] != _scope.isolateId) return; |
| 156 handleData(json, sink); | 185 handleData(json, sink); |
| 157 }); | 186 }); |
| 158 } | 187 } |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 257 var response = await _scope.sendRequest( | 286 var response = await _scope.sendRequest( |
| 258 "addBreakpointWithScriptUri", params); | 287 "addBreakpointWithScriptUri", params); |
| 259 return newVMBreakpoint(_scope, response); | 288 return newVMBreakpoint(_scope, response); |
| 260 } on rpc.RpcException catch (error) { | 289 } on rpc.RpcException catch (error) { |
| 261 // Error 102 indicates that the breakpoint couldn't be created. | 290 // Error 102 indicates that the breakpoint couldn't be created. |
| 262 if (error.code == 102) return null; | 291 if (error.code == 102) return null; |
| 263 rethrow; | 292 rethrow; |
| 264 } | 293 } |
| 265 } | 294 } |
| 266 | 295 |
| 296 /// Returns a future that completes once extension with the given [name] is | |
| 297 /// available. | |
| 298 /// | |
| 299 /// This works whether the extension is already registered or has yet to be | |
| 300 /// registered. | |
| 301 Future waitForExtension(String name) async { | |
| 302 return _scope.getInState(_scope.streams.isolate, () async { | |
| 303 var extensions = (await load()).extensionRPCs; | |
| 304 return extensions.contains(name); | |
| 305 }, (Map json) { | |
| 306 return json["kind"] == "ServiceExtensionAdded" && | |
| 307 json["extensionRPC"] == name; | |
| 308 }).then((_) => null); | |
| 309 } | |
| 310 | |
| 311 /// Makes a raw RPC to a VM service extension registered in this isolate | |
| 312 /// corresponding to the ID [number]. | |
| 313 /// | |
| 314 /// [method] must correspond to a VM service extension installed on the VM | |
| 315 /// isolate and it must begin with prefix "ext.". | |
| 316 /// | |
| 317 /// [params] are passed to the extension handler and must be serializable to | |
| 318 /// a JSON string. | |
| 319 Future<Object> invokeExtension(String method, [Map<String, String> params]) { | |
| 320 if (!method.startsWith('ext.')) { | |
| 321 throw new ArgumentError.value(method, 'method', | |
| 322 'must begin with "ext." prefix'); | |
| 323 } | |
| 324 return _scope.sendRequest(method, params); | |
| 325 } | |
| 326 | |
| 267 bool operator ==(other) => other is VMIsolateRef && | 327 bool operator ==(other) => other is VMIsolateRef && |
| 268 other._scope.isolateId == _scope.isolateId; | 328 other._scope.isolateId == _scope.isolateId; |
| 269 | 329 |
| 270 int get hashCode => _scope.isolateId.hashCode; | 330 int get hashCode => _scope.isolateId.hashCode; |
| 271 | 331 |
| 272 String toString() => name; | 332 String toString() => name; |
| 273 } | 333 } |
| 274 | 334 |
| 275 /// A full isolate on the remote VM. | 335 /// A full isolate on the remote VM. |
| 276 class VMIsolate extends VMIsolateRef { | 336 class VMIsolate extends VMIsolateRef { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 290 | 350 |
| 291 /// Whether this isolate is paused. | 351 /// Whether this isolate is paused. |
| 292 bool get isPaused => pauseEvent is! VMResumeEvent; | 352 bool get isPaused => pauseEvent is! VMResumeEvent; |
| 293 | 353 |
| 294 /// The error that's causing the isolate to exit or `null`. | 354 /// The error that's causing the isolate to exit or `null`. |
| 295 final VMError error; | 355 final VMError error; |
| 296 | 356 |
| 297 /// All breakpoints currently registered for this isolate. | 357 /// All breakpoints currently registered for this isolate. |
| 298 final List<VMBreakpoint> breakpoints; | 358 final List<VMBreakpoint> breakpoints; |
| 299 | 359 |
| 360 /// The list of service extension RPCs that are registered for this isolate. | |
| 361 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.
| |
| 362 | |
| 300 VMIsolate._(Scope scope, Map json) | 363 VMIsolate._(Scope scope, Map json) |
| 301 : startTime = new DateTime.fromMillisecondsSinceEpoch( | 364 : startTime = new DateTime.fromMillisecondsSinceEpoch( |
| 302 // Prior to v3.0, this was emitted as a double rather than an int. | 365 // Prior to v3.0, this was emitted as a double rather than an int. |
| 303 json["startTime"].round()), | 366 json["startTime"].round()), |
| 304 livePorts = json["livePorts"], | 367 livePorts = json["livePorts"], |
| 305 pauseOnExit = json["pauseOnExit"], | 368 pauseOnExit = json["pauseOnExit"], |
| 306 pauseEvent = newVMPauseEvent(scope, json["pauseEvent"]), | 369 pauseEvent = newVMPauseEvent(scope, json["pauseEvent"]), |
| 307 error = newVMError(scope, json["error"]), | 370 error = newVMError(scope, json["error"]), |
| 308 breakpoints = new UnmodifiableListView(json["breakpoints"] | 371 breakpoints = new UnmodifiableListView(json["breakpoints"] |
| 309 .map((breakpoint) => newVMBreakpoint(scope, breakpoint)) | 372 .map((breakpoint) => newVMBreakpoint(scope, breakpoint)) |
| 310 .toList()), | 373 .toList()), |
| 374 extensionRPCs = json["extensionRPCs"] != null | |
| 375 ? new UnmodifiableListView(json["extensionRPCs"]) | |
| 376 : 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.
| |
| 311 super._(scope, json); | 377 super._(scope, json); |
| 312 } | 378 } |
| 313 | 379 |
| 314 /// A full isolate on the remote VM that's ready to run code. | 380 /// A full isolate on the remote VM that's ready to run code. |
| 315 /// | 381 /// |
| 316 /// The VM service exposes isolates very early, before their contents are | 382 /// The VM service exposes isolates very early, before their contents are |
| 317 /// fully-loaded. These in-progress isolates, represented by plain [VMIsolate] | 383 /// fully-loaded. These in-progress isolates, represented by plain [VMIsolate] |
| 318 /// instances, have limited amounts of metadata available. Only once they're | 384 /// instances, have limited amounts of metadata available. Only once they're |
| 319 /// runnable is the full suite of metadata available. | 385 /// runnable is the full suite of metadata available. |
| 320 /// | 386 /// |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 358 | 424 |
| 359 /// The isolate continues until it exits the current function. | 425 /// The isolate continues until it exits the current function. |
| 360 static const out = const VMStep._("Out"); | 426 static const out = const VMStep._("Out"); |
| 361 | 427 |
| 362 /// The string name of the step type. | 428 /// The string name of the step type. |
| 363 final String _value; | 429 final String _value; |
| 364 | 430 |
| 365 const VMStep._(this._value); | 431 const VMStep._(this._value); |
| 366 | 432 |
| 367 String toString() => _value; | 433 String toString() => _value; |
| 368 } | 434 } |
| 435 | |
| 436 /// An event posted via `postEvent` from the `dart:developer` package. | |
| 437 class VMExtensionEvent { | |
| 438 /// Event kind. | |
| 439 final String kind; | |
| 440 | |
| 441 /// Event data. | |
| 442 final Map data; | |
| 443 | |
| 444 VMExtensionEvent._(this.kind, this.data); | |
| 445 } | |
| 446 | |
| 447 /// Stream data handler that picks extension events based on event kind. | |
| 448 class _VMExtensionEventSelector { | |
| 449 /// The kind of events the subscriber is interested in. | |
| 450 final String kind; | |
| 451 | |
| 452 /// Whether [kind] must match as prefix. | |
| 453 final bool prefix; | |
| 454 | |
| 455 _VMExtensionEventSelector(this.kind, this.prefix); | |
| 456 | |
| 457 call(VMExtensionEvent event, EventSink<VMExtensionEvent> sink) { | |
| 458 if (event.kind == kind || (prefix && event.kind.startsWith(kind))) { | |
| 459 sink.add(event); | |
| 460 } | |
| 461 } | |
| 462 } | |
| OLD | NEW |