| OLD | NEW |
| 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 observatory; | 5 part of observatory; |
| 6 | 6 |
| 7 /// A request response interceptor is called for each response. | 7 /// A request response interceptor is called for each response. |
| 8 typedef void RequestResponseInterceptor(); | 8 typedef void RequestResponseInterceptor(); |
| 9 | 9 |
| 10 abstract class RequestManager extends Observable { | 10 abstract class RequestManager extends Observable { |
| 11 ObservatoryApplication _application; | 11 ObservatoryApplication _application; |
| 12 ObservatoryApplication get application => _application; | 12 ObservatoryApplication get application => _application; |
| 13 RequestResponseInterceptor interceptor; | 13 RequestResponseInterceptor interceptor; |
| 14 | 14 |
| 15 /// The default request prefix is 127.0.0.1 on port 8181. | 15 /// The default request prefix is 127.0.0.1 on port 8181. |
| 16 @observable String prefix = 'http://127.0.0.1:8181'; | 16 @observable String prefix = 'http://127.0.0.1:8181'; |
| 17 /// List of responses. | 17 /// List of responses. |
| 18 @observable List<Map> responses = toObservable([]); | 18 @observable List<Map> responses = toObservable([]); |
| 19 | 19 |
| 20 /// Decode [response] into a map. |
| 21 Map decodeResponse(String response) { |
| 22 var m; |
| 23 try { |
| 24 m = JSON.decode(response); |
| 25 } catch (e, st) { |
| 26 setResponseError('$e $st'); |
| 27 }; |
| 28 return m; |
| 29 } |
| 30 |
| 20 /// Parse | 31 /// Parse |
| 21 void parseResponses(String responseString) { | 32 void parseResponses(String responseString) { |
| 22 var r; | 33 var r = decodeResponse(responseString); |
| 23 try { | 34 if (r == null) { |
| 24 r = JSON.decode(responseString); | 35 return; |
| 25 } catch (e) { | |
| 26 setResponseError(e.message); | |
| 27 } | 36 } |
| 28 if (r is Map) { | 37 if (r is Map) { |
| 29 setResponses([r]); | 38 setResponses([r]); |
| 30 } else { | 39 } else { |
| 31 setResponses(r); | 40 setResponses(r); |
| 32 } | 41 } |
| 33 } | 42 } |
| 34 | 43 |
| 35 void setResponses(List<Map> r) { | 44 void setResponses(List<Map> r) { |
| 36 responses = toObservable(r); | 45 responses = toObservable(r); |
| 37 if (interceptor != null) { | 46 if (interceptor != null) { |
| 38 interceptor(); | 47 interceptor(); |
| 39 } | 48 } |
| 40 } | 49 } |
| 41 | 50 |
| 42 void setResponseRequestError(HttpRequest request) { | 51 void setResponseRequestError(HttpRequest request) { |
| 43 String error = '${request.status} ${request.statusText}'; | 52 String error = '${request.status} ${request.statusText}'; |
| 44 if (request.status == 0) { | 53 if (request.status == 0) { |
| 45 error = 'No service found. Did you run with --enable-vm-service ?'; | 54 error = 'No service found. Did you run with --enable-vm-service ?'; |
| 46 } | 55 } |
| 47 setResponses([{ | 56 setResponses([{ |
| 48 'type': 'RequestError', | 57 'type': 'Error', |
| 58 'errorType': 'RequestError', |
| 49 'error': error | 59 'error': error |
| 50 }]); | 60 }]); |
| 51 } | 61 } |
| 52 | 62 |
| 53 void setResponseError(String message) { | 63 void setResponseError(String message) { |
| 54 setResponses([{ | 64 setResponses([{ |
| 55 'type': 'Error', | 65 'type': 'Error', |
| 66 'errorType': 'ResponseError', |
| 56 'text': message | 67 'text': message |
| 57 }]); | 68 }]); |
| 69 Logger.root.severe(message); |
| 58 } | 70 } |
| 59 | 71 |
| 60 /// Request [requestString] from the VM service. Updates [responses]. | 72 static final RegExp _codeMatcher = new RegExp(r'/isolates/\d+/code/'); |
| 73 static bool isCodeRequest(url) => _codeMatcher.hasMatch(url); |
| 74 static int codeAddressFromRequest(String url) { |
| 75 Match m = _codeMatcher.matchAsPrefix(url); |
| 76 if (m == null) { |
| 77 return 0; |
| 78 } |
| 79 try { |
| 80 var a = int.parse(m.input.substring(m.end), radix: 16); |
| 81 return a; |
| 82 } catch (e) { |
| 83 return 0; |
| 84 } |
| 85 } |
| 86 |
| 87 static final RegExp _isolateMatcher = new RegExp(r"/isolates/\d+"); |
| 88 static String isolatePrefixFromRequest(String url) { |
| 89 Match m = _isolateMatcher.matchAsPrefix(url); |
| 90 if (m == null) { |
| 91 return null; |
| 92 } |
| 93 return m.input.substring(m.start, m.end); |
| 94 } |
| 95 |
| 96 static String isolateIdFromRequest(String url) { |
| 97 var prefix = isolatePrefixFromRequest(url); |
| 98 if (prefix == null) { |
| 99 return null; |
| 100 } |
| 101 // Chop off the '/'. |
| 102 return prefix.substring(1); |
| 103 } |
| 104 |
| 105 void _setModelResponse(String type, String modelName, dynamic model) { |
| 106 var response = { |
| 107 'type': type, |
| 108 modelName: model |
| 109 }; |
| 110 setResponses([response]); |
| 111 } |
| 112 |
| 113 /// Handle 'Code' requests |
| 114 void _getCode(String requestString) { |
| 115 var isolateId = isolateIdFromRequest(requestString); |
| 116 if (isolateId == null) { |
| 117 setResponseError('$isolateId is not an isolate id.'); |
| 118 return; |
| 119 } |
| 120 var isolate = _application.isolateManager.getIsolate(isolateId); |
| 121 if (isolate == null) { |
| 122 setResponseError('$isolateId could not be found.'); |
| 123 return; |
| 124 } |
| 125 var address = codeAddressFromRequest(requestString); |
| 126 if (address == 0) { |
| 127 setResponseError('$requestString is not a valid code request.'); |
| 128 return; |
| 129 } |
| 130 var code = isolate.findCodeByAddress(address); |
| 131 if (code != null) { |
| 132 Logger.root.info( |
| 133 'Found code with 0x${address.toRadixString(16)} in isolate.'); |
| 134 _setModelResponse('Code', 'code', code); |
| 135 return; |
| 136 } |
| 137 request(requestString).then((responseString) { |
| 138 var map = decodeResponse(responseString); |
| 139 if (map == null) { |
| 140 return; |
| 141 } |
| 142 assert(map['type'] == 'Code'); |
| 143 var code = new Code.fromMap(map); |
| 144 Logger.root.info( |
| 145 'Added code with 0x${address.toRadixString(16)} to isolate.'); |
| 146 isolate.codes.add(code); |
| 147 _setModelResponse('Code', 'code', code); |
| 148 }).catchError(_requestCatchError); |
| 149 } |
| 150 |
| 151 void _requestCatchError(e, st) { |
| 152 if (e is HttpRequest) { |
| 153 setResponseRequestError(e.target); |
| 154 } else { |
| 155 setResponseError('$e $st'); |
| 156 } |
| 157 } |
| 158 |
| 159 /// Request [request] from the VM service. Updates [responses]. |
| 61 /// Will trigger [interceptor] if one is set. | 160 /// Will trigger [interceptor] if one is set. |
| 62 void get(String requestString) { | 161 void get(String requestString) { |
| 162 if (isCodeRequest(requestString)) { |
| 163 _getCode(requestString); |
| 164 return; |
| 165 } |
| 63 request(requestString).then((responseString) { | 166 request(requestString).then((responseString) { |
| 64 parseResponses(responseString); | 167 parseResponses(responseString); |
| 65 }).catchError((e) { | 168 }).catchError(_requestCatchError); |
| 66 setResponseRequestError(e.target); | |
| 67 return null; | |
| 68 }); | |
| 69 } | 169 } |
| 70 | 170 |
| 71 /// Abstract method. Given the [requestString], return a String in the | 171 /// Abstract method. Given the [requestString], return a String in the |
| 72 /// future which contains the reply from the VM service. | 172 /// future which contains the reply from the VM service. |
| 73 Future<String> request(String requestString); | 173 Future<String> request(String requestString); |
| 174 |
| 175 Future<Map> requestMap(String requestString) { |
| 176 return request(requestString).then((response) { |
| 177 try { |
| 178 var m = JSON.decode(response); |
| 179 return m; |
| 180 } catch (e) { } |
| 181 return null; |
| 182 }); |
| 183 } |
| 74 } | 184 } |
| 75 | 185 |
| 76 | 186 |
| 77 class HttpRequestManager extends RequestManager { | 187 class HttpRequestManager extends RequestManager { |
| 78 Future<String> request(String requestString) { | 188 Future<String> request(String requestString) { |
| 189 Logger.root.info('Requesting $requestString'); |
| 79 return HttpRequest.getString(prefix + requestString); | 190 return HttpRequest.getString(prefix + requestString); |
| 80 } | 191 } |
| 81 } | 192 } |
| 82 | 193 |
| 83 class PostMessageRequestManager extends RequestManager { | 194 class PostMessageRequestManager extends RequestManager { |
| 84 final Map _outstandingRequests = new Map(); | 195 final Map _outstandingRequests = new Map(); |
| 85 int _requestSerial = 0; | 196 int _requestSerial = 0; |
| 86 PostMessageRequestManager() { | 197 PostMessageRequestManager() { |
| 87 window.onMessage.listen(_messageHandler); | 198 window.onMessage.listen(_messageHandler); |
| 88 } | 199 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 113 message['query'] = requestString; | 224 message['query'] = requestString; |
| 114 _requestSerial++; | 225 _requestSerial++; |
| 115 | 226 |
| 116 var completer = new Completer(); | 227 var completer = new Completer(); |
| 117 _outstandingRequests[idString] = completer; | 228 _outstandingRequests[idString] = completer; |
| 118 | 229 |
| 119 window.parent.postMessage(JSON.encode(message), '*'); | 230 window.parent.postMessage(JSON.encode(message), '*'); |
| 120 return completer.future; | 231 return completer.future; |
| 121 } | 232 } |
| 122 } | 233 } |
| OLD | NEW |