OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 part of app; | |
6 | |
7 /// The observatory application. Instances of this are created and owned | |
8 /// by the observatory_application custom element. | |
9 class ObservatoryApplication extends Observable { | |
10 static ObservatoryApplication app; | |
11 final _pageRegistry = new List<Page>(); | |
12 @observable Page currentPage; | |
13 @observable final LocationManager locationManager; | |
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 notifications.clear(); | |
24 _vm.disconnect(); | |
25 } | |
26 if (vm != null) { | |
27 Logger.root.info('Registering new VM callbacks'); | |
28 vm.onConnect.then(_vmConnected); | |
29 vm.onDisconnect.then(_vmDisconnected); | |
30 vm.errors.stream.listen(_onError); | |
31 vm.events.stream.listen(_onEvent); | |
32 vm.exceptions.stream.listen(_onException); | |
33 } | |
34 _vm = vm; | |
35 } | |
36 final TargetManager targets; | |
37 @reflectable final ObservatoryApplicationElement rootElement; | |
38 | |
39 TraceViewElement _traceView = null; | |
40 | |
41 @reflectable ServiceObject lastErrorOrException; | |
42 @observable ObservableList<ServiceEvent> notifications = | |
43 new ObservableList<ServiceEvent>(); | |
44 | |
45 void _initOnce(bool chromium) { | |
46 assert(app == null); | |
47 app = this; | |
48 _registerPages(); | |
49 locationManager._init(this); | |
50 } | |
51 | |
52 void removePauseEvents(Isolate isolate) { | |
53 bool isPauseEvent(var event) { | |
54 return (event.eventType == 'IsolateInterrupted' || | |
55 event.eventType == 'BreakpointReached' || | |
56 event.eventType == 'ExceptionThrown'); | |
57 } | |
58 | |
59 notifications.removeWhere((oldEvent) { | |
60 return (oldEvent.isolate == isolate && | |
61 isPauseEvent(oldEvent)); | |
62 }); | |
63 } | |
64 | |
65 void _onEvent(ServiceEvent event) { | |
66 switch(event.eventType) { | |
67 case 'IsolateCreated': | |
68 // vm.reload(); | |
69 break; | |
70 | |
71 case 'IsolateShutdown': | |
72 // TODO(turnidge): Should we show the user isolate shutdown events? | |
73 // What if there are hundreds of them? Coalesce multiple | |
74 // shutdown events into one notification? | |
75 removePauseEvents(event.isolate); | |
76 // vm.reload(); | |
77 break; | |
78 | |
79 case 'BreakpointResolved': | |
80 event.isolate.reloadBreakpoints(); | |
81 break; | |
82 | |
83 case 'BreakpointReached': | |
84 case 'IsolateInterrupted': | |
85 case 'ExceptionThrown': | |
86 removePauseEvents(event.isolate); | |
87 notifications.add(event); | |
88 break; | |
89 | |
90 | |
91 case 'GC': | |
92 // Ignore GC events for now. | |
93 break; | |
94 | |
95 default: | |
96 // Ignore unrecognized events. | |
97 Logger.root.severe('Unrecognized event: $event'); | |
98 break; | |
99 } | |
100 } | |
101 | |
102 void _registerPages() { | |
103 _pageRegistry.add(new ClassTreePage(this)); | |
104 _pageRegistry.add(new DebuggerPage(this)); | |
105 _pageRegistry.add(new VMConnectPage(this)); | |
106 _pageRegistry.add(new ErrorViewPage(this)); | |
107 _pageRegistry.add(new MetricsPage(this)); | |
108 // Note that ServiceObjectPage must be the last entry in the list as it is | |
109 // the catch all. | |
110 _pageRegistry.add(new ServiceObjectPage(this)); | |
111 } | |
112 | |
113 void _onError(ServiceError error) { | |
114 lastErrorOrException = error; | |
115 _visit('error/', null); | |
116 } | |
117 | |
118 void _onException(ServiceException exception) { | |
119 lastErrorOrException = exception; | |
120 if (exception.kind == 'NetworkException') { | |
121 // Got a network exception, visit the vm-connect page. | |
122 this.vm = null; | |
123 locationManager.go(locationManager.makeLink('/vm-connect/')); | |
124 } else { | |
125 _visit('error/', null); | |
126 } | |
127 } | |
128 | |
129 void _visit(String url, String args) { | |
130 var argsMap; | |
131 if (args == null) { | |
132 argsMap = {}; | |
133 } else { | |
134 argsMap = Uri.splitQueryString(args); | |
135 } | |
136 if (argsMap['trace'] != null) { | |
137 var traceArg = argsMap['trace']; | |
138 if (traceArg == 'on') { | |
139 Tracer.start(); | |
140 } else if (traceArg == 'off') { | |
141 Tracer.stop(); | |
142 } | |
143 } | |
144 if (Tracer.current != null) { | |
145 Tracer.current.reset(); | |
146 } | |
147 if (_traceView != null) { | |
148 _traceView.tracer = Tracer.current; | |
149 } | |
150 for (var i = 0; i < _pageRegistry.length; i++) { | |
151 var page = _pageRegistry[i]; | |
152 if (page.canVisit(url)) { | |
153 _installPage(page); | |
154 page.visit(url, argsMap); | |
155 return; | |
156 } | |
157 } | |
158 throw new FallThroughError(); | |
159 } | |
160 | |
161 /// Set the Observatory application page. | |
162 void _installPage(Page page) { | |
163 assert(page != null); | |
164 if (currentPage == page) { | |
165 // Already isntalled. | |
166 return; | |
167 } | |
168 if (currentPage != null) { | |
169 Logger.root.info('Uninstalling page: $currentPage'); | |
170 currentPage.onUninstall(); | |
171 // Clear children. | |
172 rootElement.children.clear(); | |
173 } | |
174 Logger.root.info('Installing page: $page'); | |
175 try { | |
176 page.onInstall(); | |
177 } catch (e) { | |
178 Logger.root.severe('Failed to install page: $e'); | |
179 } | |
180 // Add new page. | |
181 rootElement.children.add(page.element); | |
182 | |
183 // Add tracing support. | |
184 _traceView = new Element.tag('trace-view'); | |
185 _traceView.tracer = Tracer.current; | |
186 rootElement.children.add(_traceView); | |
187 | |
188 // Remember page. | |
189 currentPage = page; | |
190 } | |
191 | |
192 ObservatoryApplication.devtools(this.rootElement) : | |
193 locationManager = new HashLocationManager(), | |
194 targets = null { | |
195 vm = new PostMessageVM(); | |
196 _initOnce(true); | |
197 } | |
198 | |
199 ObservatoryApplication(this.rootElement) : | |
200 locationManager = new HashLocationManager(), | |
201 targets = new TargetManager() { | |
202 vm = new WebSocketVM(targets.defaultTarget); | |
203 _initOnce(false); | |
204 } | |
205 | |
206 void _removeDisconnectEvents() { | |
207 notifications.removeWhere((oldEvent) { | |
208 return (oldEvent.eventType == 'VMDisconnected'); | |
209 }); | |
210 } | |
211 | |
212 _vmConnected(VM vm) { | |
213 if (vm is WebSocketVM) { | |
214 targets.add(vm.target); | |
215 } | |
216 _removeDisconnectEvents(); | |
217 } | |
218 | |
219 _vmDisconnected(VM vm) { | |
220 if (this.vm != vm) { | |
221 // This disconnect event occured *after* a new VM was installed. | |
222 return; | |
223 } | |
224 this.vm = null; | |
225 notifications.add(new ServiceEvent.vmDisconencted()); | |
226 } | |
227 } | |
OLD | NEW |