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

Unified Diff: pkg/analysis_server/lib/src/protocol.dart

Issue 137853026: Basic communication protocol for server (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 11 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
Index: pkg/analysis_server/lib/src/protocol.dart
diff --git a/pkg/analysis_server/lib/src/protocol.dart b/pkg/analysis_server/lib/src/protocol.dart
new file mode 100644
index 0000000000000000000000000000000000000000..86600eb05e74eba94544cd2e9dc072794dfdc461
--- /dev/null
+++ b/pkg/analysis_server/lib/src/protocol.dart
@@ -0,0 +1,363 @@
+// Copyright (c) 2014, 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.
+
+library protocol;
+
+import 'dart:convert';
devoncarew 2014/01/20 22:35:01 Perhaps, import 'dart:convert' show JSON;
Brian Wilkerson 2014/01/21 03:21:20 Added 'show JsonDecoder' pending resolution of the
+
+/**
+ * Instances of the class [Request] represent a request that was received.
+ */
+class Request {
+ /**
+ * The name of the JSON attribute containing the id of the request.
+ */
+ static const String ID = 'id';
+
+ /**
+ * The name of the JSON attribute containing the name of the request.
+ */
+ static const String METHOD = 'method';
+
+ /**
+ * The name of the JSON attribute containing the request parameters.
+ */
+ static const String PARAMS = 'params';
+
+ /**
+ * The unique identifier used to identify this request.
+ */
+ final String id;
+
+ /**
+ * The method being requested.
+ */
+ final String method;
+
+ /**
+ * A table mapping the names of request parameters to their values.
+ */
+ final Map<String, Object> params = new Map<String, Object>();
+
+ /**
+ * A decoder that can be used to decode strings into JSON objects.
+ */
+ static const JsonDecoder DECODER = const JsonDecoder(null);
devoncarew 2014/01/20 22:35:01 You can delete this line.
Brian Wilkerson 2014/01/21 03:21:20 Only if I make the next change.
+
+ /**
+ * Initialize a newly created [Request] to have the given [id] and [method]
+ * name.
+ */
+ Request(this.id, this.method);
+
+ /**
+ * Return a request parsed from the given [data], or `null` if the [data] is
+ * not a valid json representation of a request. The [data] is expected to
+ * have the following format:
+ *
+ * {
+ * 'id': String,
+ * 'method': methodName,
+ * 'params': {
+ * paramter_name: value
+ * }
+ * }
+ *
+ * where the parameters are optional and can contain any number of name/value
+ * pairs.
+ */
+ factory Request.fromString(String data) {
+ try {
+ var result = DECODER.convert(data);
devoncarew 2014/01/20 22:35:01 ==> var result = JSON.decode(data);
Brian Wilkerson 2014/01/21 03:21:20 I considered this, but this method creates a new d
devoncarew 2014/01/21 04:16:08 Hmm, I was not aware that a new decoder is created
+ if (result is! Map) {
+ return null;
+ }
+ String id = result[Request.ID];
+ String method = result[Request.METHOD];
+ Map<String, Object> params = result[Request.PARAMS];
+ Request request = new Request(id, method);
+ params.forEach((String key, Object value) {
+ request.setParameter(key, value);
+ });
+ return request;
+ } catch (exception) {
+ return null;
+ }
+ }
+
+ /**
+ * Return the value of the parameter with the given [name], or `null` if there
+ * is no such parameter associated with this request.
+ */
+ Object getParameter(String name) => params[name];
+
+ /**
+ * Return the value of the parameter with the given [name], or throw a
+ * [RequestFailure] exception with an appropriate error message if there is no
+ * such parameter associated with this request.
+ */
+ Object getRequiredParameter(String name) {
+ Object value = params[name];
+ if (value == null) {
+ throw new RequestFailure(new Response.missingRequiredParameter(this, name));
+ }
+ return value;
+ }
+
+ /**
+ * Set the value of the parameter with the given [name] to the given [value].
+ */
+ void setParameter(String name, Object value) {
+ params[name] = value;
+ }
+
+ /**
+ * Convert the given [value] to a boolean, or throw a [RequestFailure]
+ * exception if the [value] could not be converted.
+ *
+ * The value is typically the result of invoking either [getParameter] or
+ * [getRequiredParameter].
+ */
+ bool toBool(Object value) {
+ if (value is bool) {
+ return value;
+ } else if (value is String) {
+ return value == 'true';
+ }
+ throw new RequestFailure(new Response.expectedBoolean(this, value));
+ }
+
+ /**
+ * Convert the given [value] to an integer, or throw a [RequestFailure]
+ * exception if the [value] could not be converted.
+ *
+ * The value is typically the result of invoking either [getParameter] or
+ * [getRequiredParameter].
+ */
+ int toInt(Object value) {
+ if (value is int) {
+ return value;
+ } else if (value is String) {
+ return int.parse(value, onError: (String value) {
+ throw new RequestFailure(new Response.expectedInteger(this, value));
+ });
+ }
+ throw new RequestFailure(new Response.expectedInteger(this, value));
+ }
+}
+
+/**
+ * Instances of the class [Response] represent a response to a request.
+ */
+class Response {
+ /**
+ * The name of the JSON attribute containing the id of the request for which
+ * this is a response.
+ */
+ static const String ID = 'id';
+
+ /**
+ * The name of the JSON attribute containing the error message.
+ */
+ static const String ERROR = 'error';
+
+ /**
+ * The name of the JSON attribute containing the result values.
+ */
+ static const String RESULT = 'result';
+
+ /**
+ * The unique identifier used to identify the request that this response is
+ * associated with.
+ */
+ final String id;
+
+ /**
+ * The error that was caused by attempting to handle the request, or `null` if
+ * there was no error.
+ */
+ final Object error;
+
+ /**
+ * A table mapping the names of result fields to their values. The table
+ * should be empty if there was an error.
+ */
+ final Map<String, Object> result = new Map<String, Object>();
+
+ /**
+ * Initialize a newly created instance to represent a response to a request
+ * with the given [id]. If an [error] is provided then the response will
+ * represent an error condition.
+ */
+ Response(this.id, [this.error]);
+
+ /**
+ * Initialize a newly created instance to represent an error condition caused
+ * by a [request] referencing a context that does not exist.
+ */
+ Response.contextDoesNotExist(Request request)
+ : this(request.id, 'Context does not exist');
+
+ /**
+ * Initialize a newly created instance to represent an error condition caused
+ * by a [request] that was expected to have a boolean-valued parameter but was
+ * passed a non-boolean value.
+ */
+ Response.expectedBoolean(Request request, String value)
+ : this(request.id, 'Expected a boolean value, but found "$value"');
+
+ /**
+ * Initialize a newly created instance to represent an error condition caused
+ * by a [request] that was expected to have a integer-valued parameter but was
+ * passed a non-integer value.
+ */
+ Response.expectedInteger(Request request, String value)
+ : this(request.id, 'Expected an integer value, but found "$value"');
+
+ /**
+ * Initialize a newly created instance to represent an error condition caused
+ * by a malformed request.
+ */
+ Response.invalidRequestFormat()
+ : this('', 'Invalid request');
+
+ /**
+ * Initialize a newly created instance to represent an error condition caused
+ * by a [request] that does not have a required parameter.
+ */
+ Response.missingRequiredParameter(Request request, String parameterName)
+ : this(request.id, 'Missing required parameter: $parameterName');
+
+ /**
+ * Initialize a newly created instance to represent an error condition caused
+ * by a [request] that takes a set of analysis options but for which an
+ * unknown analysis option was provided.
+ */
+ Response.unknownAnalysisOption(Request request, String optionName)
+ : this(request.id, 'Unknown analysis option: "$optionName"');
+
+ /**
+ * Initialize a newly created instance to represent an error condition caused
+ * by a [request] that cannot be handled by any known handlers.
+ */
+ Response.unknownRequest(Request request)
+ : this(request.id, 'Unknown request');
+
+ /**
+ * Return the value of the result field with the given [name].
+ */
+ Object getResult(String name) {
+ return result[name];
+ }
+
+ /**
+ * Set the value of the result field with the given [name] to the given [value].
+ */
+ void setResult(String name, Object value) {
+ result[name] = value;
+ }
+
+ /**
+ * Return a table representing the structure of the Json object that will be
+ * sent to the client to represent this response.
+ */
+ Map<String, Object> toJson() {
devoncarew 2014/01/20 22:35:01 I have generally seen this as: Map<String, dynami
Brian Wilkerson 2014/01/21 03:21:20 The difference primarily has to do with warnings.
+ Map jsonObject = new Map();
+ jsonObject[ID] = id;
+ jsonObject[ERROR] = error;
+ if (!result.isEmpty) {
+ jsonObject[RESULT] = result;
+ }
+ return jsonObject;
+ }
+}
+
+/**
+ * Instances of the class [Notification] represent a notification from the
+ * server about an event that occurred.
+ */
+class Notification {
+ /**
+ * The name of the JSON attribute containing the name of the event that
+ * triggered the notification.
+ */
+ static const String EVENT = 'event';
+
+ /**
+ * The name of the JSON attribute containing the result values.
+ */
+ static const String PARAMS = 'params';
+
+ /**
+ * The name of the event that triggered the notification.
+ */
+ final String event;
+
+ /**
+ * A table mapping the names of notification parameters to their values.
+ */
+ final Map<String, Object> params = new Map<String, Object>();
+
+ /**
+ * Initialize a newly created [Notification] to have the given [event] name.
+ */
+ Notification(this.event);
+
+ /**
+ * Return the value of the parameter with the given [name], or `null` if there
+ * is no such parameter associated with this notification.
+ */
+ Object getParameter(String name) => params[name];
+
+ /**
+ * Set the value of the parameter with the given [name] to the given [value].
+ */
+ void setParameter(String name, Object value) {
+ params[name] = value;
+ }
+
+ /**
+ * Return a table representing the structure of the Json object that will be
+ * sent to the client to represent this response.
+ */
+ Map<String, Object> toJson() {
+ Map jsonObject = new Map();
+ jsonObject[EVENT] = event;
+ if (!params.isEmpty) {
+ jsonObject[PARAMS] = params;
+ }
+ return jsonObject;
+ }
+}
+
+/**
+ * Instances of the class [RequestHandler] implement a handler that can handle
+ * requests and produce responses for them.
+ */
+abstract class RequestHandler {
+ /**
+ * Attempt to handle the given [request]. If the request is not recognized by
+ * this handler, return `null` so that other handlers will be given a chance
+ * to handle it. Otherwise, return the response that should be passed back to
+ * the client.
+ */
+ Response handleRequest(Request request);
+}
+
+/**
+ * Instances of the class [RequestFailure] represent an exception that occurred
+ * during the handling of a request that requires that an error be returned to
+ * the client.
+ */
+class RequestFailure implements Exception {
+ /**
+ * The response to be returned as a result of the failure.
+ */
+ final Response response;
+
+ /**
+ * Initialize a newly created exception to return the given reponse.
+ */
+ RequestFailure(this.response);
+}

Powered by Google App Engine
This is Rietveld 408576698