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 |