| OLD | NEW |
| 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 |
| 8 /// is an error. |
| 7 class ProxyError { | 9 class ProxyError { |
| 8 final String message; | 10 final String message; |
| 9 ProxyError(this.message); | 11 ProxyError(this.message); |
| 10 String toString() => "ProxyError: $message"; | 12 String toString() => "ProxyError: $message"; |
| 11 } | 13 } |
| 12 | 14 |
| 13 abstract class Proxy extends core.MojoEventHandler { | 15 /// Generated ProxyControl classes implement this interface. |
| 16 /// ProxyControl objects are accessible through the [ctrl] field on Proxies. |
| 17 abstract class ProxyControl implements ProxyMessageHandler { |
| 18 String get serviceName; |
| 19 } |
| 20 |
| 21 /// Generated Proxy classes extend this base class. |
| 22 class Proxy { |
| 23 // In general it's probalby better to avoid adding fields and methods to this |
| 24 // class. Names added to this class have to be mangled by Mojo bindings |
| 25 // generation to avoid name conflicts. |
| 26 |
| 27 /// Proxies control the ProxyMessageHandler by way of this [ProxyControl] |
| 28 /// object. |
| 29 final ProxyControl ctrl; |
| 30 |
| 31 Proxy(this.ctrl); |
| 32 |
| 33 /// This is a convenience method that simply forwards to ctrl.close(). |
| 34 /// If a Mojo interface has a method 'close', its name will be mangled to be |
| 35 /// 'close_'. |
| 36 Future close({bool immediate: false}) => ctrl.close(immediate: immediate); |
| 37 |
| 38 /// This is a convenience method that simply forwards to |
| 39 /// ctrl.responseOrError(). If a Mojo interface has a method |
| 40 /// 'responseOrError', its name will be mangled to be 'responseOrError_'. |
| 41 Future responseOrError(Future f) => ctrl.responseOrError(f); |
| 42 } |
| 43 |
| 44 /// Generated Proxy classes have a factory Proxy.connectToService which takes |
| 45 /// a ServiceConnector, a url, and optionally a service name and returns a |
| 46 /// bound Proxy. For example, every class extending the Application base class |
| 47 /// in package:mojo/application.dart inherits and implementation of the |
| 48 /// ServiceConnector interface. |
| 49 abstract class ServiceConnector { |
| 50 /// Connects [proxy] to the service called [serviceName] that lives at [url]. |
| 51 void connectToService(String url, Proxy proxy, [String serviceName]); |
| 52 } |
| 53 |
| 54 class ProxyMessageHandler extends core.MojoEventHandler { |
| 14 HashMap<int, Completer> _completerMap = new HashMap<int, Completer>(); | 55 HashMap<int, Completer> _completerMap = new HashMap<int, Completer>(); |
| 15 Completer _errorCompleter = new Completer(); | 56 Completer _errorCompleter = new Completer(); |
| 16 Set<Completer> _errorCompleters; | 57 Set<Completer> _errorCompleters; |
| 17 int _nextId = 0; | 58 int _nextId = 0; |
| 18 int _version = 0; | 59 int _version = 0; |
| 19 int _pendingCount = 0; | 60 int _pendingCount = 0; |
| 20 | 61 |
| 21 Proxy.fromEndpoint(core.MojoMessagePipeEndpoint endpoint) | 62 ProxyMessageHandler.fromEndpoint(core.MojoMessagePipeEndpoint endpoint) |
| 22 : super.fromEndpoint(endpoint); | 63 : super.fromEndpoint(endpoint); |
| 23 | 64 |
| 24 Proxy.fromHandle(core.MojoHandle handle) : super.fromHandle(handle); | 65 ProxyMessageHandler.fromHandle(core.MojoHandle handle) |
| 66 : super.fromHandle(handle); |
| 25 | 67 |
| 26 Proxy.unbound() : super.unbound(); | 68 ProxyMessageHandler.unbound() : super.unbound(); |
| 27 | 69 |
| 28 void handleResponse(ServiceMessage reader); | 70 /// The function that handles responses to sent proxy message. It should be |
| 71 /// implemented by the generated ProxyControl classes that extend |
| 72 /// [ProxyMessageHandler]. |
| 73 void handleResponse(ServiceMessage msg) {} |
| 29 | 74 |
| 30 /// If there is an error in using this proxy, this future completes with | 75 /// If there is an error in using this proxy, this future completes with |
| 31 /// a ProxyError. | 76 /// a ProxyError. |
| 32 Future get errorFuture => _errorCompleter.future; | 77 Future get errorFuture => _errorCompleter.future; |
| 33 | 78 |
| 34 /// Version of this interface that the remote side supports. Updated when a | 79 /// Version of this interface that the remote side supports. Updated when a |
| 35 /// call to [queryVersion] or [requireVersion] is made. | 80 /// call to [queryVersion] or [requireVersion] is made. |
| 36 int get version => _version; | 81 int get version => _version; |
| 37 | 82 |
| 38 /// Returns a service description, which exposes the mojom type information | 83 /// Returns a service description, which exposes the mojom type information |
| 39 /// of the service being proxied. | 84 /// of the service being proxied. |
| 40 /// Note: The description is null or incomplete if type info is unavailable. | 85 /// Note: The description is null or incomplete if type info is unavailable. |
| 41 service_describer.ServiceDescription get description => null; | 86 service_describer.ServiceDescription get description => null; |
| 42 | 87 |
| 88 @override |
| 43 void handleRead() { | 89 void handleRead() { |
| 44 var result = endpoint.queryAndRead(); | 90 var result = endpoint.queryAndRead(); |
| 45 if ((result.data == null) || (result.dataLength == 0)) { | 91 if ((result.data == null) || (result.dataLength == 0)) { |
| 46 proxyError("Read from message pipe endpoint failed"); | 92 proxyError("Read from message pipe endpoint failed"); |
| 47 return; | 93 return; |
| 48 } | 94 } |
| 49 try { | 95 try { |
| 50 var message = new ServiceMessage.fromMessage(new Message(result.data, | 96 var message = new ServiceMessage.fromMessage(new Message(result.data, |
| 51 result.handles, result.dataLength, result.handlesLength)); | 97 result.handles, result.dataLength, result.handlesLength)); |
| 52 _pendingCount--; | 98 _pendingCount--; |
| 53 if (ControlMessageHandler.isControlMessage(message)) { | 99 if (ControlMessageHandler.isControlMessage(message)) { |
| 54 _handleControlMessageResponse(message); | 100 _handleControlMessageResponse(message); |
| 55 return; | 101 return; |
| 56 } | 102 } |
| 57 handleResponse(message); | 103 handleResponse(message); |
| 58 } on MojoCodecError catch (e) { | 104 } on MojoCodecError catch (e) { |
| 59 proxyError(e.toString()); | 105 proxyError(e.toString()); |
| 60 close(immediate: true); | 106 close(immediate: true); |
| 61 } | 107 } |
| 62 } | 108 } |
| 63 | 109 |
| 110 @override |
| 64 void handleWrite() { | 111 void handleWrite() { |
| 65 proxyError("Unexpected writable signal"); | 112 proxyError("Unexpected writable signal"); |
| 66 } | 113 } |
| 67 | 114 |
| 68 @override | 115 @override |
| 69 Future close({bool immediate: false}) { | 116 Future close({bool immediate: false}) { |
| 70 // Drop the completers for outstanding calls. The Futures will never | 117 // Drop the completers for outstanding calls. The Futures will never |
| 71 // complete. | 118 // complete. |
| 72 _completerMap.clear(); | 119 _completerMap.clear(); |
| 73 | 120 |
| 74 // Signal to any pending calls that the Proxy is closed. | 121 // Signal to any pending calls that the ProxyMessageHandler is closed. |
| 75 if (_pendingCount > 0) { | 122 if (_pendingCount > 0) { |
| 76 proxyError("The Proxy is closed."); | 123 proxyError("The ProxyMessageHandler is closed."); |
| 77 } | 124 } |
| 78 | 125 |
| 79 return super.close(immediate: immediate); | 126 return super.close(immediate: immediate); |
| 80 } | 127 } |
| 81 | 128 |
| 82 void sendMessage(Struct message, int name) { | 129 void sendMessage(Struct message, int name) { |
| 83 if (!isBound) { | 130 if (!isBound) { |
| 84 proxyError("The Proxy is closed."); | 131 proxyError("The ProxyMessageHandler is closed."); |
| 85 return; | 132 return; |
| 86 } | 133 } |
| 87 if (!isOpen) { | 134 if (!isOpen) { |
| 88 beginHandlingEvents(); | 135 beginHandlingEvents(); |
| 89 } | 136 } |
| 90 var header = new MessageHeader(name); | 137 var header = new MessageHeader(name); |
| 91 var serviceMessage = message.serializeWithHeader(header); | 138 var serviceMessage = message.serializeWithHeader(header); |
| 92 endpoint.write(serviceMessage.buffer, serviceMessage.buffer.lengthInBytes, | 139 endpoint.write(serviceMessage.buffer, serviceMessage.buffer.lengthInBytes, |
| 93 serviceMessage.handles); | 140 serviceMessage.handles); |
| 94 if (endpoint.status != core.MojoResult.kOk) { | 141 if (endpoint.status != core.MojoResult.kOk) { |
| 95 proxyError("Write to message pipe endpoint failed."); | 142 proxyError("Write to message pipe endpoint failed."); |
| 96 } | 143 } |
| 97 } | 144 } |
| 98 | 145 |
| 99 Future sendMessageWithRequestId(Struct message, int name, int id, int flags) { | 146 Future sendMessageWithRequestId(Struct message, int name, int id, int flags) { |
| 100 var completer = new Completer(); | 147 var completer = new Completer(); |
| 101 if (!isBound) { | 148 if (!isBound) { |
| 102 proxyError("The Proxy is closed."); | 149 proxyError("The ProxyMessageHandler is closed."); |
| 103 return completer.future; | 150 return completer.future; |
| 104 } | 151 } |
| 105 if (!isOpen) { | 152 if (!isOpen) { |
| 106 beginHandlingEvents(); | 153 beginHandlingEvents(); |
| 107 } | 154 } |
| 108 if (id == -1) { | 155 if (id == -1) { |
| 109 id = _nextId++; | 156 id = _nextId++; |
| 110 } | 157 } |
| 111 | 158 |
| 112 var header = new MessageHeader.withRequestId(name, flags, id); | 159 var header = new MessageHeader.withRequestId(name, flags, id); |
| 113 var serviceMessage = message.serializeWithHeader(header); | 160 var serviceMessage = message.serializeWithHeader(header); |
| 114 endpoint.write(serviceMessage.buffer, serviceMessage.buffer.lengthInBytes, | 161 endpoint.write(serviceMessage.buffer, serviceMessage.buffer.lengthInBytes, |
| 115 serviceMessage.handles); | 162 serviceMessage.handles); |
| 116 | 163 |
| 117 if (endpoint.status == core.MojoResult.kOk) { | 164 if (endpoint.status == core.MojoResult.kOk) { |
| 118 _completerMap[id] = completer; | 165 _completerMap[id] = completer; |
| 119 _pendingCount++; | 166 _pendingCount++; |
| 120 } else { | 167 } else { |
| 121 proxyError("Write to message pipe endpoint failed: ${endpoint}"); | 168 proxyError("Write to message pipe endpoint failed: ${endpoint}"); |
| 122 } | 169 } |
| 123 return completer.future; | 170 return completer.future; |
| 124 } | 171 } |
| 125 | 172 |
| 126 // Need a getter for this for access in subclasses. | 173 // Need a getter for this for access in subclasses. |
| 127 HashMap<int, Completer> get completerMap => _completerMap; | 174 HashMap<int, Completer> get completerMap => _completerMap; |
| 128 | 175 |
| 129 String toString() { | 176 String toString() { |
| 130 var superString = super.toString(); | 177 var superString = super.toString(); |
| 131 return "Proxy(${superString})"; | 178 return "ProxyMessageHandler(${superString})"; |
| 132 } | 179 } |
| 133 | 180 |
| 134 /// Queries the max version that the remote side supports. | 181 /// Queries the max version that the remote side supports. |
| 135 /// Updates [version]. | 182 /// Updates [version]. |
| 136 Future<int> queryVersion() async { | 183 Future<int> queryVersion() async { |
| 137 var params = new icm.RunMessageParams(); | 184 var params = new icm.RunMessageParams(); |
| 138 params.reserved0 = 16; | 185 params.reserved0 = 16; |
| 139 params.reserved1 = 0; | 186 params.reserved1 = 0; |
| 140 params.queryVersion = new icm.QueryVersion(); | 187 params.queryVersion = new icm.QueryVersion(); |
| 141 var response = await sendMessageWithRequestId( | 188 var response = await sendMessageWithRequestId( |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 179 } | 226 } |
| 180 | 227 |
| 181 /// [responseOrError] returns a [Future] that completes to whatever [f] | 228 /// [responseOrError] returns a [Future] that completes to whatever [f] |
| 182 /// completes to unless [errorFuture] completes first. When [errorFuture] | 229 /// completes to unless [errorFuture] completes first. When [errorFuture] |
| 183 /// completes first, the [Future] returned by [responseOrError] completes with | 230 /// completes first, the [Future] returned by [responseOrError] completes with |
| 184 /// an error using the object that [errorFuture] completed with. | 231 /// an error using the object that [errorFuture] completed with. |
| 185 /// | 232 /// |
| 186 /// Example usage: | 233 /// Example usage: |
| 187 /// | 234 /// |
| 188 /// try { | 235 /// try { |
| 189 /// result = await MyProxy.responseOrError(MyProxy.ptr.call(a,b,c)); | 236 /// result = await myProxy.responseOrError(myProxy.call(a,b,c)); |
| 190 /// } catch (e) { | 237 /// } catch (e) { |
| 191 /// ... | 238 /// ... |
| 192 /// } | 239 /// } |
| 193 Future responseOrError(Future f) { | 240 Future responseOrError(Future f) { |
| 194 assert(f != null); | 241 assert(f != null); |
| 195 if (_errorCompleters == null) { | 242 if (_errorCompleters == null) { |
| 196 _errorCompleters = new Set<Completer>(); | 243 _errorCompleters = new Set<Completer>(); |
| 197 errorFuture.then((e) { | 244 errorFuture.then((e) { |
| 198 for (var completer in _errorCompleters) { | 245 for (var completer in _errorCompleters) { |
| 199 assert(!completer.isCompleted); | 246 assert(!completer.isCompleted); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 234 return; | 281 return; |
| 235 } | 282 } |
| 236 completerMap.remove(message.header.requestId); | 283 completerMap.remove(message.header.requestId); |
| 237 if (c.isCompleted) { | 284 if (c.isCompleted) { |
| 238 proxyError("Control message response completer already completed"); | 285 proxyError("Control message response completer already completed"); |
| 239 return; | 286 return; |
| 240 } | 287 } |
| 241 c.complete(response); | 288 c.complete(response); |
| 242 } | 289 } |
| 243 } | 290 } |
| 244 | |
| 245 /// Generated Proxy classes implement this interface. | |
| 246 abstract class ProxyBase { | |
| 247 final Proxy impl = null; | |
| 248 final String serviceName = null; | |
| 249 Object get ptr; | |
| 250 } | |
| 251 | |
| 252 /// Generated Proxy classes have a factory Proxy.connectToService which takes | |
| 253 /// a ServiceConnector, a url, and optionally a service name and returns a | |
| 254 /// bound Proxy. For example, every class extending the Application base class | |
| 255 /// in package:mojo/application.dart inherits and implementation of the | |
| 256 /// ServiceConnector interface. | |
| 257 abstract class ServiceConnector { | |
| 258 /// Connects [proxy] to the service called [serviceName] that lives at [url]. | |
| 259 void connectToService(String url, ProxyBase proxy, [String serviceName]); | |
| 260 } | |
| OLD | NEW |