Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011, 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 /** | |
| 6 * Base class for all RpcProxy's | |
| 7 * | |
| 8 * RpcProxy objects run in the "client" isolate and have a SendPort which | |
| 9 * they use to send messages to RpcReceiver objects running in a "service" | |
| 10 * isolate. | |
| 11 */ | |
| 12 | |
| 13 class RpcProxy { | |
| 14 final Future<SendPort> futurePort; | |
| 15 RpcProxy(Future<SendPort> this.futurePort) {} | |
| 16 | |
| 17 /** | |
| 18 * Called by derived classes to send a command through a SendPort to | |
| 19 * an RpcReceiver. | |
| 20 * | |
| 21 * parameters: | |
| 22 * command - String identifying what command to execute | |
| 23 * args - optional list of arguments to the command (this may contain other | |
| 24 * RpcProxy objects to refer to other target objects in the service | |
| 25 * isolate). | |
| 26 * | |
| 27 * returns: | |
| 28 * a Future object that will be set to the value that was | |
| 29 * received as a reply to the SendPort call. | |
| 30 */ | |
| 31 Future sendCommand(String command, List args, adjustReply(Object value)) { | |
| 32 Completer completer = new Completer(); | |
| 33 futurePort.then((SendPort port) { | |
| 34 args = _filterArgs(args); | |
| 35 port.call({"command" : command, "args" : args}).receive( | |
| 36 (value, ignoreReplyTo) { | |
| 37 assert(ignoreReplyTo === null); | |
| 38 value = _filterException(value); | |
| 39 if (adjustReply != null) { | |
| 40 // give derived proxy class a chance to transate SendPort to | |
| 41 // RpcProxy | |
| 42 value = adjustReply(value); | |
| 43 } | |
| 44 if (value is Exception) { | |
| 45 completer.completeException(value); | |
| 46 } else { | |
| 47 completer.complete(value); | |
| 48 } | |
| 49 } | |
| 50 ); | |
| 51 }); | |
| 52 return completer.future; | |
| 53 } | |
| 54 | |
| 55 /** | |
| 56 * 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.
| |
| 57 */ | |
| 58 static List _filterArgs(List args) { | |
| 59 if (args == null) { | |
| 60 return null; | |
| 61 } | |
| 62 List filtered = new List(); | |
| 63 for (Object arg in args) { | |
| 64 if (arg is RpcProxy) { | |
| 65 RpcProxy proxy = arg; | |
| 66 // TODO - need to figure out if/how to wait for proxy's | |
| 67 // port to be ready | |
| 68 filtered.add(proxy.futurePort.value); | |
| 69 } else { | |
| 70 filtered.add(arg); | |
| 71 } | |
| 72 } | |
| 73 return filtered; | |
| 74 } | |
| 75 | |
| 76 // TODO (mattsh) hack, remove once we have serializable exceptions | |
| 77 Object _filterException(Object value) { | |
| 78 // Check if value is a serialized exception. | |
| 79 Exception e = RpcException.parse(value); | |
| 80 if (e != null) { | |
| 81 return e; | |
| 82 } else { | |
| 83 return value; | |
| 84 } | |
| 85 } | |
| 86 } | |
| 87 | |
| 88 | |
| 89 | |
| 90 /** | |
| 91 * Base class for all Receivers | |
| 92 * | |
| 93 * RpcReceiver objects have a ReceivePort, where they receive commands (from | |
| 94 * RpcProxy objects) that they interpret and translate into method | |
| 95 * calls on a "target" object. | |
| 96 * | |
| 97 * All RpcReceiver derived classes must implement the [receiveCommand] abstract | |
| 98 * method (where they actually command messages and call | |
| 99 * appropriate methods on the target object). | |
| 100 * | |
| 101 * type parameters: | |
| 102 * T - the type of the target object that this a receiver for | |
| 103 */ | |
| 104 class RpcReceiver<T> { | |
| 105 | |
| 106 // static map of containing all receivers in this isolate. This is used | |
| 107 // to be able to find a receiver and target, given a SendPort. | |
| 108 static Map<SendPort, RpcReceiver> _receivers; | |
| 109 static _register(RpcReceiver receiver) { | |
| 110 if (_receivers == null) { | |
| 111 _receivers = new Map<SendPort, RpcReceiver>(); | |
| 112 } | |
| 113 _receivers[receiver._receivePort.toSendPort()] = receiver; | |
| 114 } | |
| 115 | |
| 116 static void closeAll() { | |
| 117 for (RpcReceiver receiver in _receivers.getValues()) { | |
| 118 receiver._receivePort.close(); | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 // 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.
| |
| 123 final ReceivePort _receivePort; | |
| 124 | |
| 125 // the "target" object that this RpcReceiver will be calling | |
| 126 // to actually do some work. | |
| 127 final T target; | |
| 128 | |
| 129 RpcReceiver(T this.target, ReceivePort this._receivePort) { | |
| 130 // place this receiver in the receiver registry | |
| 131 _register(this); | |
| 132 | |
| 133 // start listening on the receive port for command messages | |
| 134 _receivePort.receive((var message, SendPort replyTo) { | |
| 135 String command = message["command"]; | |
| 136 | |
| 137 // filter incoming arguments (looking for SendPorts | |
| 138 // that we need to translate to RpcReceiver objects) | |
| 139 List args = _filterIncomingArgs(message["args"]); | |
| 140 | |
| 141 // Call the derived RpcReceiver to execute the command | |
| 142 // (if the command throws an exception, then catch the | |
| 143 // exception, serialize it, and send as the reply) | |
| 144 Object reply; | |
| 145 try { | |
| 146 reply = receiveCommand(message["command"], args); | |
| 147 } catch (var e) { | |
| 148 // TODO(mattsh) - would really prefer to catch Object, but currently | |
| 149 // bug http://code.google.com/p/dart/issues/detail?id=469 | |
| 150 reply = RpcException.format(e); | |
| 151 } | |
| 152 | |
| 153 reply = _filterReply(reply); | |
| 154 | |
| 155 // send reply back to the proxy | |
| 156 replyTo.send(reply, null); | |
| 157 }); | |
| 158 } | |
| 159 | |
| 160 /** | |
| 161 * Translate any ReceivePort objects in the arguments to | |
| 162 * the corresponding target object. | |
| 163 */ | |
| 164 static List _filterIncomingArgs(List originalArgs) { | |
| 165 List args = new List(); | |
| 166 var i = 0; | |
| 167 if (originalArgs != null) { | |
| 168 for (var arg in originalArgs) { | |
| 169 if (arg is SendPort) { | |
| 170 if (_receivers[arg] == null) { | |
| 171 throw "can't find receiver for SendPort"; | |
| 172 } | |
| 173 arg = _receivers[arg].target; | |
| 174 if (arg == null) { | |
| 175 throw "receiver is missing target"; | |
| 176 } | |
| 177 } | |
| 178 args.add(arg); | |
| 179 i++; | |
| 180 } | |
| 181 } | |
| 182 return args; | |
| 183 } | |
| 184 | |
| 185 /** | |
| 186 * Walk over the reply that this receiver is about to send | |
| 187 * back, and: | |
| 188 * 1. translate RpcReceiver objects in the reply to the corresponding | |
| 189 * 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.
| |
| 190 * | |
| 191 * 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.
| |
| 192 */ | |
| 193 static _filterReply(Object reply) { | |
| 194 if (reply is RpcReceiver) { | |
| 195 RpcReceiver receiver = reply; | |
| 196 reply = receiver._receivePort.toSendPort(); | |
| 197 } | |
| 198 return reply; | |
| 199 } | |
| 200 | |
| 201 /** | |
| 202 * (implemented by derived classes). | |
| 203 * | |
| 204 * parameters - | |
| 205 * command - String identifying what command to execute | |
| 206 * on the target object | |
| 207 * args - list of arguments to the command (if any arguments | |
| 208 * were ReceivePorts, these have been translated to the | |
| 209 * corresponding target objects, so this List79 will not | |
| 210 * contain any ReceivePorts) | |
| 211 */ | |
| 212 abstract Object receiveCommand(String command, List args); | |
| 213 } | |
| 214 | |
| 215 // 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.
| |
| 216 // we take the message, and prefix with a recognizable string. | |
| 217 class RpcException implements Exception { | |
| 218 | |
| 219 static final String prefix = "RpcException:"; | |
| 220 | |
| 221 final String message; | |
| 222 const RpcException(String this.message); | |
| 223 | |
| 224 String toString() { | |
| 225 return message; | |
| 226 } | |
| 227 | |
| 228 static String format(Exception e) { | |
| 229 return prefix + e.toString(); | |
| 230 } | |
| 231 | |
| 232 static RpcException parse(Object object) { | |
| 233 if (object === null || !(object is String)) { | |
| 234 return null; | |
| 235 } | |
| 236 String s = object; | |
| 237 if (!s.startsWith(prefix)) { | |
| 238 return null; | |
| 239 } | |
| 240 return new RpcException(s.substring(prefix.length, s.length)); | |
| 241 } | |
| 242 } | |
| OLD | NEW |