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

Side by Side Diff: mojo/dart/packages/mojo/lib/src/proxy.dart

Issue 2006093002: Dart: Futures -> Callbacks. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Merge Created 4 years, 6 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
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 part of bindings; 5 part of bindings;
6 6
7 /// The object that [ProxyMessageHandler.errorFuture] completes with when there 7 /// The object that [ProxyMessageHandler.errorFuture] completes with when there
8 /// is an error. 8 /// is an error.
9 class ProxyError { 9 class ProxyError {
10 final String message; 10 final String message;
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 /// bound Proxy. For example, every class extending the Application base class 62 /// bound Proxy. For example, every class extending the Application base class
63 /// in package:mojo/application.dart inherits an implementation of the 63 /// in package:mojo/application.dart inherits an implementation of the
64 /// ServiceConnector interface. 64 /// ServiceConnector interface.
65 abstract class ServiceConnector { 65 abstract class ServiceConnector {
66 /// Connects [proxy] to the service called [serviceName] that lives at [url]. 66 /// Connects [proxy] to the service called [serviceName] that lives at [url].
67 void connectToService(String url, Proxy proxy, [String serviceName]); 67 void connectToService(String url, Proxy proxy, [String serviceName]);
68 } 68 }
69 69
70 abstract class ProxyMessageHandler extends core.MojoEventHandler 70 abstract class ProxyMessageHandler extends core.MojoEventHandler
71 implements MojoInterfaceControl { 71 implements MojoInterfaceControl {
72 HashMap<int, Completer> _completerMap = new HashMap<int, Completer>(); 72 HashMap<int, Function> _callbackMap = new HashMap<int, Function>();
73 Completer _errorCompleter = new Completer(); 73 Completer _errorCompleter = new Completer();
74 Set<Completer> _errorCompleters; 74 Set<Completer> _errorCompleters;
75 int _nextId = 0; 75 int _nextId = 0;
76 int _version = 0; 76 int _version = 0;
77 int _pendingCount = 0; 77 int _pendingCount = 0;
78 78
79 ProxyMessageHandler.fromEndpoint(core.MojoMessagePipeEndpoint endpoint) 79 ProxyMessageHandler.fromEndpoint(core.MojoMessagePipeEndpoint endpoint)
80 : super.fromEndpoint(endpoint); 80 : super.fromEndpoint(endpoint);
81 81
82 ProxyMessageHandler.fromHandle(core.MojoHandle handle) 82 ProxyMessageHandler.fromHandle(core.MojoHandle handle)
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 } 124 }
125 } 125 }
126 126
127 @override 127 @override
128 void handleWrite() { 128 void handleWrite() {
129 proxyError("Unexpected writable signal"); 129 proxyError("Unexpected writable signal");
130 } 130 }
131 131
132 @override 132 @override
133 Future close({bool immediate: false}) { 133 Future close({bool immediate: false}) {
134 // Drop the completers for outstanding calls. The Futures will never 134 // Drop the callbacks for outstanding calls. They will never be called.
135 // complete. 135 _callbackMap.clear();
136 _completerMap.clear();
137 136
138 // Signal to any pending calls that the ProxyMessageHandler is closed. 137 // Signal to any pending calls that the ProxyMessageHandler is closed.
139 if (_pendingCount > 0) { 138 if (_pendingCount > 0) {
140 proxyError("The ProxyMessageHandler is closed."); 139 proxyError("The ProxyMessageHandler is closed.");
141 } 140 }
142 141
143 return super.close(immediate: immediate); 142 return super.close(immediate: immediate);
144 } 143 }
145 144
146 void sendMessage(Struct message, int name) { 145 void sendMessage(Struct message, int name) {
147 if (!isBound) { 146 if (!isBound) {
148 proxyError("The ProxyMessageHandler is closed."); 147 proxyError("The ProxyMessageHandler is closed.");
149 return; 148 return;
150 } 149 }
151 if (!isOpen) { 150 if (!isOpen) {
152 beginHandlingEvents(); 151 beginHandlingEvents();
153 } 152 }
154 var header = new MessageHeader(name); 153 var header = new MessageHeader(name);
155 var serviceMessage = message.serializeWithHeader(header); 154 var serviceMessage = message.serializeWithHeader(header);
156 endpoint.write(serviceMessage.buffer, serviceMessage.buffer.lengthInBytes, 155 endpoint.write(serviceMessage.buffer, serviceMessage.buffer.lengthInBytes,
157 serviceMessage.handles); 156 serviceMessage.handles);
158 if (endpoint.status != core.MojoResult.kOk) { 157 if (endpoint.status != core.MojoResult.kOk) {
159 proxyError("Write to message pipe endpoint failed."); 158 proxyError("Write to message pipe endpoint failed.");
160 } 159 }
161 } 160 }
162 161
163 Future sendMessageWithRequestId(Struct message, int name, int id, int flags) { 162 void sendMessageWithRequestId(
164 var completer = new Completer(); 163 Struct message, int name, int id, int flags, Function callback) {
165 if (!isBound) { 164 if (!isBound) {
166 proxyError("The ProxyMessageHandler is closed."); 165 proxyError("The Proxy is closed.");
167 return completer.future; 166 return;
168 } 167 }
169 if (!isOpen) { 168 if (!isOpen) {
170 beginHandlingEvents(); 169 beginHandlingEvents();
171 } 170 }
172 if (id == -1) { 171 if (id == -1) {
173 id = _nextId++; 172 id = _nextId++;
174 } 173 }
175 174
176 var header = new MessageHeader.withRequestId(name, flags, id); 175 var header = new MessageHeader.withRequestId(name, flags, id);
177 var serviceMessage = message.serializeWithHeader(header); 176 var serviceMessage = message.serializeWithHeader(header);
178 endpoint.write(serviceMessage.buffer, serviceMessage.buffer.lengthInBytes, 177 endpoint.write(serviceMessage.buffer, serviceMessage.buffer.lengthInBytes,
179 serviceMessage.handles); 178 serviceMessage.handles);
180 179
181 if (endpoint.status == core.MojoResult.kOk) { 180 if (endpoint.status == core.MojoResult.kOk) {
182 _completerMap[id] = completer; 181 _callbackMap[id] = callback;
183 _pendingCount++; 182 _pendingCount++;
184 } else { 183 } else {
185 proxyError("Write to message pipe endpoint failed: ${endpoint}"); 184 proxyError("Write to message pipe endpoint failed: ${endpoint}");
186 } 185 }
187 return completer.future;
188 } 186 }
189 187
190 // Need a getter for this for access in subclasses. 188 // Need a getter for this for access in subclasses.
191 HashMap<int, Completer> get completerMap => _completerMap; 189 HashMap<int, Function> get callbackMap => _callbackMap;
192 190
193 @override 191 @override
194 String toString() { 192 String toString() {
195 var superString = super.toString(); 193 var superString = super.toString();
196 return "ProxyMessageHandler(${superString})"; 194 return "ProxyMessageHandler(${superString})";
197 } 195 }
198 196
199 /// Queries the max version that the remote side supports. 197 /// Queries the max version that the remote side supports.
200 /// Updates [version]. 198 /// Updates [version].
201 Future<int> queryVersion() async { 199 Future<int> queryVersion() {
200 Completer<int> completer = new Completer<int>();
202 var params = new icm.RunMessageParams(); 201 var params = new icm.RunMessageParams();
203 params.reserved0 = 16; 202 params.reserved0 = 16;
204 params.reserved1 = 0; 203 params.reserved1 = 0;
205 params.queryVersion = new icm.QueryVersion(); 204 params.queryVersion = new icm.QueryVersion();
206 var response = await sendMessageWithRequestId( 205 sendMessageWithRequestId(
207 params, icm.kRunMessageId, -1, MessageHeader.kMessageExpectsResponse); 206 params, icm.kRunMessageId, -1, MessageHeader.kMessageExpectsResponse,
208 _version = response.queryVersionResult.version; 207 (r0, r1, queryResult) {
209 return _version; 208 _version = queryResult.version;
209 completer.complete(_version);
210 });
211 return completer.future;
210 } 212 }
211 213
212 /// If the remote side doesn't support the [requiredVersion], it will close 214 /// If the remote side doesn't support the [requiredVersion], it will close
213 /// its end of the message pipe asynchronously. This does nothing if it's 215 /// its end of the message pipe asynchronously. This does nothing if it's
214 /// already known that the remote side supports [requiredVersion]. 216 /// already known that the remote side supports [requiredVersion].
215 /// Updates [version]. 217 /// Updates [version].
216 void requireVersion(int requiredVersion) { 218 void requireVersion(int requiredVersion) {
217 if (requiredVersion <= _version) { 219 if (requiredVersion <= _version) {
218 // Already supported. 220 // Already supported.
219 return; 221 return;
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
280 return callCompleter.future; 282 return callCompleter.future;
281 } 283 }
282 284
283 _handleControlMessageResponse(ServiceMessage message) { 285 _handleControlMessageResponse(ServiceMessage message) {
284 // We only expect to see Run messages. 286 // We only expect to see Run messages.
285 if (message.header.type != icm.kRunMessageId) { 287 if (message.header.type != icm.kRunMessageId) {
286 proxyError("Unexpected header type in control message response: " 288 proxyError("Unexpected header type in control message response: "
287 "${message.header.type}"); 289 "${message.header.type}");
288 return; 290 return;
289 } 291 }
290
291 var response = icm.RunResponseMessageParams.deserialize(message.payload); 292 var response = icm.RunResponseMessageParams.deserialize(message.payload);
292 if (!message.header.hasRequestId) { 293 if (!message.header.hasRequestId) {
293 proxyError("Expected a message with a valid request Id."); 294 proxyError("Expected a message with a valid request Id.");
294 return; 295 return;
295 } 296 }
296 Completer c = completerMap[message.header.requestId]; 297 Function callback = callbackMap[message.header.requestId];
297 if (c == null) { 298 if (callback == null) {
298 proxyError("Message had unknown request Id: ${message.header.requestId}"); 299 proxyError("Message had unknown request Id: ${message.header.requestId}");
299 return; 300 return;
300 } 301 }
301 completerMap.remove(message.header.requestId); 302 callbackMap.remove(message.header.requestId);
302 if (c.isCompleted) { 303 callback(
303 proxyError("Control message response completer already completed"); 304 response.reserved0, response.reserved1, response.queryVersionResult);
304 return; 305 return;
305 }
306 c.complete(response);
307 } 306 }
308 } 307 }
308
309 // A class that acts like a function, but which completes a completer with the
310 // the result of the function rather than returning the result. E.g.:
311 //
312 // Completer c = new Completer();
313 // var completerator = new Completerator._(c, f);
314 // completerator(a, b);
315 // await c.future;
316 //
317 // This completes the future c with the result of passing a and b to f.
318 //
319 // More usefully for Mojo, e.g.:
320 // await _Completerator.completerate(
321 // proxy.method, argList, MethodResponseParams#init);
322 class _Completerator implements Function {
323 final Completer _c;
324 final Function _toComplete;
325
326 _Completerator._(this._c, this._toComplete);
327
328 static Future completerate(Function f, List args, Function ctor) {
329 Completer c = new Completer();
330 var newArgs = new List.from(args);
331 newArgs.add(new _Completerator._(c, ctor));
332 Function.apply(f, newArgs);
333 return c.future;
334 }
335
336 // Work-around to avoid checked-mode only having grudging support for
337 // Function implemented with noSuchMethod. See:
338 // https://github.com/dart-lang/sdk/issues/26528
339 dynamic call([
340 dynamic a1, dynamic a2, dynamic a3, dynamic a4, dynamic a5,
341 dynamic a6, dynamic a7, dynamic a8, dynamic a9, dynamic a10,
342 dynamic a11, dynamic a12, dynamic a13, dynamic a14, dynamic a15,
343 dynamic a16, dynamic a17, dynamic a18, dynamic a19, dynamic a20]);
344
345 @override
346 dynamic noSuchMethod(Invocation invocation) =>
347 (invocation.memberName == #call)
348 ? _c.complete(Function.apply(_toComplete, invocation.positionalArguments))
349 : super.noSuchMethod(invocation);
350 }
351
352 /// Base class for Proxy class Futurizing wrappers. It turns callback-based
353 /// methods on the Proxy into Future based methods in derived classes. E.g.:
354 ///
355 /// class FuturizedHostResolverProxy extends FuturizedProxy<HostResolverProxy> {
356 /// Map<Symbol, Function> _mojoMethods;
357 ///
358 /// FuturizedHostResolverProxy(HostResolverProxy proxy) : super(proxy) {
359 /// _mojoMethods = <Symbol, Function>{
360 /// #getHostAddresses: proxy.getHostAddresses,
361 /// };
362 /// }
363 /// Map<Symbol, Function> get mojoMethods => _mojoMethods;
364 ///
365 /// FuturizedHostResolverProxy.unbound() :
366 /// this(new HostResolverProxy.unbound());
367 ///
368 /// static final Map<Symbol, Function> _mojoResponses = {
369 /// #getHostAddresses: new HostResolverGetHostAddressesResponseParams#init,
370 /// };
371 /// Map<Symbol, Function> get mojoResponses => _mojoResponses;
372 /// }
373 ///
374 /// Then:
375 ///
376 /// HostResolveProxy proxy = ...
377 /// var futurizedProxy = new FuturizedHostResolverProxy(proxy);
378 /// var response = await futurizedProxy.getHostAddresses(host, family);
379 /// // etc.
380 ///
381 /// Warning 1: The list of methods and return object constructors in
382 /// FuturizedHostResolverProxy has to be kept up-do-date by hand with changes
383 /// to the Mojo interface.
384 ///
385 /// Warning 2: The recommended API to use is the generated callback-based API.
386 /// This wrapper class is exposed only for convenience during development,
387 /// and has no guarantee of optimal performance.
388 abstract class FuturizedProxy<T extends Proxy> {
389 final T _proxy;
390 Map<Symbol, Function> get mojoMethods;
391 Map<Symbol, Function> get mojoResponses;
392
393 FuturizedProxy(T this._proxy);
394
395 T get proxy => _proxy;
396 Future responseOrError(Future f) => _proxy.responseOrError(f);
397 Future close({immediate: false}) => _proxy.close(immediate: immediate);
398
399 @override
400 dynamic noSuchMethod(Invocation invocation) =>
401 mojoMethods.containsKey(invocation.memberName)
402 ? _Completerator.completerate(
403 mojoMethods[invocation.memberName],
404 invocation.positionalArguments,
405 mojoResponses[invocation.memberName])
406 : super.noSuchMethod(invocation);
407 }
OLDNEW
« no previous file with comments | « mojo/dart/packages/mojo/lib/src/control_message.dart ('k') | mojo/dart/packages/mojo/lib/src/stub.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698