Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Side by Side Diff: runtime/bin/vmservice/client/lib/src/app/application.dart

Issue 335463008: Allow Observatory to run as a hosted web service (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 app; 5 part of app;
6 6
7 /// A [Pane] controls the user interface of Observatory. At any given time
8 /// one pane will be the current pane. Panes are registered at startup.
9 /// When the user navigates within the application, each pane is asked if it
10 /// can handle the current location, the first pane to say yes, wins.
11 abstract class Pane extends Observable {
12 final ObservatoryApplication app;
13
14 @observable ObservatoryElement element;
15
16 Pane(this.app);
17
18 /// Called when the pane is installed, this callback must initialize
19 /// [element].
20 void onInstall();
21
22 /// Called when the pane is uninstalled, this callback must clear
23 /// [element].
24 void onUninstall() {
25 element = null;
26 }
27
28 /// Called when the pane should update its state based on [url].
29 /// NOTE: Only called when the pane is installed.
30 void visit(String url);
31
32 /// Called to test whether this pane can visit [url].
33 bool canVisit(String url);
34 }
35
36 /// A general service object viewer.
37 class ServiceObjectPane extends Pane {
38 ServiceObjectPane(app) : super(app);
39
40 void onInstall() {
41 if (element == null) {
42 /// Lazily create pane.
43 element = new Element.tag('service-view');
44 }
45 }
46
47 void visit(String url) {
48 assert(element != null);
49 assert(canVisit(url));
50 if (url == '') {
51 // Nothing requested.
52 return;
53 }
54 /// Request url from VM and display it.
55 app.vm.get(url).then((obj) {
56 ServiceObjectViewElement pane = element;
57 pane.object = obj;
58 });
59 }
60
61 /// Catch all.
62 bool canVisit(String url) => true;
63 }
64
65 /// Class tree pane.
66 class ClassTreePane extends Pane {
67 static const _urlPrefix = 'class-tree/';
68
69 ClassTreePane(app) : super(app);
70
71 void onInstall() {
72 if (element == null) {
73 element = new Element.tag('class-tree');
74 }
75 }
76
77 void visit(String url) {
78 assert(element != null);
79 assert(canVisit(url));
80 // ClassTree urls are 'class-tree/isolate-id', chop off prefix, leaving
81 // isolate url.
82 url = url.substring(_urlPrefix.length);
83 /// Request the isolate url.
84 app.vm.get(url).then((i) {
85 if (element != null) {
86 /// Update the pane.
87 ClassTreeElement pane = element;
88 pane.isolate = i;
89 }
90 });
91 }
92
93 /// Catch all.
94 bool canVisit(String url) => url.startsWith(_urlPrefix);
95 }
96
97 class ErrorViewPane extends Pane {
98 ErrorViewPane(app) : super(app);
99
100 void onInstall() {
101 if (element == null) {
102 /// Lazily create pane.
103 element = new Element.tag('service-view');
104 }
105 }
106
107 void visit(String url) {
108 assert(element != null);
109 assert(canVisit(url));
110 (element as ServiceObjectViewElement).object = app.lastErrorOrException;
111 }
112
113 bool canVisit(String url) => url.startsWith('error/');
114 }
115
116 /// The observatory application. Instances of this are created and owned 7 /// The observatory application. Instances of this are created and owned
117 /// by the observatory_application custom element. 8 /// by the observatory_application custom element.
118 class ObservatoryApplication extends Observable { 9 class ObservatoryApplication extends Observable {
119 static ObservatoryApplication app; 10 static ObservatoryApplication app;
120 final _paneRegistry = new List<Pane>(); 11 final _paneRegistry = new List<Pane>();
121 ServiceObjectPane _serviceObjectPane;
122 Pane _currentPane; 12 Pane _currentPane;
123 @observable final LocationManager locationManager; 13 @observable final LocationManager locationManager;
124 @observable final VM vm; 14 VM _vm;
15 VM get vm => _vm;
16 set vm(VM vm) {
17 if (_vm == vm) {
18 // Do nothing.
19 return;
20 }
21 if (_vm != null) {
22 // Disconnect from current VM.
23 _vm.disconnect();
24 }
25 if (vm != null) {
26 Logger.root.info('Registering new VM callbacks');
27 vm.onConnect.then(_vmConnected);
28 vm.onDisconnect.then(_vmDisconnected);
29 vm.errors.stream.listen(_onError);
30 vm.exceptions.stream.listen(_onException);
31 }
32 _vm = vm;
33 }
34 final TargetManager targets;
125 @observable Isolate isolate; 35 @observable Isolate isolate;
126 @reflectable final ObservatoryApplicationElement rootElement; 36 @reflectable final ObservatoryApplicationElement rootElement;
127 37
128 @reflectable ServiceObject lastErrorOrException; 38 @reflectable ServiceObject lastErrorOrException;
129
130 @observable ObservableList<ServiceEvent> notifications = 39 @observable ObservableList<ServiceEvent> notifications =
131 new ObservableList<ServiceEvent>(); 40 new ObservableList<ServiceEvent>();
132 41
133 void _initOnce() { 42 void _initOnce(bool chromium) {
43 assert(app == null);
134 app = this; 44 app = this;
135 vm.events.stream.listen(_handleEvent);
136 _registerPanes(); 45 _registerPanes();
137 vm.errors.stream.listen(_onError);
138 vm.exceptions.stream.listen(_onException);
139 location = locationManager;
140 locationManager._init(this); 46 locationManager._init(this);
141 } 47 }
142 48
143 void removePauseEvents(Isolate isolate) { 49 void removePauseEvents(Isolate isolate) {
144 bool isPauseEvent(var event) { 50 bool isPauseEvent(var event) {
145 return (event.eventType == 'IsolateInterrupted' || 51 return (event.eventType == 'IsolateInterrupted' ||
146 event.eventType == 'BreakpointReached' || 52 event.eventType == 'BreakpointReached' ||
147 event.eventType == 'ExceptionThrown'); 53 event.eventType == 'ExceptionThrown');
148 } 54 }
149 55
(...skipping 29 matching lines...) Expand all
179 break; 85 break;
180 86
181 default: 87 default:
182 // Ignore unrecognized events. 88 // Ignore unrecognized events.
183 Logger.root.severe('Unrecognized event type: ${event.eventType}'); 89 Logger.root.severe('Unrecognized event type: ${event.eventType}');
184 break; 90 break;
185 } 91 }
186 } 92 }
187 93
188 void _registerPanes() { 94 void _registerPanes() {
189 if (_serviceObjectPane != null) {
190 // Already done.
191 return;
192 }
193 // Register ClassTreePane. 95 // Register ClassTreePane.
194 _paneRegistry.add(new ClassTreePane(this)); 96 _paneRegistry.add(new ClassTreePane(this));
97 _paneRegistry.add(new VMConnectPane(this));
195 _paneRegistry.add(new ErrorViewPane(this)); 98 _paneRegistry.add(new ErrorViewPane(this));
196 // Note that ServiceObjectPane must be the last entry in the list as it is 99 // Note that ServiceObjectPane must be the last entry in the list as it is
197 // the catch all. 100 // the catch all.
198 _serviceObjectPane = new ServiceObjectPane(this); 101 _paneRegistry.add(new ServiceObjectPane(this));
199 _paneRegistry.add(_serviceObjectPane);
200 } 102 }
201 103
202 void _onError(ServiceError error) { 104 void _onError(ServiceError error) {
203 lastErrorOrException = error; 105 lastErrorOrException = error;
204 _visit('error/', null); 106 _visit('error/', null);
205 } 107 }
206 108
207 void _onException(ServiceException exception) { 109 void _onException(ServiceException exception) {
208 lastErrorOrException = exception; 110 lastErrorOrException = exception;
209 _visit('error/', null); 111 if (exception.kind == 'NetworkException') {
112 // Got a network exception, visit the vm-connect pane.
113 locationManager.go(locationManager.makeLink('/vm-connect/'));
114 } else {
115 _visit('error/', null);
116 }
210 } 117 }
211 118
212 void _visit(String url, String args) { 119 void _visit(String url, String args) {
213 // TODO(johnmccutchan): Pass [args] to pane. 120 // TODO(johnmccutchan): Pass [args] to pane.
214 for (var i = 0; i < _paneRegistry.length; i++) { 121 for (var i = 0; i < _paneRegistry.length; i++) {
215 var pane = _paneRegistry[i]; 122 var pane = _paneRegistry[i];
216 if (pane.canVisit(url)) { 123 if (pane.canVisit(url)) {
217 _installPane(pane); 124 _installPane(pane);
218 pane.visit(url); 125 pane.visit(url);
219 return; 126 return;
220 } 127 }
221 } 128 }
222 throw new FallThroughError(); 129 throw new FallThroughError();
223 } 130 }
224 131
225 /// Set the Observatory application pane. 132 /// Set the Observatory application pane.
226 void _installPane(Pane pane) { 133 void _installPane(Pane pane) {
227 assert(pane != null); 134 assert(pane != null);
228 print('Installing $pane');
229 if (_currentPane == pane) { 135 if (_currentPane == pane) {
230 // Already isntalled. 136 // Already isntalled.
231 return; 137 return;
232 } 138 }
233 if (_currentPane != null) { 139 if (_currentPane != null) {
140 Logger.root.info('Uninstalling pane: $_currentPane');
234 _currentPane.onUninstall(); 141 _currentPane.onUninstall();
142 // Clear children.
143 rootElement.children.clear();
235 } 144 }
236 pane.onInstall(); 145 Logger.root.info('Installing pane: $pane');
237 // Clear children. 146 try {
238 rootElement.children.clear(); 147 pane.onInstall();
148 } catch (e) {
149 Logger.root.severe('Failed to install pane: $e');
150 }
239 // Add new pane. 151 // Add new pane.
240 rootElement.children.add(pane.element); 152 rootElement.children.add(pane.element);
241 // Remember pane. 153 // Remember pane.
242 _currentPane = pane; 154 _currentPane = pane;
243 } 155 }
244 156
245 ObservatoryApplication.devtools(this.rootElement) : 157 ObservatoryApplication.devtools(this.rootElement) :
246 locationManager = new HashLocationManager(), 158 locationManager = new HashLocationManager(),
247 vm = new DartiumVM() { 159 targets = null {
248 _initOnce(); 160 vm = new PostMessageVM();
161 _initOnce(true);
249 } 162 }
250 163
251 ObservatoryApplication(this.rootElement) : 164 ObservatoryApplication(this.rootElement) :
252 locationManager = new HashLocationManager(), 165 locationManager = new HashLocationManager(),
253 vm = new WebSocketVM() { 166 targets = new TargetManager() {
254 _initOnce(); 167 vm = new WebSocketVM(targets.defaultTarget);
168 _initOnce(false);
169 }
170
171 _vmConnected(VM vm) {
172 if (vm is WebSocketVM) {
173 targets.add(vm.target);
174 }
175 }
176
177 _vmDisconnected(VM vm) {
178 if (this.vm != vm) {
179 // This disconnect event occured *after* a new VM was installed.
180 return;
181 }
182 this.vm = null;
183 locationManager.go(locationManager.makeLink('/vm-connect/'));
255 } 184 }
256 } 185 }
257
258 LocationManager location;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698