| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 library dart._vmservice; | 5 library dart._vmservice; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 import 'dart:convert'; | 9 import 'dart:convert'; |
| 10 import 'dart:isolate'; | 10 import 'dart:isolate'; |
| 11 import 'dart:typed_data'; | 11 import 'dart:typed_data'; |
| 12 | 12 |
| 13 part 'asset.dart'; | 13 part 'asset.dart'; |
| 14 part 'client.dart'; | 14 part 'client.dart'; |
| 15 part 'devfs.dart'; |
| 15 part 'constants.dart'; | 16 part 'constants.dart'; |
| 16 part 'running_isolate.dart'; | 17 part 'running_isolate.dart'; |
| 17 part 'running_isolates.dart'; | 18 part 'running_isolates.dart'; |
| 18 part 'message.dart'; | 19 part 'message.dart'; |
| 19 part 'message_router.dart'; | 20 part 'message_router.dart'; |
| 20 | 21 |
| 21 final RawReceivePort isolateLifecyclePort = new RawReceivePort(); | 22 final RawReceivePort isolateLifecyclePort = new RawReceivePort(); |
| 22 final RawReceivePort scriptLoadPort = new RawReceivePort(); | 23 final RawReceivePort scriptLoadPort = new RawReceivePort(); |
| 23 | 24 |
| 24 abstract class IsolateEmbedderData { | 25 abstract class IsolateEmbedderData { |
| 25 void cleanup(); | 26 void cleanup(); |
| 26 } | 27 } |
| 27 | 28 |
| 28 // This is for use by the embedder. It is a map from the isolateId to | 29 // This is for use by the embedder. It is a map from the isolateId to |
| 29 // anything implementing IsolateEmbedderData. When an isolate goes away, | 30 // anything implementing IsolateEmbedderData. When an isolate goes away, |
| 30 // the cleanup method will be invoked after being removed from the map. | 31 // the cleanup method will be invoked after being removed from the map. |
| 31 final Map<int, IsolateEmbedderData> isolateEmbedderData = | 32 final Map<int, IsolateEmbedderData> isolateEmbedderData = |
| 32 new Map<int, IsolateEmbedderData>(); | 33 new Map<int, IsolateEmbedderData>(); |
| 33 | 34 |
| 34 // These must be kept in sync with the declarations in vm/json_stream.h. | 35 // These must be kept in sync with the declarations in vm/json_stream.h. |
| 35 const kInvalidParams = -32602; | 36 const kInvalidParams = -32602; |
| 36 const kInternalError = -32603; | 37 const kInternalError = -32603; |
| 37 const kStreamAlreadySubscribed = 103; | 38 const kFeatureDisabled = 100; |
| 38 const kStreamNotSubscribed = 104; | 39 const kStreamAlreadySubscribed = 103; |
| 40 const kStreamNotSubscribed = 104; |
| 41 const kFileSystemAlreadyExists = 1001; |
| 42 const kFileSystemDoesNotExist = 1002; |
| 43 const kFileDoesNotExist = 1003; |
| 39 | 44 |
| 40 var _errorMessages = { | 45 var _errorMessages = { |
| 41 kInvalidParams: 'Invalid params', | 46 kInvalidParams: 'Invalid params', |
| 42 kInternalError: 'Internal error', | 47 kInternalError: 'Internal error', |
| 48 kFeatureDisabled: 'Feature is disabled', |
| 43 kStreamAlreadySubscribed: 'Stream already subscribed', | 49 kStreamAlreadySubscribed: 'Stream already subscribed', |
| 44 kStreamNotSubscribed: 'Stream not subscribed', | 50 kStreamNotSubscribed: 'Stream not subscribed', |
| 51 kFileSystemAlreadyExists: 'File system already exists', |
| 52 kFileSystemDoesNotExist: 'File system does not exist', |
| 53 kFileDoesNotExist: 'File does not exist', |
| 45 }; | 54 }; |
| 46 | 55 |
| 47 String encodeRpcError(Message message, int code, {String details}) { | 56 String encodeRpcError(Message message, int code, {String details}) { |
| 48 var response = { | 57 var response = { |
| 49 'jsonrpc': '2.0', | 58 'jsonrpc': '2.0', |
| 50 'id' : message.serial, | 59 'id' : message.serial, |
| 51 'error' : { | 60 'error' : { |
| 52 'code': code, | 61 'code': code, |
| 53 'message': _errorMessages[code], | 62 'message': _errorMessages[code], |
| 54 }, | 63 }, |
| 55 }; | 64 }; |
| 56 if (details != null) { | 65 if (details != null) { |
| 57 response['error']['data'] = { | 66 response['error']['data'] = { |
| 58 'details': details, | 67 'details': details, |
| 59 }; | 68 }; |
| 60 } | 69 } |
| 61 return JSON.encode(response); | 70 return JSON.encode(response); |
| 62 } | 71 } |
| 63 | 72 |
| 73 String encodeMissingParamError(Message message, String param) { |
| 74 return encodeRpcError( |
| 75 message, kInvalidParams, |
| 76 details: "${message.method} expects the '${param}' parameter"); |
| 77 } |
| 78 |
| 79 String encodeInvalidParamError(Message message, String param) { |
| 80 var value = message.params[param]; |
| 81 return encodeRpcError( |
| 82 message, kInvalidParams, |
| 83 details: "${message.method}: invalid '${param}' parameter: ${value}"); |
| 84 } |
| 85 |
| 64 String encodeResult(Message message, Map result) { | 86 String encodeResult(Message message, Map result) { |
| 65 var response = { | 87 var response = { |
| 66 'jsonrpc': '2.0', | 88 'jsonrpc': '2.0', |
| 67 'id' : message.serial, | 89 'id' : message.serial, |
| 68 'result' : result, | 90 'result' : result, |
| 69 }; | 91 }; |
| 70 return JSON.encode(response); | 92 return JSON.encode(response); |
| 71 } | 93 } |
| 72 | 94 |
| 95 String encodeSuccess(Message message) { |
| 96 return encodeResult(message, { 'type': 'Success' }); |
| 97 } |
| 98 |
| 73 const shortDelay = const Duration(milliseconds: 10); | 99 const shortDelay = const Duration(milliseconds: 10); |
| 74 | 100 |
| 75 /// Called when the server should be started. | 101 /// Called when the server should be started. |
| 76 typedef Future ServerStartCallback(); | 102 typedef Future ServerStartCallback(); |
| 77 | 103 |
| 78 /// Called when the server should be stopped. | 104 /// Called when the server should be stopped. |
| 79 typedef Future ServerStopCallback(); | 105 typedef Future ServerStopCallback(); |
| 80 | 106 |
| 81 /// Called when the service is exiting. | 107 /// Called when the service is exiting. |
| 82 typedef Future CleanupCallback(); | 108 typedef Future CleanupCallback(); |
| 83 | 109 |
| 110 /// Called to create a temporary directory |
| 111 typedef Future<Uri> CreateTempDirCallback(String base); |
| 112 |
| 113 /// Called to delete a directory |
| 114 typedef Future DeleteDirCallback(Uri path); |
| 115 |
| 116 /// Called to write a file. |
| 117 typedef Future WriteFileCallback(Uri path, List<int> bytes); |
| 118 |
| 119 /// Called to read a file. |
| 120 typedef Future<List<int>> ReadFileCallback(Uri path); |
| 121 |
| 122 /// Called to list all files under some path. |
| 123 typedef Future<List<Map<String,String>>> ListFilesCallback(Uri path); |
| 124 |
| 84 /// Hooks that are setup by the embedder. | 125 /// Hooks that are setup by the embedder. |
| 85 class VMServiceEmbedderHooks { | 126 class VMServiceEmbedderHooks { |
| 86 static ServerStartCallback serverStart; | 127 static ServerStartCallback serverStart; |
| 87 static ServerStopCallback serverStop; | 128 static ServerStopCallback serverStop; |
| 88 static CleanupCallback cleanup; | 129 static CleanupCallback cleanup; |
| 130 static CreateTempDirCallback createTempDir; |
| 131 static DeleteDirCallback deleteDir; |
| 132 static WriteFileCallback writeFile; |
| 133 static ReadFileCallback readFile; |
| 134 static ListFilesCallback listFiles; |
| 89 } | 135 } |
| 90 | 136 |
| 91 class VMService extends MessageRouter { | 137 class VMService extends MessageRouter { |
| 92 static VMService _instance; | 138 static VMService _instance; |
| 93 | 139 |
| 94 /// Collection of currently connected clients. | 140 /// Collection of currently connected clients. |
| 95 final Set<Client> clients = new Set<Client>(); | 141 final Set<Client> clients = new Set<Client>(); |
| 96 | 142 |
| 97 /// Collection of currently running isolates. | 143 /// Collection of currently running isolates. |
| 98 RunningIsolates runningIsolates = new RunningIsolates(); | 144 RunningIsolates runningIsolates = new RunningIsolates(); |
| 99 | 145 |
| 100 /// A port used to receive events from the VM. | 146 /// A port used to receive events from the VM. |
| 101 final RawReceivePort eventPort; | 147 final RawReceivePort eventPort; |
| 102 | 148 |
| 149 final _devfs = new DevFS(); |
| 150 |
| 103 void _addClient(Client client) { | 151 void _addClient(Client client) { |
| 104 assert(client.streams.isEmpty); | 152 assert(client.streams.isEmpty); |
| 105 clients.add(client); | 153 clients.add(client); |
| 106 } | 154 } |
| 107 | 155 |
| 108 void _removeClient(Client client) { | 156 void _removeClient(Client client) { |
| 109 clients.remove(client); | 157 clients.remove(client); |
| 110 for (var streamId in client.streams) { | 158 for (var streamId in client.streams) { |
| 111 if (!_isAnyClientSubscribed(streamId)) { | 159 if (!_isAnyClientSubscribed(streamId)) { |
| 112 _vmCancelStream(streamId); | 160 _vmCancelStream(streamId); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 151 // Close receive ports. | 199 // Close receive ports. |
| 152 isolateLifecyclePort.close(); | 200 isolateLifecyclePort.close(); |
| 153 scriptLoadPort.close(); | 201 scriptLoadPort.close(); |
| 154 | 202 |
| 155 // Create a copy of the set as a list because client.disconnect() will | 203 // Create a copy of the set as a list because client.disconnect() will |
| 156 // alter the connected clients set. | 204 // alter the connected clients set. |
| 157 var clientsList = clients.toList(); | 205 var clientsList = clients.toList(); |
| 158 for (var client in clientsList) { | 206 for (var client in clientsList) { |
| 159 client.disconnect(); | 207 client.disconnect(); |
| 160 } | 208 } |
| 209 _devfs.cleanup(); |
| 161 if (VMServiceEmbedderHooks.cleanup != null) { | 210 if (VMServiceEmbedderHooks.cleanup != null) { |
| 162 await VMServiceEmbedderHooks.cleanup(); | 211 await VMServiceEmbedderHooks.cleanup(); |
| 163 } | 212 } |
| 164 // Notify the VM that we have exited. | 213 // Notify the VM that we have exited. |
| 165 _onExit(); | 214 _onExit(); |
| 166 } | 215 } |
| 167 | 216 |
| 168 void messageHandler(message) { | 217 void messageHandler(message) { |
| 169 if (message is List) { | 218 if (message is List) { |
| 170 if (message.length == 2) { | 219 if (message.length == 2) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 } | 270 } |
| 222 if (!_isAnyClientSubscribed(streamId)) { | 271 if (!_isAnyClientSubscribed(streamId)) { |
| 223 if (!_vmListenStream(streamId)) { | 272 if (!_vmListenStream(streamId)) { |
| 224 return encodeRpcError( | 273 return encodeRpcError( |
| 225 message, kInvalidParams, | 274 message, kInvalidParams, |
| 226 details:"streamListen: invalid 'streamId' parameter: ${streamId}"); | 275 details:"streamListen: invalid 'streamId' parameter: ${streamId}"); |
| 227 } | 276 } |
| 228 } | 277 } |
| 229 client.streams.add(streamId); | 278 client.streams.add(streamId); |
| 230 | 279 |
| 231 var result = { 'type' : 'Success' }; | 280 return encodeSuccess(message); |
| 232 return encodeResult(message, result); | |
| 233 } | 281 } |
| 234 | 282 |
| 235 Future<String> _streamCancel(Message message) async { | 283 Future<String> _streamCancel(Message message) async { |
| 236 var client = message.client; | 284 var client = message.client; |
| 237 var streamId = message.params['streamId']; | 285 var streamId = message.params['streamId']; |
| 238 | 286 |
| 239 if (!client.streams.contains(streamId)) { | 287 if (!client.streams.contains(streamId)) { |
| 240 return encodeRpcError(message, kStreamNotSubscribed); | 288 return encodeRpcError(message, kStreamNotSubscribed); |
| 241 } | 289 } |
| 242 client.streams.remove(streamId); | 290 client.streams.remove(streamId); |
| 243 if (!_isAnyClientSubscribed(streamId)) { | 291 if (!_isAnyClientSubscribed(streamId)) { |
| 244 _vmCancelStream(streamId); | 292 _vmCancelStream(streamId); |
| 245 } | 293 } |
| 246 | 294 |
| 247 var result = { 'type' : 'Success' }; | 295 return encodeSuccess(message); |
| 248 return encodeResult(message, result); | |
| 249 } | 296 } |
| 250 | 297 |
| 251 // TODO(johnmccutchan): Turn this into a command line tool that uses the | 298 // TODO(johnmccutchan): Turn this into a command line tool that uses the |
| 252 // service library. | 299 // service library. |
| 253 Future<String> _getCrashDump(Message message) async { | 300 Future<String> _getCrashDump(Message message) async { |
| 254 var client = message.client; | 301 var client = message.client; |
| 255 final perIsolateRequests = [ | 302 final perIsolateRequests = [ |
| 256 // ?isolateId=<isolate id> will be appended to each of these requests. | 303 // ?isolateId=<isolate id> will be appended to each of these requests. |
| 257 // Isolate information. | 304 // Isolate information. |
| 258 Uri.parse('getIsolate'), | 305 Uri.parse('getIsolate'), |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 313 // TODO(turnidge): Update to json rpc. BEFORE SUBMIT. | 360 // TODO(turnidge): Update to json rpc. BEFORE SUBMIT. |
| 314 if (message.method == '_getCrashDump') { | 361 if (message.method == '_getCrashDump') { |
| 315 return _getCrashDump(message); | 362 return _getCrashDump(message); |
| 316 } | 363 } |
| 317 if (message.method == 'streamListen') { | 364 if (message.method == 'streamListen') { |
| 318 return _streamListen(message); | 365 return _streamListen(message); |
| 319 } | 366 } |
| 320 if (message.method == 'streamCancel') { | 367 if (message.method == 'streamCancel') { |
| 321 return _streamCancel(message); | 368 return _streamCancel(message); |
| 322 } | 369 } |
| 370 if (_devfs.shouldHandleMessage(message)) { |
| 371 return _devfs.handleMessage(message); |
| 372 } |
| 323 if (message.params['isolateId'] != null) { | 373 if (message.params['isolateId'] != null) { |
| 324 return runningIsolates.route(message); | 374 return runningIsolates.route(message); |
| 325 } | 375 } |
| 326 return message.sendToVM(); | 376 return message.sendToVM(); |
| 327 } | 377 } |
| 328 } | 378 } |
| 329 | 379 |
| 330 RawReceivePort boot() { | 380 RawReceivePort boot() { |
| 331 // Return the port we expect isolate startup and shutdown messages on. | 381 // Return the port we expect isolate startup and shutdown messages on. |
| 332 return isolateLifecyclePort; | 382 return isolateLifecyclePort; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 347 external void onServerAddressChange(String address); | 397 external void onServerAddressChange(String address); |
| 348 | 398 |
| 349 /// Subscribe to a service stream. | 399 /// Subscribe to a service stream. |
| 350 external bool _vmListenStream(String streamId); | 400 external bool _vmListenStream(String streamId); |
| 351 | 401 |
| 352 /// Cancel a subscription to a service stream. | 402 /// Cancel a subscription to a service stream. |
| 353 external void _vmCancelStream(String streamId); | 403 external void _vmCancelStream(String streamId); |
| 354 | 404 |
| 355 /// Get the bytes to the tar archive. | 405 /// Get the bytes to the tar archive. |
| 356 external Uint8List _requestAssets(); | 406 external Uint8List _requestAssets(); |
| OLD | NEW |