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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sdk/lib/developer/developer_sources.gypi ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/developer/extension.dart
diff --git a/sdk/lib/developer/extension.dart b/sdk/lib/developer/extension.dart
new file mode 100644
index 0000000000000000000000000000000000000000..95c3db2e7253eb3b3d2b7aab9bba0d2f5f2853b0
--- /dev/null
+++ b/sdk/lib/developer/extension.dart
@@ -0,0 +1,182 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.developer;
+
+class ServiceExtensionResponse {
+ final String _result;
+ final int _errorCode;
+ final String _errorDetail;
+
+ ServiceExtensionResponse.result(this._result)
+ : _errorCode = null,
+ _errorDetail = null {
+ if (_result is! String) {
+ throw new ArgumentError.value(_result, "result", "Must be a String");
+ }
+ }
+
+ ServiceExtensionResponse.error(this._errorCode, this._errorDetail)
+ : _result = null {
+ _validateErrorCode(_errorCode);
+ if (_errorDetail is! String) {
+ throw new ArgumentError.value(_errorDetail,
+ "errorDetail",
+ "Must be a String");
+ }
+ }
+
+ /// Invalid method parameter(s) error code.
+ static const kInvalidParams = -32602;
+ /// Generic extension error code.
+ static const kExtensionError = -32000;
+ /// Maximum extension provided error code.
+ static const kExtensionErrorMax = -32000;
+ /// Minimum extension provided error code.
+ static const kExtensionErrorMin = -32016;
+
+ static String _errorCodeMessage(int errorCode) {
+ _validateErrorCode(errorCode);
+ if (errorCode == kInvalidParams) {
+ return "Invalid params";
+ }
+ return "Server error";
+ }
+
+ static _validateErrorCode(int errorCode) {
+ if (errorCode is! int) {
+ throw new ArgumentError.value(errorCode, "errorCode", "Must be an int");
+ }
+ if (errorCode == kInvalidParams) {
+ return;
+ }
+ if ((errorCode >= kExtensionErrorMin) &&
+ (errorCode <= kExtensionErrorMax)) {
+ return;
+ }
+ throw new ArgumentError.value(errorCode, "errorCode", "Out of range");
+ }
+
+ bool _isError() => (_errorCode != null) && (_errorDetail != null);
+
+ String _toString() {
+ if (_result != null) {
+ return _result;
+ } else {
+ assert(_errorCode != null);
+ assert(_errorDetail != null);
+ return JSON.encode({
+ 'code': _errorCode,
+ 'message': _errorCodeMessage(_errorCode),
+ 'data': {
+ 'details': _errorDetail
+ }
+ });
+ }
+ }
+}
+
+/// A service protocol extension handler. Registered with [registerExtension].
+///
+/// Must complete to a [ServiceExtensionResponse].
+///
+/// [method] - the method name.
+/// [parameters] - the parameters.
+typedef Future<ServiceExtensionResponse>
+ ServiceExtensionHandler(String method, Map parameters);
+
+final _extensions = new Map<String, ServiceExtensionHandler>();
+
+/// Register a [ServiceExtensionHandler] that will be invoked in this isolate
+/// for [method].
+void registerExtension(String method, ServiceExtensionHandler handler) {
+ if (_extensions[method] != null) {
+ throw new ArgumentError('Extension already registered: $method');
+ }
+ if (handler is! ServiceExtensionHandler) {
+ throw new ArgumentError.value(handler,
+ 'handler',
+ 'Must be a ServiceExtensionHandler');
+ }
+ _extensions[method] = handler;
+}
+
+bool _extensionExists(String method) {
+ return _extensions[method] != null;
+}
+
+bool _invokeExtension(String method,
+ List<String> parameterKeys,
+ List<String> parameterValues,
+ SendPort replyPort,
+ Object id) {
+ ServiceExtensionHandler handler = _extensions[method];
+ assert(handler != null);
+ var parameters = {};
+ for (var i = 0; i < parameterKeys.length; i++) {
+ parameters[parameterKeys[i]] = parameterValues[i];
+ }
+ var response;
+ try {
+ response = handler(method, parameters);
+ } catch (e, st) {
+ var errorDetails = (st == null) ? '$e' : '$e\n$st';
+ response = new ServiceExtensionResponse.error(
+ ServiceExtensionResponse.kExtensionError,
+ errorDetails);
+ _postResponse(replyPort, id, response);
+ return true;
+ }
+ if (response is! Future) {
+ response = new ServiceExtensionResponse.error(
+ ServiceExtensionResponse.kExtensionError,
+ "Extension handler must return a Future");
+ _postResponse(replyPort, id, response);
+ return true;
+ }
+ response.catchError((e, st) {
+ var errorDetails = (st == null) ? '$e' : '$e\n$st';
+ return new ServiceExtensionResponse.error(
+ ServiceExtensionResponse.kExtensionError,
+ errorDetails);
+ }).then((response) {
+ if (response == null) {
+ response = new ServiceExtensionResponse.error(
+ ServiceExtensionResponse.kExtensionError,
+ "Extension handler returned null");
+ }
+ _postResponse(replyPort, id, response);
+ });
+ // Push an event on the event loop so that we invoke the scheduled microtasks.
+ Timer.run(() {});
+ return true;
+}
+
+_postResponse(SendPort replyPort,
+ Object id,
+ ServiceExtensionResponse response) {
+ assert(replyPort != null);
+ if (id == null) {
+ // No id -> no response.
+ // TODO(johnmccutchan): This code and the code in service.cc leave the
+ // service isolate with an open port. Consider posting 'null' to indicate
+ // that no response is coming.
+ return;
+ }
+ assert(id != null);
+ StringBuffer sb = new StringBuffer();
+ sb.write('{"jsonrpc":"2.0",');
+ if (response._isError()) {
+ sb.write('"error":');
+ } else {
+ sb.write('"result":');
+ }
+ sb.write('${response._toString()},');
+ if (id is String) {
+ sb.write('"id":"$id"}');
+ } else {
+ sb.write('"id":$id}');
+ }
+ replyPort.send(sb.toString());
+}
« 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