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 app; | 5 part of app; |
6 | 6 |
7 /// A [Page] controls the user interface of Observatory. At any given time | 7 /// A [Page] controls the user interface of Observatory. At any given time |
8 /// one page will be the current page. Pages are registered at startup. | 8 /// one page will be the current page. Pages are registered at startup. |
9 /// When the user navigates within the application, each page is asked if it | 9 /// When the user navigates within the application, each page is asked if it |
10 /// can handle the current location, the first page to say yes, wins. | 10 /// can handle the current location, the first page to say yes, wins. |
11 abstract class Page extends Observable { | 11 abstract class Page extends Observable { |
12 final ObservatoryApplication app; | 12 final ObservatoryApplication app; |
13 | 13 |
14 @observable ObservatoryElement element; | 14 @observable ObservatoryElement element; |
15 @observable ObservableMap args; | 15 @observable ObservableMap args; |
16 | 16 |
17 Page(this.app); | 17 Page(this.app); |
18 | 18 |
19 /// Called when the page is installed, this callback must initialize | 19 /// Called when the page is installed, this callback must initialize |
20 /// [element]. | 20 /// [element]. |
21 void onInstall(); | 21 void onInstall(); |
22 | 22 |
23 /// Called when the page is uninstalled, this callback must clear | 23 /// Called when the page is uninstalled, this callback must clear |
24 /// [element]. | 24 /// [element]. |
25 void onUninstall() { | 25 void onUninstall() { |
26 element = null; | 26 element = null; |
27 } | 27 } |
28 | 28 |
29 /// Called when the page should update its state based on [url]. | 29 /// Called when the page should update its state based on [uri]. |
30 /// NOTE: Only called when the page is installed. | 30 /// NOTE: Only called when the page is installed. |
31 void visit(String url, Map argsMap) { | 31 void visit(Uri uri, Map argsMap) { |
32 args = toObservable(argsMap); | 32 args = toObservable(argsMap); |
33 _visit(url); | 33 _visit(uri); |
34 } | 34 } |
35 | 35 |
36 // Overridden by subclasses. | 36 // Overridden by subclasses. |
37 void _visit(String url); | 37 void _visit(Uri uri); |
38 | 38 |
39 /// Called to test whether this page can visit [url]. | 39 /// Called to test whether this page can visit [uri]. |
40 bool canVisit(String url); | 40 bool canVisit(Uri uri); |
41 } | 41 } |
42 | 42 |
43 /// A general service object viewer. | 43 /// A [SimplePage] matches a single uri path and displays a single element. |
44 class ServiceObjectPage extends Page { | 44 class SimplePage extends Page { |
45 ServiceObjectPage(app) : super(app); | 45 final String path; |
46 | |
47 void onInstall() { | |
48 if (element == null) { | |
49 /// Lazily create page. | |
50 element = new Element.tag('service-view'); | |
51 } | |
52 } | |
53 | |
54 void _visit(String url) { | |
55 assert(element != null); | |
56 assert(canVisit(url)); | |
57 if (url == '') { | |
58 // Nothing requested. | |
59 return; | |
60 } | |
61 /// Request url from VM and display it. | |
62 app.vm.getDeprecated(url).then((obj) { | |
63 ServiceObjectViewElement serviceElement = element; | |
64 serviceElement.object = obj; | |
65 }).catchError((e) { | |
66 Logger.root.severe('ServiceObjectPage visit error: $e'); | |
67 }); | |
68 } | |
69 | |
70 /// Catch all. | |
71 bool canVisit(String url) => true; | |
72 } | |
73 | |
74 class IsolateSuffixPage extends Page { | |
75 final String pagePrefix; | |
76 final String elementTagName; | 46 final String elementTagName; |
77 String _isolateId; | 47 SimplePage(this.path, this.elementTagName, app) : super(app); |
78 String get isolateId => _isolateId; | |
79 IsolateSuffixPage(this.pagePrefix, this.elementTagName, app) : super(app); | |
80 | 48 |
81 void onInstall() { | 49 void onInstall() { |
82 if (element == null) { | 50 if (element == null) { |
83 element = new Element.tag(elementTagName); | 51 element = new Element.tag(elementTagName); |
84 } | 52 } |
85 } | 53 } |
86 | 54 |
87 void _visit(String url) { | 55 void _visit(Uri uri) { |
88 assert(url != null); | 56 assert(uri != null); |
89 assert(canVisit(url)); | 57 assert(canVisit(uri)); |
90 _isolateId = url.substring(pagePrefix.length); | |
91 } | 58 } |
92 | 59 |
93 Future<Isolate> getIsolate() { | 60 Future<Isolate> getIsolate(Uri uri) { |
94 return app.vm.getIsolate(isolateId).catchError((e) { | 61 return app.vm.getIsolate(uri.queryParameters['isolateId']).catchError((e) { |
95 Logger.root.severe('$pagePrefix visit error: $e'); | 62 Logger.root.severe('$path visit error: $e'); |
96 return e; | 63 return e; |
97 }); | 64 }); |
98 } | 65 } |
99 | 66 |
100 bool canVisit(String url) => url.startsWith(pagePrefix); | 67 bool canVisit(Uri uri) => uri.path == path; |
68 } | |
69 | |
70 /// Error page for unrecognized paths. | |
71 class ErrorPage extends Page { | |
72 ErrorPage(app) : super(app); | |
73 | |
74 void onInstall() { | |
75 if (element == null) { | |
76 // Lazily create page. | |
77 element = new Element.tag('general-error'); | |
78 } | |
79 } | |
80 | |
81 void _visit(Uri uri) { | |
82 assert(element != null); | |
83 assert(canVisit(uri)); | |
84 | |
85 if (uri.path == '') { | |
86 // Nothing requested. | |
Cutch
2015/02/05 14:54:48
Should we display something in this case?
turnidge
2015/02/05 17:11:36
Removed.
| |
87 return; | |
88 } | |
89 | |
90 if (element != null) { | |
91 GeneralErrorElement serviceElement = element; | |
92 serviceElement.message = "Path '${uri.path}' not found"; | |
93 } | |
94 } | |
95 | |
96 /// Catch all. | |
97 bool canVisit(Uri uri) => true; | |
98 } | |
99 | |
100 /// Top-level vm info page. | |
101 class VMPage extends SimplePage { | |
102 VMPage(app) : super('vm', 'service-view', app); | |
103 | |
104 void _visit(Uri uri) { | |
105 super._visit(uri); | |
106 app.vm.reload().then((vm) { | |
107 if (element != null) { | |
108 ServiceObjectViewElement serviceElement = element; | |
109 serviceElement.object = vm; | |
110 } | |
111 }).catchError((e) { | |
112 Logger.root.severe('VMPage visit error: $e'); | |
113 }); | |
114 } | |
115 } | |
116 | |
117 class FlagsPage extends SimplePage { | |
118 FlagsPage(app) : super('flags', 'flag-list', app); | |
119 | |
120 void _visit(Uri uri) { | |
121 super._visit(uri); | |
122 app.vm.getFlagList().then((flags) { | |
123 if (element != null) { | |
124 FlagListElement serviceElement = element; | |
125 serviceElement.flagList = flags; | |
126 } | |
127 }).catchError((e) { | |
128 Logger.root.severe('FlagsPage visit error: $e'); | |
129 }); | |
130 } | |
131 } | |
132 | |
133 class InspectPage extends SimplePage { | |
134 InspectPage(app) : super('inspect', 'service-view', app); | |
135 | |
136 void _visit(Uri uri) { | |
137 super._visit(uri); | |
138 getIsolate(uri).then((isolate) { | |
139 var objectId = uri.queryParameters['objectId']; | |
140 if (objectId == null) { | |
141 isolate.reload().then(_visitObject); | |
142 } else { | |
143 isolate.getObject(objectId).then(_visitObject); | |
144 } | |
145 }); | |
146 } | |
147 | |
148 void _visitObject(obj) { | |
149 if (element != null) { | |
150 ServiceObjectViewElement serviceElement = element; | |
151 serviceElement.object = obj; | |
152 } | |
153 } | |
101 } | 154 } |
102 | 155 |
103 | 156 |
104 /// Class tree page. | 157 /// Class tree page. |
105 class ClassTreePage extends IsolateSuffixPage { | 158 class ClassTreePage extends SimplePage { |
106 ClassTreePage(app) : super('class-tree/', 'class-tree', app); | 159 ClassTreePage(app) : super('class-tree', 'class-tree', app); |
107 | 160 |
108 void _visit(String url) { | 161 void _visit(Uri uri) { |
109 super._visit(url); | 162 super._visit(uri); |
110 getIsolate().then((isolate) { | 163 getIsolate(uri).then((isolate) { |
111 if (element != null) { | 164 if (element != null) { |
112 /// Update the page. | 165 /// Update the page. |
113 ClassTreeElement page = element; | 166 ClassTreeElement page = element; |
114 page.isolate = isolate; | 167 page.isolate = isolate; |
115 } | 168 } |
116 }); | 169 }); |
117 } | 170 } |
118 } | 171 } |
119 | 172 |
120 class DebuggerPage extends IsolateSuffixPage { | 173 class DebuggerPage extends SimplePage { |
121 DebuggerPage(app) : super('debugger/', 'debugger-page', app); | 174 DebuggerPage(app) : super('debugger', 'debugger-page', app); |
122 | 175 |
123 void _visit(String url) { | 176 void _visit(Uri uri) { |
124 super._visit(url); | 177 super._visit(uri); |
125 getIsolate().then((isolate) { | 178 getIsolate(uri).then((isolate) { |
126 if (element != null) { | 179 if (element != null) { |
127 /// Update the page. | 180 /// Update the page. |
128 DebuggerPageElement page = element; | 181 DebuggerPageElement page = element; |
129 page.isolate = isolate; | 182 page.isolate = isolate; |
130 } | 183 } |
131 }); | 184 }); |
132 } | 185 } |
133 } | 186 } |
134 | 187 |
135 class CpuProfilerPage extends IsolateSuffixPage { | 188 class CpuProfilerPage extends SimplePage { |
136 CpuProfilerPage(app) : super('profiler/', 'cpu-profile', app); | 189 CpuProfilerPage(app) : super('profiler', 'cpu-profile', app); |
137 | 190 |
138 void _visit(String url) { | 191 void _visit(Uri uri) { |
139 super._visit(url); | 192 super._visit(uri); |
140 getIsolate().then((isolate) { | 193 getIsolate(uri).then((isolate) { |
141 if (element != null) { | 194 if (element != null) { |
142 /// Update the page. | 195 /// Update the page. |
143 CpuProfileElement page = element; | 196 CpuProfileElement page = element; |
144 page.isolate = isolate; | 197 page.isolate = isolate; |
145 } | 198 } |
146 }); | 199 }); |
147 } | 200 } |
148 } | 201 } |
149 | 202 |
150 class AllocationProfilerPage extends IsolateSuffixPage { | 203 class AllocationProfilerPage extends SimplePage { |
151 AllocationProfilerPage(app) | 204 AllocationProfilerPage(app) |
152 : super('allocation-profiler/', 'heap-profile', app); | 205 : super('allocation-profiler', 'heap-profile', app); |
153 | 206 |
154 void _visit(String url) { | 207 void _visit(Uri uri) { |
155 super._visit(url); | 208 super._visit(uri); |
156 getIsolate().then((isolate) { | 209 getIsolate(uri).then((isolate) { |
157 if (element != null) { | 210 if (element != null) { |
158 /// Update the page. | 211 /// Update the page. |
159 HeapProfileElement page = element; | 212 HeapProfileElement page = element; |
160 page.isolate = isolate; | 213 page.isolate = isolate; |
161 } | 214 } |
162 }); | 215 }); |
163 } | 216 } |
164 } | 217 } |
165 | 218 |
166 class HeapMapPage extends IsolateSuffixPage { | 219 class HeapMapPage extends SimplePage { |
167 HeapMapPage(app) : super('heap-map/', 'heap-map', app); | 220 HeapMapPage(app) : super('heap-map', 'heap-map', app); |
168 | 221 |
169 void _visit(String url) { | 222 void _visit(Uri uri) { |
170 super._visit(url); | 223 super._visit(uri); |
171 getIsolate().then((isolate) { | 224 getIsolate(uri).then((isolate) { |
172 if (element != null) { | 225 if (element != null) { |
173 /// Update the page. | 226 /// Update the page. |
174 HeapMapElement page = element; | 227 HeapMapElement page = element; |
175 page.isolate = isolate; | 228 page.isolate = isolate; |
176 } | 229 } |
177 }); | 230 }); |
178 } | 231 } |
179 } | 232 } |
180 | 233 |
181 class ErrorViewPage extends Page { | 234 class ErrorViewPage extends Page { |
182 ErrorViewPage(app) : super(app); | 235 ErrorViewPage(app) : super(app); |
183 | 236 |
184 void onInstall() { | 237 void onInstall() { |
185 if (element == null) { | 238 if (element == null) { |
186 /// Lazily create page. | 239 /// Lazily create page. |
187 element = new Element.tag('service-view'); | 240 element = new Element.tag('service-view'); |
188 } | 241 } |
189 } | 242 } |
190 | 243 |
191 void _visit(String url) { | 244 void _visit(Uri uri) { |
192 assert(element != null); | 245 assert(element != null); |
193 assert(canVisit(url)); | 246 assert(canVisit(uri)); |
194 (element as ServiceObjectViewElement).object = app.lastErrorOrException; | 247 (element as ServiceObjectViewElement).object = app.lastErrorOrException; |
195 } | 248 } |
196 | 249 |
197 bool canVisit(String url) => url.startsWith('error/'); | 250 // TODO(turnidge): How to test this page? |
251 bool canVisit(Uri uri) => uri.path.startsWith('error/'); | |
198 } | 252 } |
199 | 253 |
200 class VMConnectPage extends Page { | 254 class VMConnectPage extends Page { |
201 VMConnectPage(app) : super(app); | 255 VMConnectPage(app) : super(app); |
202 | 256 |
203 void onInstall() { | 257 void onInstall() { |
204 if (element == null) { | 258 if (element == null) { |
205 element = new Element.tag('vm-connect'); | 259 element = new Element.tag('vm-connect'); |
206 } | 260 } |
207 assert(element != null); | 261 assert(element != null); |
208 } | 262 } |
209 | 263 |
210 void _visit(String url) { | 264 void _visit(Uri uri) { |
211 assert(element != null); | 265 assert(element != null); |
212 assert(canVisit(url)); | 266 assert(canVisit(uri)); |
213 } | 267 } |
214 | 268 |
215 bool canVisit(String url) => url.startsWith('vm-connect/'); | 269 // TODO(turnidge): Update this to not have the trailing slash. |
270 bool canVisit(Uri uri) => uri.path.startsWith('vm-connect/'); | |
216 } | 271 } |
217 | 272 |
218 class MetricsPage extends Page { | 273 class MetricsPage extends Page { |
219 static RegExp _matcher = new RegExp(r'isolates/.*/metrics'); | |
220 static RegExp _isolateMatcher = new RegExp(r'isolates/.*/'); | |
221 | |
222 // Page state, retained as long as ObservatoryApplication. | 274 // Page state, retained as long as ObservatoryApplication. |
223 String selectedMetricId; | 275 String selectedMetricId; |
224 | 276 |
225 final Map<int, MetricPoller> pollers = new Map<int, MetricPoller>(); | 277 final Map<int, MetricPoller> pollers = new Map<int, MetricPoller>(); |
226 | 278 |
227 // 8 seconds, 4 seconds, 2 seconds, 1 second, and one hundred milliseconds. | 279 // 8 seconds, 4 seconds, 2 seconds, 1 second, and one hundred milliseconds. |
228 static final List<int> POLL_PERIODS = [8000, | 280 static final List<int> POLL_PERIODS = [8000, |
229 4000, | 281 4000, |
230 2000, | 282 2000, |
231 1000, | 283 1000, |
(...skipping 27 matching lines...) Expand all Loading... | |
259 } | 311 } |
260 var poller = pollers[refreshPeriod]; | 312 var poller = pollers[refreshPeriod]; |
261 if (poller != null) { | 313 if (poller != null) { |
262 poller.metrics.add(metric); | 314 poller.metrics.add(metric); |
263 metric.poller = poller; | 315 metric.poller = poller; |
264 return; | 316 return; |
265 } | 317 } |
266 throw new FallThroughError(); | 318 throw new FallThroughError(); |
267 } | 319 } |
268 | 320 |
269 String _isolateId(String url) { | 321 void _visit(Uri uri) { |
270 // Grab isolate prefix. | |
271 String isolateId = _isolateMatcher.stringMatch(url); | |
272 // Remove the trailing slash. | |
273 return isolateId.substring(0, isolateId.length - 1); | |
274 } | |
275 | |
276 void _visit(String url) { | |
277 assert(element != null); | 322 assert(element != null); |
278 assert(canVisit(url)); | 323 assert(canVisit(uri)); |
279 app.vm.getIsolate(_isolateId(url)).then((i) { | 324 app.vm.getIsolate(uri.queryParameters['isolateId']).then((i) { |
280 (element as MetricsPageElement).isolate = i; | 325 (element as MetricsPageElement).isolate = i; |
281 }); | 326 }); |
282 } | 327 } |
283 | 328 |
284 bool canVisit(String url) => _matcher.hasMatch(url); | 329 bool canVisit(Uri uri) => uri.path == 'metrics'; |
285 } | 330 } |
OLD | NEW |