Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(286)

Side by Side Diff: sdk/lib/developer/extension.dart

Issue 1270103002: Allow Dart code to register service protocol handlers (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sdk/lib/developer/developer_sources.gypi ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 != null);
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 _postResponse(replyPort, id, response);
129 return true;
130 }
131 if (response is! Future) {
132 response = new ServiceExtensionResponse.error(
133 ServiceExtensionResponse.kExtensionError,
134 "Extension handler must return a Future");
135 _postResponse(replyPort, id, response);
136 return true;
137 }
138 response.catchError((e, st) {
139 var errorDetails = (st == null) ? '$e' : '$e\n$st';
140 return new ServiceExtensionResponse.error(
141 ServiceExtensionResponse.kExtensionError,
142 errorDetails);
143 }).then((response) {
144 if (response == null) {
145 response = new ServiceExtensionResponse.error(
146 ServiceExtensionResponse.kExtensionError,
147 "Extension handler returned null");
148 }
149 _postResponse(replyPort, id, response);
150 });
151 // Push an event on the event loop so that we invoke the scheduled microtasks.
152 Timer.run(() {});
153 return true;
154 }
155
156 _postResponse(SendPort replyPort,
157 Object id,
158 ServiceExtensionResponse response) {
159 assert(replyPort != null);
160 if (id == null) {
161 // No id -> no response.
162 // TODO(johnmccutchan): This code and the code in service.cc leave the
163 // service isolate with an open port. Consider posting 'null' to indicate
164 // that no response is coming.
165 return;
166 }
167 assert(id != null);
168 StringBuffer sb = new StringBuffer();
169 sb.write('{"jsonrpc":"2.0",');
170 if (response._isError()) {
171 sb.write('"error":');
172 } else {
173 sb.write('"result":');
174 }
175 sb.write('${response._toString()},');
176 if (id is String) {
177 sb.write('"id":"$id"}');
178 } else {
179 sb.write('"id":$id}');
180 }
181 replyPort.send(sb.toString());
182 }
OLDNEW
« no previous file with comments | « sdk/lib/developer/developer_sources.gypi ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698