OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * Utility functions for setting up ports and sending data. | 6 * Utility functions for setting up ports and sending data. |
7 * | 7 * |
8 * This library contains a number of functions that handle the | 8 * This library contains a number of functions that handle the |
9 * boiler-plate of setting up a receive port and receiving a | 9 * boiler-plate of setting up a receive port and receiving a |
10 * single message on the port. | 10 * single message on the port. |
(...skipping 28 matching lines...) Expand all Loading... | |
39 * | 39 * |
40 * Returns the `SendPort` expecting the single message. | 40 * Returns the `SendPort` expecting the single message. |
41 * | 41 * |
42 * Equivalent to: | 42 * Equivalent to: |
43 * | 43 * |
44 * (new ReceivePort() | 44 * (new ReceivePort() |
45 * ..first.timeout(duration, () => timeoutValue).then(callback)) | 45 * ..first.timeout(duration, () => timeoutValue).then(callback)) |
46 * .sendPort | 46 * .sendPort |
47 */ | 47 */ |
48 SendPort singleCallbackPort(void callback(response), | 48 SendPort singleCallbackPort(void callback(response), |
49 {Duration timeout, | 49 {Duration timeout, var timeoutValue}) { |
Lasse Reichstein Nielsen
2015/02/26 10:59:14
Indent '{' to after '('.
| |
50 var timeoutValue}) { | |
51 RawReceivePort responsePort = new RawReceivePort(); | 50 RawReceivePort responsePort = new RawReceivePort(); |
52 Zone zone = Zone.current; | 51 Zone zone = Zone.current; |
53 callback = zone.registerUnaryCallback(callback); | 52 callback = zone.registerUnaryCallback(callback); |
54 var timer; | 53 var timer; |
55 responsePort.handler = (response) { | 54 responsePort.handler = (response) { |
56 responsePort.close(); | 55 responsePort.close(); |
57 if (timer != null) timer.cancel(); | 56 if (timer != null) timer.cancel(); |
58 zone.runUnary(callback, response); | 57 zone.runUnary(callback, response); |
59 }; | 58 }; |
60 if (timeout != null) { | 59 if (timeout != null) { |
(...skipping 26 matching lines...) Expand all Loading... | |
87 * as long as the initial message is received in time. | 86 * as long as the initial message is received in time. |
88 * If `onTimeout` is omitted, it defaults to completing the `completer` with | 87 * If `onTimeout` is omitted, it defaults to completing the `completer` with |
89 * a [TimeoutException]. | 88 * a [TimeoutException]. |
90 * | 89 * |
91 * The [completer] may be a synchronous completer. It is only | 90 * The [completer] may be a synchronous completer. It is only |
92 * completed in response to another event, either a port message or a timer. | 91 * completed in response to another event, either a port message or a timer. |
93 * | 92 * |
94 * Returns the `SendPort` expecting the single message. | 93 * Returns the `SendPort` expecting the single message. |
95 */ | 94 */ |
96 SendPort singleCompletePort(Completer completer, | 95 SendPort singleCompletePort(Completer completer, |
97 {callback(message), | 96 {callback(message), Duration timeout, onTimeout()}) { |
Lasse Reichstein Nielsen
2015/02/26 10:59:14
Indent '{' to after '(' or put the completer on a
| |
98 Duration timeout, | |
99 onTimeout()}) { | |
100 if (callback == null && timeout == null) { | 97 if (callback == null && timeout == null) { |
101 return singleCallbackPort(completer.complete); | 98 return singleCallbackPort(completer.complete); |
102 } | 99 } |
103 RawReceivePort responsePort = new RawReceivePort(); | 100 RawReceivePort responsePort = new RawReceivePort(); |
104 var timer; | 101 var timer; |
105 if (callback == null) { | 102 if (callback == null) { |
106 responsePort.handler = (response) { | 103 responsePort.handler = (response) { |
107 responsePort.close(); | 104 responsePort.close(); |
108 if (timer != null) timer.cancel(); | 105 if (timer != null) timer.cancel(); |
109 completer.complete(response); | 106 completer.complete(response); |
110 }; | 107 }; |
111 } else { | 108 } else { |
112 Zone zone = Zone.current; | 109 Zone zone = Zone.current; |
113 Function action = zone.registerUnaryCallback((response) { | 110 Function action = zone.registerUnaryCallback((response) { |
114 completer.complete(new Future.sync(() => callback(response))); | 111 completer.complete(new Future.sync(() => callback(response))); |
115 }); | 112 }); |
116 responsePort.handler = (response) { | 113 responsePort.handler = (response) { |
117 responsePort.close(); | 114 responsePort.close(); |
118 if (timer != null) timer.cancel(); | 115 if (timer != null) timer.cancel(); |
119 zone.runUnary(action, response); | 116 zone.runUnary(action, response); |
120 }; | 117 }; |
121 } | 118 } |
122 if (timeout != null) { | 119 if (timeout != null) { |
123 timer = new Timer(timeout, () { | 120 timer = new Timer(timeout, () { |
124 responsePort.close(); | 121 responsePort.close(); |
125 if (onTimeout != null) { | 122 if (onTimeout != null) { |
126 completer.complete(new Future.sync(onTimeout)); | 123 completer.complete(new Future.sync(onTimeout)); |
127 } else { | 124 } else { |
128 completer.completeError(new TimeoutException("Future not completed", | 125 completer.completeError( |
129 timeout)); | 126 new TimeoutException("Future not completed", timeout)); |
130 } | 127 } |
131 }); | 128 }); |
132 } | 129 } |
133 return responsePort.sendPort; | 130 return responsePort.sendPort; |
134 } | 131 } |
135 | 132 |
136 /** | 133 /** |
137 * Creates a [Future], and a [SendPort] that can be used to complete that | 134 * Creates a [Future], and a [SendPort] that can be used to complete that |
138 * future. | 135 * future. |
139 * | 136 * |
140 * Calls [action] with the response `SendPort`, then waits for someone | 137 * Calls [action] with the response `SendPort`, then waits for someone |
141 * to send a value on that port | 138 * to send a value on that port |
142 * The returned `Future` is completed with the value sent on the port. | 139 * The returned `Future` is completed with the value sent on the port. |
143 * | 140 * |
144 * If [action] throws, which it shouldn't, | 141 * If [action] throws, which it shouldn't, |
145 * the returned future is completed with that error. | 142 * the returned future is completed with that error. |
146 * Any return value of `action` is ignored, and if it is asynchronous, | 143 * Any return value of `action` is ignored, and if it is asynchronous, |
147 * it should handle its own errors. | 144 * it should handle its own errors. |
148 * | 145 * |
149 * If [timeout] is supplied, it is used as a limit on how | 146 * If [timeout] is supplied, it is used as a limit on how |
150 * long it can take before the message is received. If a | 147 * long it can take before the message is received. If a |
151 * message isn't received in time, the [timeoutValue] used | 148 * message isn't received in time, the [timeoutValue] used |
152 * as the returned future's value instead. | 149 * as the returned future's value instead. |
153 * | 150 * |
154 * If you want a timeout on the returned future, it's recommended to | 151 * If you want a timeout on the returned future, it's recommended to |
155 * use the [timeout] parameter, and not [Future.timeout] on the result. | 152 * use the [timeout] parameter, and not [Future.timeout] on the result. |
156 * The `Future` method won't be able to close the underlying [ReceivePort]. | 153 * The `Future` method won't be able to close the underlying [ReceivePort]. |
157 */ | 154 */ |
158 Future singleResponseFuture(void action(SendPort responsePort), | 155 Future singleResponseFuture(void action(SendPort responsePort), |
159 {Duration timeout, | 156 {Duration timeout, var timeoutValue}) { |
Lasse Reichstein Nielsen
2015/02/26 10:59:14
Indentation again.
| |
160 var timeoutValue}) { | |
161 Completer completer = new Completer.sync(); | 157 Completer completer = new Completer.sync(); |
162 RawReceivePort responsePort = new RawReceivePort(); | 158 RawReceivePort responsePort = new RawReceivePort(); |
163 Timer timer; | 159 Timer timer; |
164 Zone zone = Zone.current; | 160 Zone zone = Zone.current; |
165 responsePort.handler = (v) { | 161 responsePort.handler = (v) { |
166 responsePort.close(); | 162 responsePort.close(); |
167 if (timer != null) timer.cancel(); | 163 if (timer != null) timer.cancel(); |
168 zone.run(() { | 164 zone.run(() { |
169 completer.complete(v); | 165 completer.complete(v); |
170 }); | 166 }); |
171 }; | 167 }; |
172 if (timeout != null) { | 168 if (timeout != null) { |
173 timer = new Timer(timeout, () { | 169 timer = new Timer(timeout, () { |
174 responsePort.close(); | 170 responsePort.close(); |
175 completer.complete(timeoutValue); | 171 completer.complete(timeoutValue); |
176 }); | 172 }); |
177 } | 173 } |
178 try { | 174 try { |
179 action(responsePort.sendPort); | 175 action(responsePort.sendPort); |
180 } catch (e, s) { | 176 } catch (e, s) { |
181 responsePort.close(); | 177 responsePort.close(); |
182 if (timer != null) timer.cancel(); | 178 if (timer != null) timer.cancel(); |
183 // Delay completion because completer is sync. | 179 // Delay completion because completer is sync. |
184 scheduleMicrotask(() { completer.completeError(e, s); }); | 180 scheduleMicrotask(() { |
181 completer.completeError(e, s); | |
182 }); | |
185 } | 183 } |
186 return completer.future; | 184 return completer.future; |
187 } | 185 } |
188 | 186 |
189 | |
190 /** | 187 /** |
191 * Send the result of a future, either value or error, as a message. | 188 * Send the result of a future, either value or error, as a message. |
192 * | 189 * |
193 * The result of [future] is sent on [resultPort] in a form expected by | 190 * The result of [future] is sent on [resultPort] in a form expected by |
194 * either [receiveFutureResult], [completeFutureResult], or | 191 * either [receiveFutureResult], [completeFutureResult], or |
195 * by the port of [singleResultFuture]. | 192 * by the port of [singleResultFuture]. |
196 */ | 193 */ |
197 void sendFutureResult(Future future, SendPort resultPort) { | 194 void sendFutureResult(Future future, SendPort resultPort) { |
198 future.then((v) { resultPort.send(list1(v)); }, | 195 future.then((v) { |
199 onError: (e, s) { resultPort.send(list2("$e", "$s")); }); | 196 resultPort.send(list1(v)); |
197 }, onError: (e, s) { | |
198 resultPort.send(list2("$e", "$s")); | |
199 }); | |
200 } | 200 } |
201 | 201 |
202 | |
203 /** | 202 /** |
204 * Creates a [Future], and a [SendPort] that can be used to complete that | 203 * Creates a [Future], and a [SendPort] that can be used to complete that |
205 * future. | 204 * future. |
206 * | 205 * |
207 * Calls [action] with the response `SendPort`, then waits for someone | 206 * Calls [action] with the response `SendPort`, then waits for someone |
208 * to send a future result on that port using [sendFutureResult]. | 207 * to send a future result on that port using [sendFutureResult]. |
209 * The returned `Future` is completed with the future result sent on the port. | 208 * The returned `Future` is completed with the future result sent on the port. |
210 * | 209 * |
211 * If [action] throws, which it shouldn't, | 210 * If [action] throws, which it shouldn't, |
212 * the returned future is completed with that error, | 211 * the returned future is completed with that error, |
213 * unless someone manages to send a message on the port before `action` throws. | 212 * unless someone manages to send a message on the port before `action` throws. |
214 * | 213 * |
215 * If [timeout] is supplied, it is used as a limit on how | 214 * If [timeout] is supplied, it is used as a limit on how |
216 * long it can take before the message is received. If a | 215 * long it can take before the message is received. If a |
217 * message isn't received in time, the [onTimeout] is called, | 216 * message isn't received in time, the [onTimeout] is called, |
218 * and the future is completed with the result of that call | 217 * and the future is completed with the result of that call |
219 * instead. | 218 * instead. |
220 * If `onTimeout` is omitted, it defaults to throwing | 219 * If `onTimeout` is omitted, it defaults to throwing |
221 * a [TimeoutException]. | 220 * a [TimeoutException]. |
222 */ | 221 */ |
223 Future singleResultFuture(void action(SendPort responsePort), | 222 Future singleResultFuture(void action(SendPort responsePort), |
224 {Duration timeout, | 223 {Duration timeout, onTimeout()}) { |
Lasse Reichstein Nielsen
2015/02/26 10:59:14
Indent '{'.
| |
225 onTimeout()}) { | |
226 Completer completer = new Completer.sync(); | 224 Completer completer = new Completer.sync(); |
227 SendPort port = singleCompletePort(completer, | 225 SendPort port = singleCompletePort(completer, |
228 callback: receiveFutureResult, | 226 callback: receiveFutureResult, timeout: timeout, onTimeout: onTimeout); |
Lasse Reichstein Nielsen
2015/02/26 10:59:14
Put completer on a new line too, or indent as orig
| |
229 timeout: timeout, | |
230 onTimeout: onTimeout); | |
231 try { | 227 try { |
232 action(port); | 228 action(port); |
233 } catch (e, s) { | 229 } catch (e, s) { |
234 // This should not happen. | 230 // This should not happen. |
235 sendFutureResult(new Future.error(e, s), port); | 231 sendFutureResult(new Future.error(e, s), port); |
236 } | 232 } |
237 return completer.future; | 233 return completer.future; |
238 } | 234 } |
239 | 235 |
240 /** | 236 /** |
241 * Completes a completer with a message created by [sendFutureResult] | 237 * Completes a completer with a message created by [sendFutureResult] |
242 * | 238 * |
243 * The [response] must be a message on the format sent by [sendFutureResult]. | 239 * The [response] must be a message on the format sent by [sendFutureResult]. |
244 */ | 240 */ |
245 void completeFutureResult(var response, Completer completer) { | 241 void completeFutureResult(var response, Completer completer) { |
246 if (response.length == 2) { | 242 if (response.length == 2) { |
247 var error = new RemoteError(response[0], response[1]); | 243 var error = new RemoteError(response[0], response[1]); |
248 completer.completeError(error, error.stackTrace); | 244 completer.completeError(error, error.stackTrace); |
249 } else { | 245 } else { |
250 var result = response[0]; | 246 var result = response[0]; |
251 completer.complete(result); | 247 completer.complete(result); |
252 } | 248 } |
253 } | 249 } |
254 | 250 |
255 | |
Lasse Reichstein Nielsen
2015/02/26 10:59:14
I'm not sure I always want single lines between fu
| |
256 /** | 251 /** |
257 * Convertes a received message created by [sendFutureResult] to a future | 252 * Convertes a received message created by [sendFutureResult] to a future |
258 * result. | 253 * result. |
259 * | 254 * |
260 * The [response] must be a message on the format sent by [sendFutureResult]. | 255 * The [response] must be a message on the format sent by [sendFutureResult]. |
261 */ | 256 */ |
262 Future receiveFutureResult(var response) { | 257 Future receiveFutureResult(var response) { |
263 if (response.length == 2) { | 258 if (response.length == 2) { |
264 var error = new RemoteError(response[0], response[1]); | 259 var error = new RemoteError(response[0], response[1]); |
265 return new Future.error(error, error.stackTrace); | 260 return new Future.error(error, error.stackTrace); |
266 } | 261 } |
267 var result = response[0]; | 262 var result = response[0]; |
268 return new Future.value(result); | 263 return new Future.value(result); |
269 } | 264 } |
OLD | NEW |