Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 part of dart.developer; | |
| 6 | |
| 7 class ServiceExtensionResponse { | |
| 8 final String _result; | |
| 9 final int _errorCode; | |
| 10 final String _errorDetail; | |
| 11 | |
| 12 ServiceExtensionResponse.result(this._result) | |
| 13 : _errorCode = null, | |
| 14 _errorDetail = null { | |
| 15 if (_result is! String) { | |
| 16 throw new ArgumentError.value(_result, "result", "Must be a String"); | |
| 17 } | |
| 18 } | |
| 19 | |
| 20 ServiceExtensionResponse.error(this._errorCode, this._errorDetail) | |
| 21 : _result = null { | |
| 22 _validateErrorCode(_errorCode); | |
| 23 if (_errorDetail is! String) { | |
| 24 throw new ArgumentError.value(_errorDetail, | |
| 25 "errorDetail", | |
| 26 "Must be a String"); | |
| 27 } | |
| 28 } | |
| 29 | |
| 30 /// Invalid method parameter(s) error code. | |
| 31 static const kInvalidParams = -32602; | |
| 32 /// Generic extension error code. | |
| 33 static const kExtensionError = -32000; | |
| 34 /// Maximum extension provided error code. | |
| 35 static const kExtensionErrorMax = -32000; | |
| 36 /// Minimum extension provided error code. | |
| 37 static const kExtensionErrorMin = -32016; | |
| 38 | |
| 39 static String _errorCodeMessage(int errorCode) { | |
| 40 _validateErrorCode(errorCode); | |
| 41 if (errorCode == kInvalidParams) { | |
| 42 return "Invalid params"; | |
| 43 } | |
| 44 return "Server error"; | |
| 45 } | |
| 46 | |
| 47 static _validateErrorCode(int errorCode) { | |
| 48 if (errorCode is! int) { | |
| 49 throw new ArgumentError.value(errorCode, "errorCode", "Must be an int"); | |
| 50 } | |
| 51 if (errorCode == kInvalidParams) { | |
| 52 return; | |
| 53 } | |
| 54 if ((errorCode >= kExtensionErrorMin) && | |
| 55 (errorCode <= kExtensionErrorMax)) { | |
| 56 return; | |
| 57 } | |
| 58 throw new ArgumentError.value(errorCode, "errorCode", "Out of range"); | |
| 59 } | |
| 60 | |
| 61 bool _isError() => (_errorCode != null) && (_errorDetail != null); | |
| 62 | |
| 63 String _toString() { | |
| 64 if (_result != null) { | |
| 65 return _result; | |
| 66 } else { | |
| 67 assert(_errorCode != null); | |
| 68 assert(_errorDetail != null); | |
| 69 return JSON.encode({ | |
| 70 'code': _errorCode, | |
| 71 'message': _errorCodeMessage(_errorCode), | |
| 72 'data': { | |
| 73 'details': _errorDetail | |
| 74 } | |
| 75 }); | |
| 76 } | |
| 77 } | |
| 78 } | |
| 79 | |
| 80 /// A service protocol extension handler. Registered with [registerExtension]. | |
| 81 /// | |
| 82 /// Must complete to a [ServiceExtensionResponse]. | |
| 83 /// | |
| 84 /// [method] - the method name. | |
| 85 /// [parameters] - the parameters. | |
| 86 typedef Future<ServiceExtensionResponse> | |
| 87 ServiceExtensionHandler(String method, Map parameters); | |
| 88 | |
| 89 final _extensions = new Map<String, ServiceExtensionHandler>(); | |
| 90 | |
| 91 /// Register a [ServiceExtensionHandler] that will be invoked in this isolate | |
| 92 /// for [method]. | |
| 93 void registerExtension(String method, ServiceExtensionHandler handler) { | |
| 94 if (_extensions[method] != null) { | |
| 95 throw new ArgumentError('Extension already registered: $method'); | |
| 96 } | |
| 97 if (handler is! ServiceExtensionHandler) { | |
| 98 throw new ArgumentError.value(handler, | |
| 99 'handler', | |
| 100 'Must be a ServiceExtensionHandler'); | |
| 101 } | |
| 102 _extensions[method] = handler; | |
| 103 } | |
| 104 | |
| 105 bool _extensionExists(String method) { | |
| 106 return _extensions[method] != null; | |
| 107 } | |
| 108 | |
| 109 bool _invokeExtension(String method, | |
| 110 List<String> parameterKeys, | |
| 111 List<String> parameterValues, | |
| 112 SendPort replyPort, | |
| 113 Object id) { | |
| 114 ServiceExtensionHandler handler = _extensions[method]; | |
| 115 assert(handler); | |
| 116 var parameters = {}; | |
| 117 for (var i = 0; i < parameterKeys.length; i++) { | |
| 118 parameters[parameterKeys[i]] = parameterValues[i]; | |
| 119 } | |
| 120 var response; | |
| 121 try { | |
| 122 response = handler(method, parameters); | |
| 123 } catch (e, st) { | |
| 124 var errorDetails = (st == null) ? '$e' : '$e\n$st'; | |
| 125 response = new ServiceExtensionResponse.error( | |
| 126 ServiceExtensionResponse.kExtensionError, | |
| 127 errorDetails); | |
| 128 } | |
| 129 if (response is! Future) { | |
|
turnidge
2015/08/06 18:12:54
I would prefer to force the user to always return
Cutch
2015/08/06 23:20:18
Done.
| |
| 130 response = new Future.value(response); | |
| 131 } | |
| 132 response.catchError((e, st) { | |
| 133 var errorDetails = (st == null) ? '$e' : '$e\n$st'; | |
| 134 return new ServiceExtensionResponse.error( | |
| 135 ServiceExtensionResponse.kExtensionError, | |
| 136 errorDetails); | |
| 137 }).then((response) { | |
| 138 if (response == null) { | |
| 139 response = new ServiceExtensionResponse.error( | |
| 140 ServiceExtensionResponse.kExtensionError, | |
| 141 "Extension handler returned null"); | |
| 142 } | |
| 143 _postResponse(replyPort, id, response); | |
| 144 }); | |
| 145 // Push an event on the event loop so that we invoke the scheduled microtasks. | |
| 146 Timer.run(() {}); | |
| 147 return true; | |
| 148 } | |
| 149 | |
| 150 _postResponse(SendPort replyPort, | |
| 151 Object id, | |
| 152 ServiceExtensionResponse response) { | |
| 153 assert(replyPort != null); | |
| 154 if (id == null) { | |
| 155 // No id -> no response. | |
| 156 // TODO(johnmccutchan): This code and the code in service.cc leave the | |
| 157 // service isolate with an open port. Consider posting 'null' to indicate | |
| 158 // that no response is coming. | |
| 159 return; | |
| 160 } | |
| 161 assert(id != null); | |
| 162 StringBuffer sb = new StringBuffer(); | |
| 163 sb.write('{"jsonrpc":"2.0",'); | |
| 164 if (response._isError()) { | |
| 165 sb.write('"error":'); | |
| 166 } else { | |
| 167 sb.write('"result":'); | |
| 168 } | |
| 169 sb.write('${response._toString()},'); | |
| 170 if (id is String) { | |
| 171 sb.write('"id":"$id"}'); | |
| 172 } else { | |
| 173 sb.write('"id":$id}'); | |
| 174 } | |
| 175 replyPort.send(sb.toString()); | |
| 176 } | |
| OLD | NEW |