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

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

Powered by Google App Engine
This is Rietveld 408576698