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

Unified Diff: corelib/src/proxy.dart

Issue 8536006: rpc example for directory file listing (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: builtin_in.cc Created 9 years, 1 month 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: corelib/src/proxy.dart
diff --git a/corelib/src/proxy.dart b/corelib/src/proxy.dart
new file mode 100644
index 0000000000000000000000000000000000000000..8683af4b69a96b79a71ea28d9dc64798fd58ac68
--- /dev/null
+++ b/corelib/src/proxy.dart
@@ -0,0 +1,242 @@
+// Copyright (c) 2011, 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.
+
+/**
+ * Base class for all RpcProxy's
+ *
+ * RpcProxy objects run in the "client" isolate and have a SendPort which
+ * they use to send messages to RpcReceiver objects running in a "service"
+ * isolate.
+ */
+
+class RpcProxy {
+ final Future<SendPort> futurePort;
+ RpcProxy(Future<SendPort> this.futurePort) {}
+
+ /**
+ * Called by derived classes to send a command through a SendPort to
+ * an RpcReceiver.
+ *
+ * parameters:
+ * command - String identifying what command to execute
+ * args - optional list of arguments to the command (this may contain other
+ * RpcProxy objects to refer to other target objects in the service
+ * isolate).
+ *
+ * returns:
+ * a Future object that will be set to the value that was
+ * received as a reply to the SendPort call.
+ */
+ Future sendCommand(String command, List args, adjustReply(Object value)) {
+ Completer completer = new Completer();
+ futurePort.then((SendPort port) {
+ args = _filterArgs(args);
+ port.call({"command" : command, "args" : args}).receive(
+ (value, ignoreReplyTo) {
+ assert(ignoreReplyTo === null);
+ value = _filterException(value);
+ if (adjustReply != null) {
+ // give derived proxy class a chance to transate SendPort to
+ // RpcProxy
+ value = adjustReply(value);
+ }
+ if (value is Exception) {
+ completer.completeException(value);
+ } else {
+ completer.complete(value);
+ }
+ }
+ );
+ });
+ return completer.future;
+ }
+
+ /**
+ * Convert RpcProxy objects to SendPorts
Siggi Cherem (dart-lang) 2011/11/30 01:44:38 style nits: - use single line /** ... */ for comme
mattsh 2011/11/30 05:03:33 Done.
+ */
+ static List _filterArgs(List args) {
+ if (args == null) {
+ return null;
+ }
+ List filtered = new List();
+ for (Object arg in args) {
+ if (arg is RpcProxy) {
+ RpcProxy proxy = arg;
+ // TODO - need to figure out if/how to wait for proxy's
+ // port to be ready
+ filtered.add(proxy.futurePort.value);
+ } else {
+ filtered.add(arg);
+ }
+ }
+ return filtered;
+ }
+
+ // TODO (mattsh) hack, remove once we have serializable exceptions
+ Object _filterException(Object value) {
+ // Check if value is a serialized exception.
+ Exception e = RpcException.parse(value);
+ if (e != null) {
+ return e;
+ } else {
+ return value;
+ }
+ }
+}
+
+
+
+/**
+ * Base class for all Receivers
+ *
+ * RpcReceiver objects have a ReceivePort, where they receive commands (from
+ * RpcProxy objects) that they interpret and translate into method
+ * calls on a "target" object.
+ *
+ * All RpcReceiver derived classes must implement the [receiveCommand] abstract
+ * method (where they actually command messages and call
+ * appropriate methods on the target object).
+ *
+ * type parameters:
+ * T - the type of the target object that this a receiver for
+ */
+class RpcReceiver<T> {
+
+ // static map of containing all receivers in this isolate. This is used
+ // to be able to find a receiver and target, given a SendPort.
+ static Map<SendPort, RpcReceiver> _receivers;
+ static _register(RpcReceiver receiver) {
+ if (_receivers == null) {
+ _receivers = new Map<SendPort, RpcReceiver>();
+ }
+ _receivers[receiver._receivePort.toSendPort()] = receiver;
+ }
+
+ static void closeAll() {
+ for (RpcReceiver receiver in _receivers.getValues()) {
+ receiver._receivePort.close();
+ }
+ }
+
+ // the port that this receiver will listen on
Siggi Cherem (dart-lang) 2011/11/30 01:44:38 (nit): to be consistent with all of our libraries,
Siggi Cherem (dart-lang) 2011/11/30 01:46:45 (here and elsewhere in this code)
mattsh 2011/11/30 05:03:33 Done.
mattsh 2011/11/30 05:03:33 Done.
+ final ReceivePort _receivePort;
+
+ // the "target" object that this RpcReceiver will be calling
+ // to actually do some work.
+ final T target;
+
+ RpcReceiver(T this.target, ReceivePort this._receivePort) {
+ // place this receiver in the receiver registry
+ _register(this);
+
+ // start listening on the receive port for command messages
+ _receivePort.receive((var message, SendPort replyTo) {
+ String command = message["command"];
+
+ // filter incoming arguments (looking for SendPorts
+ // that we need to translate to RpcReceiver objects)
+ List args = _filterIncomingArgs(message["args"]);
+
+ // Call the derived RpcReceiver to execute the command
+ // (if the command throws an exception, then catch the
+ // exception, serialize it, and send as the reply)
+ Object reply;
+ try {
+ reply = receiveCommand(message["command"], args);
+ } catch (var e) {
+ // TODO(mattsh) - would really prefer to catch Object, but currently
+ // bug http://code.google.com/p/dart/issues/detail?id=469
+ reply = RpcException.format(e);
+ }
+
+ reply = _filterReply(reply);
+
+ // send reply back to the proxy
+ replyTo.send(reply, null);
+ });
+ }
+
+ /**
+ * Translate any ReceivePort objects in the arguments to
+ * the corresponding target object.
+ */
+ static List _filterIncomingArgs(List originalArgs) {
+ List args = new List();
+ var i = 0;
+ if (originalArgs != null) {
+ for (var arg in originalArgs) {
+ if (arg is SendPort) {
+ if (_receivers[arg] == null) {
+ throw "can't find receiver for SendPort";
+ }
+ arg = _receivers[arg].target;
+ if (arg == null) {
+ throw "receiver is missing target";
+ }
+ }
+ args.add(arg);
+ i++;
+ }
+ }
+ return args;
+ }
+
+ /**
+ * Walk over the reply that this receiver is about to send
+ * back, and:
+ * 1. translate RpcReceiver objects in the reply to the corresponding
+ * ReceivePort.
Siggi Cherem (dart-lang) 2011/11/30 01:44:38 nit: is there a 2. ?, remove the bullet list?
mattsh 2011/11/30 05:03:33 Done.
+ *
+ * TODO(mattsh) need to walk deeply
Siggi Cherem (dart-lang) 2011/11/30 01:46:45 TODO's shouldn't be inside the /** */ docs, so tha
mattsh 2011/11/30 05:03:33 Done.
+ */
+ static _filterReply(Object reply) {
+ if (reply is RpcReceiver) {
+ RpcReceiver receiver = reply;
+ reply = receiver._receivePort.toSendPort();
+ }
+ return reply;
+ }
+
+ /**
+ * (implemented by derived classes).
+ *
+ * parameters -
+ * command - String identifying what command to execute
+ * on the target object
+ * args - list of arguments to the command (if any arguments
+ * were ReceivePorts, these have been translated to the
+ * corresponding target objects, so this List79 will not
+ * contain any ReceivePorts)
+ */
+ abstract Object receiveCommand(String command, List args);
+}
+
+// TODO - hack - need better way to serialize exceptions. For now
Siggi Cherem (dart-lang) 2011/11/30 01:44:38 TODO(mattsh)? no need to say 'hack'
mattsh 2011/11/30 05:03:33 Done.
+// we take the message, and prefix with a recognizable string.
+class RpcException implements Exception {
+
+ static final String prefix = "RpcException:";
+
+ final String message;
+ const RpcException(String this.message);
+
+ String toString() {
+ return message;
+ }
+
+ static String format(Exception e) {
+ return prefix + e.toString();
+ }
+
+ static RpcException parse(Object object) {
+ if (object === null || !(object is String)) {
+ return null;
+ }
+ String s = object;
+ if (!s.startsWith(prefix)) {
+ return null;
+ }
+ return new RpcException(s.substring(prefix.length, s.length));
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698