| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 part of service; | 5 part of service; |
| 6 | 6 |
| 7 /// An RpcException represents an exceptional event that happened | 7 /// An RpcException represents an exceptional event that happened |
| 8 /// while invoking an rpc. | 8 /// while invoking an rpc. |
| 9 abstract class RpcException implements Exception { | 9 abstract class RpcException implements Exception { |
| 10 RpcException(this.message); | 10 RpcException(this.message); |
| (...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 419 | 419 |
| 420 String toString() { | 420 String toString() { |
| 421 if (endTokenPos == null) { | 421 if (endTokenPos == null) { |
| 422 return '${script.name}:token(${tokenPos})'; | 422 return '${script.name}:token(${tokenPos})'; |
| 423 } else { | 423 } else { |
| 424 return '${script.name}:tokens(${tokenPos}-${endTokenPos})'; | 424 return '${script.name}:tokens(${tokenPos}-${endTokenPos})'; |
| 425 } | 425 } |
| 426 } | 426 } |
| 427 } | 427 } |
| 428 | 428 |
| 429 class _EventStreamState { |
| 430 VM _vm; |
| 431 String streamId; |
| 432 |
| 433 Function _onDone; |
| 434 |
| 435 // A list of all subscribed controllers for this stream. |
| 436 List _controllers = []; |
| 437 |
| 438 // Completes when the listen rpc is finished. |
| 439 Future _listenFuture; |
| 440 |
| 441 // Completes when then cancel rpc is finished. |
| 442 Future _cancelFuture; |
| 443 |
| 444 _EventStreamState(this._vm, this.streamId, this._onDone); |
| 445 |
| 446 Future _cancelController(StreamController controller) { |
| 447 _controllers.remove(controller); |
| 448 if (_controllers.isEmpty) { |
| 449 assert(_listenFuture != null); |
| 450 _listenFuture = null; |
| 451 _cancelFuture = _vm._streamCancel(streamId); |
| 452 _cancelFuture.then((_) { |
| 453 if (_controllers.isEmpty) { |
| 454 // No new listeners showed up during cancelation. |
| 455 _onDone(); |
| 456 } |
| 457 }); |
| 458 } |
| 459 // No need to wait for _cancelFuture here. |
| 460 return new Future.value(null); |
| 461 } |
| 462 |
| 463 Future<Stream> addStream() async { |
| 464 var controller; |
| 465 controller = new StreamController( |
| 466 onCancel:() => _cancelController(controller)); |
| 467 _controllers.add(controller); |
| 468 if (_cancelFuture != null) { |
| 469 await _cancelFuture; |
| 470 } |
| 471 if (_listenFuture == null) { |
| 472 _listenFuture = _vm._streamListen(streamId); |
| 473 } |
| 474 await _listenFuture; |
| 475 return controller.stream; |
| 476 } |
| 477 |
| 478 void addEvent(ServiceEvent event) { |
| 479 for (var controller in _controllers) { |
| 480 controller.add(event); |
| 481 } |
| 482 } |
| 483 } |
| 484 |
| 429 /// State for a VM being inspected. | 485 /// State for a VM being inspected. |
| 430 abstract class VM extends ServiceObjectOwner { | 486 abstract class VM extends ServiceObjectOwner { |
| 431 @reflectable VM get vm => this; | 487 @reflectable VM get vm => this; |
| 432 @reflectable Isolate get isolate => null; | 488 @reflectable Isolate get isolate => null; |
| 433 | 489 |
| 434 // TODO(turnidge): The connection should not be stored in the VM object. | 490 // TODO(turnidge): The connection should not be stored in the VM object. |
| 435 bool get isDisconnected; | 491 bool get isDisconnected; |
| 436 | 492 |
| 437 // TODO(johnmccutchan): Ensure that isolates do not end up in _cache. | 493 // TODO(johnmccutchan): Ensure that isolates do not end up in _cache. |
| 438 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); | 494 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 452 @observable Duration get upTime => | 508 @observable Duration get upTime => |
| 453 (new DateTime.now().difference(startTime)); | 509 (new DateTime.now().difference(startTime)); |
| 454 | 510 |
| 455 VM() : super._empty(null) { | 511 VM() : super._empty(null) { |
| 456 name = 'vm'; | 512 name = 'vm'; |
| 457 vmName = 'vm'; | 513 vmName = 'vm'; |
| 458 _cache['vm'] = this; | 514 _cache['vm'] = this; |
| 459 update(toObservable({'id':'vm', 'type':'@VM'})); | 515 update(toObservable({'id':'vm', 'type':'@VM'})); |
| 460 } | 516 } |
| 461 | 517 |
| 462 final StreamController<ServiceEvent> events = | 518 void postServiceEvent(String streamId, Map response, ByteData data) { |
| 463 new StreamController.broadcast(); | |
| 464 | |
| 465 void postServiceEvent(Map response, ByteData data) { | |
| 466 var map = toObservable(response); | 519 var map = toObservable(response); |
| 467 assert(!map.containsKey('_data')); | 520 assert(!map.containsKey('_data')); |
| 468 if (data != null) { | 521 if (data != null) { |
| 469 map['_data'] = data; | 522 map['_data'] = data; |
| 470 } | 523 } |
| 471 if (map['type'] != 'Event') { | 524 if (map['type'] != 'Event') { |
| 472 Logger.root.severe( | 525 Logger.root.severe( |
| 473 "Expected 'Event' but found '${map['type']}'"); | 526 "Expected 'Event' but found '${map['type']}'"); |
| 474 return; | 527 return; |
| 475 } | 528 } |
| 476 | 529 |
| 477 var eventIsolate = map['isolate']; | 530 var eventIsolate = map['isolate']; |
| 531 var event; |
| 478 if (eventIsolate == null) { | 532 if (eventIsolate == null) { |
| 479 var event = new ServiceObject._fromMap(vm, map); | 533 event = new ServiceObject._fromMap(vm, map); |
| 480 events.add(event); | |
| 481 } else { | 534 } else { |
| 482 // getFromMap creates the Isolate if it hasn't been seen already. | 535 // getFromMap creates the Isolate if it hasn't been seen already. |
| 483 var isolate = getFromMap(map['isolate']); | 536 var isolate = getFromMap(map['isolate']); |
| 484 var event = new ServiceObject._fromMap(isolate, map); | 537 event = new ServiceObject._fromMap(isolate, map); |
| 485 if (event.kind == ServiceEvent.kIsolateExit) { | 538 if (event.kind == ServiceEvent.kIsolateExit) { |
| 486 _removeIsolate(isolate.id); | 539 _removeIsolate(isolate.id); |
| 487 } | 540 } |
| 488 isolate._onEvent(event); | 541 } |
| 489 events.add(event); | 542 var eventStream = _eventStreams[streamId]; |
| 543 if (eventStream != null) { |
| 544 eventStream.addEvent(event); |
| 545 } else { |
| 546 Logger.root.warning("Ignoring unexpected event on stream '${streamId}'"); |
| 490 } | 547 } |
| 491 } | 548 } |
| 492 | 549 |
| 493 void _removeIsolate(String isolateId) { | 550 void _removeIsolate(String isolateId) { |
| 494 assert(_isolateCache.containsKey(isolateId)); | 551 assert(_isolateCache.containsKey(isolateId)); |
| 495 _isolateCache.remove(isolateId); | 552 _isolateCache.remove(isolateId); |
| 496 notifyPropertyChange(#isolates, true, false); | 553 notifyPropertyChange(#isolates, true, false); |
| 497 } | 554 } |
| 498 | 555 |
| 499 void _removeDeadIsolates(List newIsolates) { | 556 void _removeDeadIsolates(List newIsolates) { |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 579 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { | 636 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { |
| 580 var obj = new ServiceObject._fromMap(this, response); | 637 var obj = new ServiceObject._fromMap(this, response); |
| 581 if ((obj != null) && obj.canCache) { | 638 if ((obj != null) && obj.canCache) { |
| 582 String objId = obj.id; | 639 String objId = obj.id; |
| 583 _cache.putIfAbsent(objId, () => obj); | 640 _cache.putIfAbsent(objId, () => obj); |
| 584 } | 641 } |
| 585 return obj; | 642 return obj; |
| 586 }); | 643 }); |
| 587 } | 644 } |
| 588 | 645 |
| 646 void _dispatchEventToIsolate(ServiceEvent event) { |
| 647 var isolate = event.isolate; |
| 648 if (isolate != null) { |
| 649 isolate._onEvent(event); |
| 650 } |
| 651 } |
| 652 |
| 589 Future<ObservableMap> _fetchDirect() async { | 653 Future<ObservableMap> _fetchDirect() async { |
| 590 if (!loaded) { | 654 if (!loaded) { |
| 591 // TODO(turnidge): Instead of always listening to all streams, | 655 // The vm service relies on these events to keep the VM and |
| 592 // implement a stream abstraction in the service library so | 656 // Isolate types up to date. |
| 593 // that we only subscribe to the streams we want. | 657 (await getIsolateEventStream()).listen(_dispatchEventToIsolate); |
| 594 await _streamListen('Isolate'); | 658 (await getDebugEventStream()).listen(_dispatchEventToIsolate); |
| 595 await _streamListen('Debug'); | 659 (await getEventStream('_Graph')).listen(_dispatchEventToIsolate); |
| 596 await _streamListen('GC'); | |
| 597 await _streamListen('_Echo'); | |
| 598 await _streamListen('_Graph'); | |
| 599 } | 660 } |
| 600 return await invokeRpcNoUpgrade('getVM', {}); | 661 return await invokeRpcNoUpgrade('getVM', {}); |
| 601 } | 662 } |
| 602 | 663 |
| 603 Future<ServiceObject> getFlagList() { | 664 Future<ServiceObject> getFlagList() { |
| 604 return invokeRpc('getFlagList', {}); | 665 return invokeRpc('getFlagList', {}); |
| 605 } | 666 } |
| 606 | 667 |
| 607 Future<ServiceObject> _streamListen(String streamId) { | 668 Future<ServiceObject> _streamListen(String streamId) { |
| 608 Map params = { | 669 Map params = { |
| 609 'streamId': streamId, | 670 'streamId': streamId, |
| 610 }; | 671 }; |
| 611 return invokeRpc('streamListen', params); | 672 return invokeRpc('streamListen', params); |
| 612 } | 673 } |
| 613 | 674 |
| 675 Future<ServiceObject> _streamCancel(String streamId) { |
| 676 Map params = { |
| 677 'streamId': streamId, |
| 678 }; |
| 679 return invokeRpc('streamCancel', params); |
| 680 } |
| 681 |
| 682 // A map from stream id to event stream state. |
| 683 Map<String,_EventStreamState> _eventStreams = {}; |
| 684 |
| 685 /// Returns a single-subscription Stream object for a VM event stream. |
| 686 Future<Stream> getEventStream(String streamId) async { |
| 687 var eventStream = _eventStreams.putIfAbsent( |
| 688 streamId, () => new _EventStreamState( |
| 689 this, streamId, () => _eventStreams.remove(streamId))); |
| 690 return eventStream.addStream(); |
| 691 } |
| 692 |
| 693 Future<Stream> getIsolateEventStream() { |
| 694 return getEventStream('Isolate'); |
| 695 } |
| 696 |
| 697 Future<Stream> getDebugEventStream() { |
| 698 return getEventStream('Debug'); |
| 699 } |
| 700 |
| 701 Future<Stream> getGCEventStream() { |
| 702 return getEventStream('GC'); |
| 703 } |
| 704 |
| 614 /// Force the VM to disconnect. | 705 /// Force the VM to disconnect. |
| 615 void disconnect(); | 706 void disconnect(); |
| 616 /// Completes when the VM first connects. | 707 /// Completes when the VM first connects. |
| 617 Future get onConnect; | 708 Future get onConnect; |
| 618 /// Completes when the VM disconnects or there was an error connecting. | 709 /// Completes when the VM disconnects or there was an error connecting. |
| 619 Future get onDisconnect; | 710 Future get onDisconnect; |
| 620 | 711 |
| 621 void _update(ObservableMap map, bool mapIsRef) { | 712 void _update(ObservableMap map, bool mapIsRef) { |
| 622 if (mapIsRef) { | 713 if (mapIsRef) { |
| 623 return; | 714 return; |
| (...skipping 2829 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3453 var v = list[i]; | 3544 var v = list[i]; |
| 3454 if ((v is ObservableMap) && _isServiceMap(v)) { | 3545 if ((v is ObservableMap) && _isServiceMap(v)) { |
| 3455 list[i] = owner.getFromMap(v); | 3546 list[i] = owner.getFromMap(v); |
| 3456 } else if (v is ObservableList) { | 3547 } else if (v is ObservableList) { |
| 3457 _upgradeObservableList(v, owner); | 3548 _upgradeObservableList(v, owner); |
| 3458 } else if (v is ObservableMap) { | 3549 } else if (v is ObservableMap) { |
| 3459 _upgradeObservableMap(v, owner); | 3550 _upgradeObservableMap(v, owner); |
| 3460 } | 3551 } |
| 3461 } | 3552 } |
| 3462 } | 3553 } |
| OLD | NEW |