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 define('data_receiver', [ | 5 define('data_receiver', [ |
6 'async_waiter', | 6 'async_waiter', |
7 'device/serial/data_stream.mojom', | 7 'device/serial/data_stream.mojom', |
| 8 'device/serial/data_stream_serialization.mojom', |
8 'mojo/public/js/bindings/core', | 9 'mojo/public/js/bindings/core', |
9 'mojo/public/js/bindings/router', | 10 'mojo/public/js/bindings/router', |
10 ], function(asyncWaiter, dataStream, core, router) { | 11 ], function(asyncWaiter, dataStream, serialization, core, router) { |
11 /** | 12 /** |
12 * @module data_receiver | 13 * @module data_receiver |
13 */ | 14 */ |
14 | 15 |
15 /** | 16 /** |
16 * @typedef module:data_receiver~PendingError | |
17 * @type {Object} | |
18 * @property {number} error - the error | |
19 * @property {number} offset - the location of the error | |
20 * @private | |
21 */ | |
22 | |
23 /** | |
24 * A pending receive operation. | 17 * A pending receive operation. |
25 * @constructor | 18 * @constructor |
26 * @alias module:data_receiver~PendingReceive | 19 * @alias module:data_receiver~PendingReceive |
27 * @private | 20 * @private |
28 */ | 21 */ |
29 function PendingReceive() { | 22 function PendingReceive() { |
30 /** | 23 /** |
31 * The promise that will be resolved or rejected when this receive completes | 24 * The promise that will be resolved or rejected when this receive completes |
32 * or fails, respectively. | 25 * or fails, respectively. |
33 * @type {Promise.<ArrayBuffer>} | 26 * @type {!Promise.<ArrayBuffer>} |
34 * @private | 27 * @private |
35 */ | 28 */ |
36 this.promise_ = new Promise(function(resolve, reject) { | 29 this.promise_ = new Promise(function(resolve, reject) { |
37 /** | 30 /** |
38 * The callback to call with the data received on success. | 31 * The callback to call with the data received on success. |
39 * @type {Function} | 32 * @type {Function} |
40 * @private | 33 * @private |
41 */ | 34 */ |
42 this.dataCallback_ = resolve; | 35 this.dataCallback_ = resolve; |
43 /** | 36 /** |
(...skipping 10 matching lines...) Expand all Loading... |
54 * rejected if an error occurs. | 47 * rejected if an error occurs. |
55 * @return {Promise.<ArrayBuffer>} A promise to the data received. | 48 * @return {Promise.<ArrayBuffer>} A promise to the data received. |
56 */ | 49 */ |
57 PendingReceive.prototype.getPromise = function() { | 50 PendingReceive.prototype.getPromise = function() { |
58 return this.promise_; | 51 return this.promise_; |
59 }; | 52 }; |
60 | 53 |
61 /** | 54 /** |
62 * Dispatches received data to the promise returned by | 55 * Dispatches received data to the promise returned by |
63 * [getPromise]{@link module:data_receiver.PendingReceive#getPromise}. | 56 * [getPromise]{@link module:data_receiver.PendingReceive#getPromise}. |
64 * @param {ArrayBuffer} data The data to dispatch. | 57 * @param {!ArrayBuffer} data The data to dispatch. |
65 */ | 58 */ |
66 PendingReceive.prototype.dispatchData = function(data) { | 59 PendingReceive.prototype.dispatchData = function(data) { |
67 this.dataCallback_(data); | 60 this.dataCallback_(data); |
68 }; | 61 }; |
69 | 62 |
70 /** | 63 /** |
71 * Dispatches an error if the offset of the error has been reached. | 64 * Dispatches an error if the offset of the error has been reached. |
72 * @param {module:data_receiver~PendingError} error The error to dispatch. | 65 * @param {!PendingReceiveError} error The error to dispatch. |
73 * @param {number} bytesReceived The number of bytes that have been received. | 66 * @param {number} bytesReceived The number of bytes that have been received. |
74 */ | 67 */ |
75 PendingReceive.prototype.dispatchError = function(error, bytesReceived) { | 68 PendingReceive.prototype.dispatchError = function(error, bytesReceived) { |
76 if (bytesReceived != error.offset) | 69 if (bytesReceived != error.offset) |
77 return false; | 70 return false; |
78 | 71 |
79 var e = new Error(); | 72 var e = new Error(); |
80 e.error = error.error; | 73 e.error = error.error; |
81 this.errorCallback_(e); | 74 this.errorCallback_(e); |
82 return true; | 75 return true; |
83 }; | 76 }; |
84 | 77 |
85 /** | 78 /** |
86 * Unconditionally dispatches an error. | 79 * Unconditionally dispatches an error. |
87 * @param {number} error The error to dispatch. | 80 * @param {number} error The error to dispatch. |
88 */ | 81 */ |
89 PendingReceive.prototype.dispatchFatalError = function(error) { | 82 PendingReceive.prototype.dispatchFatalError = function(error) { |
90 var e = new Error(); | 83 var e = new Error(); |
91 e.error = error; | 84 e.error = error; |
92 this.errorCallback_(e); | 85 this.errorCallback_(e); |
93 }; | 86 }; |
94 | 87 |
95 /** | 88 /** |
96 * A DataReceiver that receives data from a DataSource. | 89 * A DataReceiver that receives data from a DataSource. |
97 * @param {MojoHandle} handle The handle to the DataSource. | 90 * @param {!MojoHandle} handle The handle to the DataSource. |
98 * @param {number} bufferSize How large a buffer the data pipe should use. | 91 * @param {number} bufferSize How large a buffer the data pipe should use. |
99 * @param {number} fatalErrorValue The receive error value to report in the | 92 * @param {number} fatalErrorValue The receive error value to report in the |
100 * event of a fatal error. | 93 * event of a fatal error. |
101 * @constructor | 94 * @constructor |
102 * @alias module:data_receiver.DataReceiver | 95 * @alias module:data_receiver.DataReceiver |
103 */ | 96 */ |
104 function DataReceiver(handle, bufferSize, fatalErrorValue) { | 97 function DataReceiver(handle, bufferSize, fatalErrorValue) { |
| 98 var dataPipeOptions = { |
| 99 flags: core.CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, |
| 100 elementNumBytes: 1, |
| 101 capacityNumBytes: bufferSize, |
| 102 }; |
| 103 var receivePipe = core.createDataPipe(dataPipeOptions); |
| 104 this.init_( |
| 105 handle, receivePipe.consumerHandle, fatalErrorValue, 0, null, false); |
| 106 this.source_.init(receivePipe.producerHandle); |
| 107 } |
| 108 |
| 109 DataReceiver.prototype = |
| 110 $Object.create(dataStream.DataSourceClientStub.prototype); |
| 111 |
| 112 /** |
| 113 * Closes this DataReceiver. |
| 114 */ |
| 115 DataReceiver.prototype.close = function() { |
| 116 if (this.shutDown_) |
| 117 return; |
| 118 this.shutDown_ = true; |
| 119 this.router_.close(); |
| 120 this.waiter_.stop(); |
| 121 core.close(this.receivePipe_); |
| 122 if (this.receive_) { |
| 123 this.receive_.dispatchFatalError(this.fatalErrorValue_); |
| 124 this.receive_ = null; |
| 125 } |
| 126 }; |
| 127 |
| 128 /** |
| 129 * Initialize this DataReceiver. |
| 130 * @param {!MojoHandle} source A handle to the DataSource |
| 131 * @param {!MojoHandle} dataPipe A handle to use for receiving data from the |
| 132 * DataSource. |
| 133 * @param {number} fatalErrorValue The error to dispatch in the event of a |
| 134 * fatal error. |
| 135 * @param {number} bytesReceived The number of bytes already received. |
| 136 * @param {PendingReceiveError} pendingError The pending error if there is |
| 137 * one. |
| 138 * @param {boolean} paused Whether the DataSource is paused. |
| 139 * @private |
| 140 */ |
| 141 DataReceiver.prototype.init_ = function(source, |
| 142 dataPipe, |
| 143 fatalErrorValue, |
| 144 bytesReceived, |
| 145 pendingError, |
| 146 paused) { |
105 /** | 147 /** |
106 * The [Router]{@link module:mojo/public/js/bindings/router.Router} for the | 148 * The [Router]{@link module:mojo/public/js/bindings/router.Router} for the |
107 * connection to the DataSource. | 149 * connection to the DataSource. |
108 * @private | 150 * @private |
109 */ | 151 */ |
110 this.router_ = new router.Router(handle); | 152 this.router_ = new router.Router(source); |
111 /** | 153 /** |
112 * The connection to the DataSource. | 154 * The connection to the DataSource. |
113 * @private | 155 * @private |
114 */ | 156 */ |
115 this.source_ = new dataStream.DataSourceProxy(this.router_); | 157 this.source_ = new dataStream.DataSourceProxy(this.router_); |
116 this.router_.setIncomingReceiver(this); | 158 this.router_.setIncomingReceiver(this); |
117 var dataPipeOptions = { | |
118 flags: core.CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, | |
119 elementNumBytes: 1, | |
120 capacityNumBytes: bufferSize, | |
121 }; | |
122 var receivePipe = core.createDataPipe(dataPipeOptions); | |
123 this.source_.init(receivePipe.producerHandle); | |
124 /** | 159 /** |
125 * The handle to the data pipe to use for receiving data. | 160 * The handle to the data pipe to use for receiving data. |
126 * @private | 161 * @private |
127 */ | 162 */ |
128 this.receivePipe_ = receivePipe.consumerHandle; | 163 this.receivePipe_ = dataPipe; |
129 /** | 164 /** |
130 * The current receive operation. | 165 * The current receive operation. |
131 * @type {module:data_receiver~PendingReceive} | 166 * @type {module:data_receiver~PendingReceive} |
132 * @private | 167 * @private |
133 */ | 168 */ |
134 this.receive_ = null; | 169 this.receive_ = null; |
135 /** | 170 /** |
136 * The error to be dispatched in the event of a fatal error. | 171 * The error to be dispatched in the event of a fatal error. |
137 * @type {number} | 172 * @const {number} |
138 * @private | 173 * @private |
139 */ | 174 */ |
140 this.fatalErrorValue_ = fatalErrorValue; | 175 this.fatalErrorValue_ = fatalErrorValue; |
141 /** | 176 /** |
142 * The async waiter used to wait for | 177 * The async waiter used to wait for |
143 * {@link module:data_receiver.DataReceiver#receivePipe_} to be readable. | 178 * |[receivePipe_]{@link module:data_receiver.DataReceiver#receivePipe_}| to |
144 * @type module:async_waiter.AsyncWaiter | 179 * be readable. |
| 180 * @type {!module:async_waiter.AsyncWaiter} |
145 * @private | 181 * @private |
146 */ | 182 */ |
147 this.waiter_ = new asyncWaiter.AsyncWaiter(this.receivePipe_, | 183 this.waiter_ = new asyncWaiter.AsyncWaiter(this.receivePipe_, |
148 core.HANDLE_SIGNAL_READABLE, | 184 core.HANDLE_SIGNAL_READABLE, |
149 this.onHandleReady_.bind(this)); | 185 this.onHandleReady_.bind(this)); |
150 /** | 186 /** |
151 * The number of bytes received from the DataSource. | 187 * The number of bytes received from the DataSource. |
152 * @type {number} | 188 * @type {number} |
153 * @private | 189 * @private |
154 */ | 190 */ |
155 this.bytesReceived_ = 0; | 191 this.bytesReceived_ = bytesReceived; |
156 /** | 192 /** |
157 * The pending error if there is one. | 193 * The pending error if there is one. |
158 * @type module:data_receiver~PendingError | 194 * @type {PendingReceiveError} |
159 * @private | 195 * @private |
160 */ | 196 */ |
161 this.pendingError_ = null; | 197 this.pendingError_ = pendingError; |
162 /** | 198 /** |
163 * Whether the DataSource is paused. | 199 * Whether the DataSource is paused. |
164 * @type {boolean} | 200 * @type {boolean} |
165 * @private | 201 * @private |
166 */ | 202 */ |
167 this.paused_ = false; | 203 this.paused_ = paused; |
168 /** | 204 /** |
169 * Whether this DataReceiver has shut down. | 205 * Whether this DataReceiver has shut down. |
170 * @type {boolean} | 206 * @type {boolean} |
171 * @private | 207 * @private |
172 */ | 208 */ |
173 this.shutDown_ = false; | 209 this.shutDown_ = false; |
174 } | 210 }; |
175 | |
176 DataReceiver.prototype = | |
177 $Object.create(dataStream.DataSourceClientStub.prototype); | |
178 | 211 |
179 /** | 212 /** |
180 * Closes this DataReceiver. | 213 * Serializes this DataReceiver. |
| 214 * This will cancel a receive if one is in progress. |
| 215 * @return {!Promise.<SerializedDataReceiver>} A promise that will resolve to |
| 216 * the serialization of this DataReceiver. If this DataReceiver has shut |
| 217 * down, the promise will resolve to null. |
181 */ | 218 */ |
182 DataReceiver.prototype.close = function() { | 219 DataReceiver.prototype.serialize = function() { |
183 if (this.shutDown_) | 220 if (this.shutDown_) |
184 return; | 221 return Promise.resolve(null); |
185 this.shutDown_ = true; | 222 |
186 this.router_.close(); | |
187 this.waiter_.stop(); | 223 this.waiter_.stop(); |
188 core.close(this.receivePipe_); | |
189 if (this.receive_) { | 224 if (this.receive_) { |
190 this.receive_.dispatchFatalError(this.fatalErrorValue_); | 225 this.receive_.dispatchFatalError(this.fatalErrorValue_); |
191 this.receive_ = null; | 226 this.receive_ = null; |
192 } | 227 } |
| 228 var serialized = new serialization.SerializedDataReceiver(); |
| 229 serialized.source = this.router_.connector_.handle_; |
| 230 serialized.data_pipe = this.receivePipe_; |
| 231 serialized.fatal_error_value = this.fatalErrorValue_; |
| 232 serialized.bytes_received = this.bytesReceived_; |
| 233 serialized.paused = this.paused_; |
| 234 serialized.pending_error = this.pendingError_; |
| 235 this.router_.connector_.handle_ = null; |
| 236 this.router_.close(); |
| 237 this.shutDown_ = true; |
| 238 return Promise.resolve(serialized); |
193 }; | 239 }; |
194 | 240 |
195 /** | 241 /** |
| 242 * Deserializes a SerializedDataReceiver. |
| 243 * @param {SerializedDataReceiver} serialized The serialized DataReceiver. |
| 244 * @return {!DataReceiver} The deserialized DataReceiver. |
| 245 */ |
| 246 DataReceiver.deserialize = function(serialized) { |
| 247 var receiver = $Object.create(DataReceiver.prototype); |
| 248 receiver.deserialize_(serialized); |
| 249 return receiver; |
| 250 }; |
| 251 |
| 252 /** |
| 253 * Deserializes a SerializedDataReceiver into this DataReceiver. |
| 254 * @param {SerializedDataReceiver} serialized The serialized DataReceiver. |
| 255 * @private |
| 256 */ |
| 257 DataReceiver.prototype.deserialize_ = function(serialized) { |
| 258 if (!serialized) { |
| 259 this.shutDown_ = true; |
| 260 return; |
| 261 } |
| 262 this.init_(serialized.source, |
| 263 serialized.data_pipe, |
| 264 serialized.fatal_error_value, |
| 265 serialized.bytes_received, |
| 266 serialized.pending_error, |
| 267 serialized.paused); |
| 268 }; |
| 269 |
| 270 /** |
196 * Receive data from the DataSource. | 271 * Receive data from the DataSource. |
197 * @return {Promise.<ArrayBuffer>} A promise to the received data. If an error | 272 * @return {Promise.<ArrayBuffer>} A promise to the received data. If an error |
198 * occurs, the promise will reject with an Error object with a property | 273 * occurs, the promise will reject with an Error object with a property |
199 * error containing the error code. | 274 * error containing the error code. |
200 * @throws Will throw if this has encountered a fatal error or another receive | 275 * @throws Will throw if this has encountered a fatal error or another receive |
201 * is in progress. | 276 * is in progress. |
202 */ | 277 */ |
203 DataReceiver.prototype.receive = function() { | 278 DataReceiver.prototype.receive = function() { |
204 if (this.shutDown_) | 279 if (this.shutDown_) |
205 throw new Error('System error'); | 280 throw new Error('DataReceiver has been closed'); |
206 if (this.receive_) | 281 if (this.receive_) |
207 throw new Error('Receive already in progress.'); | 282 throw new Error('Receive already in progress.'); |
208 var receive = new PendingReceive(); | 283 var receive = new PendingReceive(); |
209 var promise = receive.getPromise(); | 284 var promise = receive.getPromise(); |
210 if (this.pendingError_ && | 285 if (this.pendingError_ && |
211 receive.dispatchError(this.pendingError_, this.bytesReceived_)) { | 286 receive.dispatchError(this.pendingError_, this.bytesReceived_)) { |
212 this.pendingError_ = null; | 287 this.pendingError_ = null; |
213 this.paused_ = true; | 288 this.paused_ = true; |
214 return promise; | 289 return promise; |
215 } | 290 } |
216 if (this.paused_) { | 291 if (this.paused_) { |
217 this.source_.resume(); | 292 this.source_.resume(); |
218 this.paused_ = false; | 293 this.paused_ = false; |
219 } | 294 } |
220 this.receive_ = receive; | 295 this.receive_ = receive; |
221 this.waiter_.start(); | 296 this.waiter_.start(); |
222 return promise; | 297 return promise; |
223 }; | 298 }; |
224 | 299 |
225 /** | 300 /** |
226 * Invoked when |handle_| is ready to read. Reads from the data pipe if the | 301 * Invoked when |
227 * wait is successful. | 302 * |[receivePipe_]{@link module:data_receiver.DataReceiver#receivePipe_}| is |
| 303 * ready to read. Reads from the data pipe if the wait is successful. |
228 * @param {number} waitResult The result of the asynchronous wait. | 304 * @param {number} waitResult The result of the asynchronous wait. |
229 * @private | 305 * @private |
230 */ | 306 */ |
231 DataReceiver.prototype.onHandleReady_ = function(waitResult) { | 307 DataReceiver.prototype.onHandleReady_ = function(waitResult) { |
232 if (waitResult != core.RESULT_OK || !this.receive_) { | 308 if (waitResult != core.RESULT_OK || !this.receive_) { |
233 this.close(); | 309 this.close(); |
234 return; | 310 return; |
235 } | 311 } |
236 var result = core.readData(this.receivePipe_, core.READ_DATA_FLAG_NONE); | 312 var result = core.readData(this.receivePipe_, core.READ_DATA_FLAG_NONE); |
237 if (result.result == core.RESULT_OK) { | 313 if (result.result == core.RESULT_OK) { |
(...skipping 11 matching lines...) Expand all Loading... |
249 /** | 325 /** |
250 * Invoked by the DataSource when an error is encountered. | 326 * Invoked by the DataSource when an error is encountered. |
251 * @param {number} offset The location at which the error occurred. | 327 * @param {number} offset The location at which the error occurred. |
252 * @param {number} error The error that occurred. | 328 * @param {number} error The error that occurred. |
253 * @private | 329 * @private |
254 */ | 330 */ |
255 DataReceiver.prototype.onError = function(offset, error) { | 331 DataReceiver.prototype.onError = function(offset, error) { |
256 if (this.shutDown_) | 332 if (this.shutDown_) |
257 return; | 333 return; |
258 | 334 |
259 /** | 335 var pendingError = new serialization.PendingReceiveError(); |
260 * @type module:data_receiver~PendingError | 336 pendingError.error = error; |
261 */ | 337 pendingError.offset = offset; |
262 var pendingError = { | |
263 error: error, | |
264 offset: offset, | |
265 }; | |
266 if (this.receive_ && | 338 if (this.receive_ && |
267 this.receive_.dispatchError(pendingError, this.bytesReceived_)) { | 339 this.receive_.dispatchError(pendingError, this.bytesReceived_)) { |
268 this.receive_ = null; | 340 this.receive_ = null; |
269 this.waiter_.stop(); | 341 this.waiter_.stop(); |
270 this.paused_ = true; | 342 this.paused_ = true; |
271 return; | 343 return; |
272 } | 344 } |
273 this.pendingError_ = pendingError; | 345 this.pendingError_ = pendingError; |
274 }; | 346 }; |
275 | 347 |
276 return {DataReceiver: DataReceiver}; | 348 return {DataReceiver: DataReceiver}; |
277 }); | 349 }); |
OLD | NEW |