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 |