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 /// A response to a service protocol extension RPC. |
| 8 /// |
| 9 /// If the RPC was successful, use [ServiceExtensionResponse.result], otherwise |
| 10 /// use [ServiceExtensionResponse.error]. |
| 11 class ServiceExtensionResponse { |
| 12 final String _result; |
| 13 final int _errorCode; |
| 14 final String _errorDetail; |
| 15 |
| 16 /// Creates a successful response to a service protocol extension RPC. |
| 17 /// |
| 18 /// Requires [result] to be a JSON object encoded as a string. When forming |
| 19 /// the JSON-RPC message [result] will be inlined directly. |
| 20 ServiceExtensionResponse.result(String result) |
| 21 : _result = result, |
| 22 _errorCode = null, |
| 23 _errorDetail = null { |
| 24 if (_result is! String) { |
| 25 throw new ArgumentError.value(_result, "result", "Must be a String"); |
| 26 } |
| 27 } |
| 28 |
| 29 /// Creates an error response to a service protocol extension RPC. |
| 30 /// |
| 31 /// Requires [errorCode] to be [invalidParams] or between [extensionErrorMin] |
| 32 /// and [extensionErrorMax]. Requires [errorDetail] to be a JSON object |
| 33 /// encoded as a string. When forming the JSON-RPC message [errorDetail] will |
| 34 /// be inlined directly. |
| 35 ServiceExtensionResponse.error(int errorCode, String errorDetail) |
| 36 : _result = null, |
| 37 _errorCode = errorCode, |
| 38 _errorDetail = errorDetail { |
| 39 _validateErrorCode(_errorCode); |
| 40 if (_errorDetail is! String) { |
| 41 throw new ArgumentError.value(_errorDetail, |
| 42 "errorDetail", |
| 43 "Must be a String"); |
| 44 } |
| 45 } |
| 46 |
| 47 /// Invalid method parameter(s) error code. |
| 48 @deprecated static const kInvalidParams = invalidParams; |
| 49 /// Generic extension error code. |
| 50 @deprecated static const kExtensionError = extensionError; |
| 51 /// Maximum extension provided error code. |
| 52 @deprecated static const kExtensionErrorMax = extensionErrorMax; |
| 53 /// Minimum extension provided error code. |
| 54 @deprecated static const kExtensionErrorMin = extensionErrorMin; |
| 55 |
| 56 /// Invalid method parameter(s) error code. |
| 57 static const invalidParams = -32602; |
| 58 /// Generic extension error code. |
| 59 static const extensionError = -32000; |
| 60 /// Maximum extension provided error code. |
| 61 static const extensionErrorMax = -32000; |
| 62 /// Minimum extension provided error code. |
| 63 static const extensionErrorMin = -32016; |
| 64 |
| 65 |
| 66 static String _errorCodeMessage(int errorCode) { |
| 67 _validateErrorCode(errorCode); |
| 68 if (errorCode == kInvalidParams) { |
| 69 return "Invalid params"; |
| 70 } |
| 71 return "Server error"; |
| 72 } |
| 73 |
| 74 static _validateErrorCode(int errorCode) { |
| 75 if (errorCode is! int) { |
| 76 throw new ArgumentError.value(errorCode, "errorCode", "Must be an int"); |
| 77 } |
| 78 if (errorCode == invalidParams) { |
| 79 return; |
| 80 } |
| 81 if ((errorCode >= extensionErrorMin) && |
| 82 (errorCode <= extensionErrorMax)) { |
| 83 return; |
| 84 } |
| 85 throw new ArgumentError.value(errorCode, "errorCode", "Out of range"); |
| 86 } |
| 87 |
| 88 bool _isError() => (_errorCode != null) && (_errorDetail != null); |
| 89 |
| 90 String _toString() { |
| 91 if (_result != null) { |
| 92 return _result; |
| 93 } else { |
| 94 assert(_errorCode != null); |
| 95 assert(_errorDetail != null); |
| 96 return JSON.encode({ |
| 97 'code': _errorCode, |
| 98 'message': _errorCodeMessage(_errorCode), |
| 99 'data': { |
| 100 'details': _errorDetail |
| 101 } |
| 102 }); |
| 103 } |
| 104 } |
| 105 } |
| 106 |
| 107 /// A service protocol extension handler. Registered with [registerExtension]. |
| 108 /// |
| 109 /// Must complete to a [ServiceExtensionResponse]. |
| 110 /// |
| 111 /// [method] - the method name of the service protocol request. |
| 112 /// [parameters] - A map holding the parameters to the service protocol request. |
| 113 /// |
| 114 /// *NOTE*: All parameter names and values are **encoded as strings**. |
| 115 typedef Future<ServiceExtensionResponse> |
| 116 ServiceExtensionHandler(String method, Map<String, String> parameters); |
| 117 |
| 118 /// Register a [ServiceExtensionHandler] that will be invoked in this isolate |
| 119 /// for [method]. *NOTE*: Service protocol extensions must be registered |
| 120 /// in each isolate. |
| 121 /// |
| 122 /// *NOTE*: [method] must begin with 'ext.' and you should use the following |
| 123 /// structure to avoid conflicts with other packages: 'ext.package.command'. |
| 124 /// That is, immediately following the 'ext.' prefix, should be the registering |
| 125 /// package name followed by another period ('.') and then the command name. |
| 126 /// For example: 'ext.dart.io.getOpenFiles'. |
| 127 /// |
| 128 /// Because service extensions are isolate specific, clients using extensions |
| 129 /// must always include an 'isolateId' parameter with each RPC. |
| 130 void registerExtension(String method, ServiceExtensionHandler handler) { |
| 131 if (method is! String) { |
| 132 throw new ArgumentError.value(method, |
| 133 'method', |
| 134 'Must be a String'); |
| 135 } |
| 136 if (!method.startsWith('ext.')) { |
| 137 throw new ArgumentError.value(method, |
| 138 'method', |
| 139 'Must begin with ext.'); |
| 140 } |
| 141 if (_lookupExtension(method) != null) { |
| 142 throw new ArgumentError('Extension already registered: $method'); |
| 143 } |
| 144 if (handler is! ServiceExtensionHandler) { |
| 145 throw new ArgumentError.value(handler, |
| 146 'handler', |
| 147 'Must be a ServiceExtensionHandler'); |
| 148 } |
| 149 _registerExtension(method, handler); |
| 150 } |
| 151 |
| 152 /// Post an event of [eventKind] with payload of [eventData] to the `Extension` |
| 153 /// event stream. |
| 154 void postEvent(String eventKind, Map eventData) { |
| 155 if (eventKind is! String) { |
| 156 throw new ArgumentError.value(eventKind, |
| 157 'eventKind', |
| 158 'Must be a String'); |
| 159 } |
| 160 if (eventData is! Map) { |
| 161 throw new ArgumentError.value(eventData, |
| 162 'eventData', |
| 163 'Must be a Map'); |
| 164 } |
| 165 String eventDataAsString = JSON.encode(eventData); |
| 166 _postEvent(eventKind, eventDataAsString); |
| 167 } |
| 168 |
| 169 external _postEvent(String eventKind, String eventData); |
| 170 |
| 171 // Both of these functions are written inside C++ to avoid updating the data |
| 172 // structures in Dart, getting an OOB, and observing stale state. Do not move |
| 173 // these into Dart code unless you can ensure that the operations will can be |
| 174 // done atomically. Native code lives in vm/isolate.cc- |
| 175 // LookupServiceExtensionHandler and RegisterServiceExtensionHandler. |
| 176 external ServiceExtensionHandler _lookupExtension(String method); |
| 177 external _registerExtension(String method, ServiceExtensionHandler handler); |
OLD | NEW |