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

Side by Side Diff: corelib/src/proxy.dart

Issue 9363064: move proxy out into sample/proxy (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: '' Created 8 years, 10 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « corelib/src/corelib_sources.gypi ('k') | frog/lib/corelib.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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> 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 /** Convert RpcProxy objects to SendPorts. */
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 // TODO - need to figure out if/how to wait for proxy's
65 // port to be ready
66 filtered.add(proxy.futurePort.value);
67 } else {
68 filtered.add(arg);
69 }
70 }
71 return filtered;
72 }
73
74 // TODO (mattsh) hack, remove once we have serializable exceptions
75 Object _filterException(Object value) {
76 // Check if value is a serialized exception.
77 Exception e = RpcException.parse(value);
78 if (e != null) {
79 return e;
80 } else {
81 return value;
82 }
83 }
84 }
85
86
87
88 /**
89 * Base class for all Receivers
90 *
91 * RpcReceiver objects have a ReceivePort, where they receive commands (from
92 * RpcProxy objects) that they interpret and translate into method
93 * calls on a "target" object.
94 *
95 * All RpcReceiver derived classes must implement the [receiveCommand] abstract
96 * method (where they actually command messages and call
97 * appropriate methods on the target object).
98 *
99 * type parameters:
100 * T - the type of the target object that this a receiver for
101 */
102 class RpcReceiver<T> {
103
104 // static map of containing all receivers in this isolate. This is used
105 // to be able to find a receiver and target, given a SendPort.
106 static Map<SendPort, RpcReceiver> _receivers;
107 static _register(RpcReceiver receiver) {
108 if (_receivers == null) {
109 _receivers = new Map<SendPort, RpcReceiver>();
110 }
111 _receivers[receiver._receivePort.toSendPort()] = receiver;
112 }
113
114 static void closeAll() {
115 for (RpcReceiver receiver in _receivers.getValues()) {
116 receiver._receivePort.close();
117 }
118 }
119
120 /** the port that this receiver will listen on */
121 final ReceivePort _receivePort;
122
123 /** the "target" object that this RpcReceiver will be calling
124 * to actually do some work.
125 */
126 final T target;
127
128 RpcReceiver(T this.target, ReceivePort this._receivePort) {
129 // place this receiver in the receiver registry
130 _register(this);
131
132 // start listening on the receive port for command messages
133 _receivePort.receive((var message, SendPort replyTo) {
134 String command = message["command"];
135
136 // filter incoming arguments (looking for SendPorts
137 // that we need to translate to RpcReceiver objects)
138 List args = _filterIncomingArgs(message["args"]);
139
140 // Call the derived RpcReceiver to execute the command
141 // (if the command throws an exception, then catch the
142 // exception, serialize it, and send as the reply)
143 Object reply;
144 try {
145 reply = receiveCommand(message["command"], args);
146 } catch (Object e) {
147 reply = RpcException.format(e);
148 }
149
150 reply = _filterReply(reply);
151
152 // send reply back to the proxy
153 replyTo.send(reply, null);
154 });
155 }
156
157 /**
158 * Translate any ReceivePort objects in the arguments to
159 * the corresponding target object.
160 */
161 static List _filterIncomingArgs(List originalArgs) {
162 List args = new List();
163 var i = 0;
164 if (originalArgs != null) {
165 for (var arg in originalArgs) {
166 if (arg is SendPort) {
167 if (_receivers[arg] == null) {
168 throw "can't find receiver for SendPort";
169 }
170 arg = _receivers[arg].target;
171 if (arg == null) {
172 throw "receiver is missing target";
173 }
174 }
175 args.add(arg);
176 i++;
177 }
178 }
179 return args;
180 }
181
182 /**
183 * Walk over the reply that this receiver is about to send
184 * back, and translate RpcReceiver objects in the reply to the
185 * corresponding ReceivePort.
186 */
187 // TODO(mattsh) need to walk deeply
188 static _filterReply(Object reply) {
189 if (reply is RpcReceiver) {
190 RpcReceiver receiver = reply;
191 reply = receiver._receivePort.toSendPort();
192 }
193 return reply;
194 }
195
196 /**
197 * (implemented by derived classes).
198 *
199 * parameters -
200 * command - String identifying what command to execute
201 * on the target object
202 * args - list of arguments to the command (if any arguments
203 * were ReceivePorts, these have been translated to the
204 * corresponding target objects, so this List79 will not
205 * contain any ReceivePorts)
206 */
207 abstract Object receiveCommand(String command, List args);
208 }
209
210 // TODO - need better way to serialize exceptions. For now
211 // we take the message, and prefix with a recognizable string.
212 class RpcException implements Exception {
213
214 static final String prefix = "RpcException:";
215
216 final String message;
217 const RpcException(String this.message);
218
219 String toString() {
220 return message;
221 }
222
223 static String format(Object e) {
224 return prefix + e.toString();
225 }
226
227 static RpcException parse(Object object) {
228 if (object === null || !(object is String)) {
229 return null;
230 }
231 String s = object;
232 if (!s.startsWith(prefix)) {
233 return null;
234 }
235 return new RpcException(s.substring(prefix.length, s.length));
236 }
237 }
OLDNEW
« no previous file with comments | « corelib/src/corelib_sources.gypi ('k') | frog/lib/corelib.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698