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
3 // found in the LICENSE file.
5 define('data_receiver', [
7 'device/serial/data_stream.mojom',
8 'mojo/public/js/bindings/core',
9 'mojo/public/js/bindings/router',
10 ], function(asyncWaiter
, dataStream
, core
, router
) {
12 * @module data_receiver
16 * @typedef module:data_receiver~PendingError
18 * @property {number} error - the error
19 * @property {number} offset - the location of the error
24 * A pending receive operation.
26 * @alias module:data_receiver~PendingReceive
29 function PendingReceive() {
31 * The promise that will be resolved or rejected when this receive completes
32 * or fails, respectively.
33 * @type {Promise.<ArrayBuffer>}
36 this.promise_
= new Promise(function(resolve
, reject
) {
38 * The callback to call with the data received on success.
42 this.dataCallback_
= resolve
;
44 * The callback to call with the error on failure.
48 this.errorCallback_
= reject
;
53 * Returns the promise that will be resolved when this operation completes or
54 * rejected if an error occurs.
55 * @return {Promise.<ArrayBuffer>} A promise to the data received.
57 PendingReceive
.prototype.getPromise = function() {
62 * Dispatches received data to the promise returned by
63 * [getPromise]{@link module:data_receiver.PendingReceive#getPromise}.
64 * @param {ArrayBuffer} data The data to dispatch.
66 PendingReceive
.prototype.dispatchData = function(data
) {
67 this.dataCallback_(data
);
71 * Dispatches an error if the offset of the error has been reached.
72 * @param {module:data_receiver~PendingError} error The error to dispatch.
73 * @param {number} bytesReceived The number of bytes that have been received.
75 PendingReceive
.prototype.dispatchError = function(error
, bytesReceived
) {
76 if (bytesReceived
!= error
.offset
)
80 e
.error
= error
.error
;
81 this.errorCallback_(e
);
86 * Unconditionally dispatches an error.
87 * @param {number} error The error to dispatch.
89 PendingReceive
.prototype.dispatchFatalError = function(error
) {
92 this.errorCallback_(e
);
96 * A DataReceiver that receives data from a DataSource.
97 * @param {MojoHandle} handle The handle to the DataSource.
98 * @param {number} bufferSize How large a buffer the data pipe should use.
99 * @param {number} fatalErrorValue The receive error value to report in the
100 * event of a fatal error.
102 * @alias module:data_receiver.DataReceiver
104 function DataReceiver(handle
, bufferSize
, fatalErrorValue
) {
106 * The [Router]{@link module:mojo/public/js/bindings/router.Router} for the
107 * connection to the DataSource.
110 this.router_
= new router
.Router(handle
);
112 * The connection to the DataSource.
115 this.source_
= new dataStream
.DataSourceProxy(this.router_
);
116 this.router_
.setIncomingReceiver(this);
117 var dataPipeOptions
= {
118 flags
: core
.CREATE_DATA_PIPE_OPTIONS_FLAG_NONE
,
120 capacityNumBytes
: bufferSize
,
122 var receivePipe
= core
.createDataPipe(dataPipeOptions
);
123 this.source_
.init(receivePipe
.producerHandle
);
125 * The handle to the data pipe to use for receiving data.
128 this.receivePipe_
= receivePipe
.consumerHandle
;
130 * The current receive operation.
131 * @type {module:data_receiver~PendingReceive}
134 this.receive_
= null;
136 * The error to be dispatched in the event of a fatal error.
140 this.fatalErrorValue_
= fatalErrorValue
;
142 * The async waiter used to wait for
143 * {@link module:data_receiver.DataReceiver#receivePipe_} to be readable.
144 * @type module:async_waiter.AsyncWaiter
147 this.waiter_
= new asyncWaiter
.AsyncWaiter(this.receivePipe_
,
148 core
.HANDLE_SIGNAL_READABLE
,
149 this.onHandleReady_
.bind(this));
151 * The number of bytes received from the DataSource.
155 this.bytesReceived_
= 0;
157 * The pending error if there is one.
158 * @type module:data_receiver~PendingError
161 this.pendingError_
= null;
163 * Whether the DataSource is paused.
167 this.paused_
= false;
169 * Whether this DataReceiver has shut down.
173 this.shutDown_
= false;
176 DataReceiver
.prototype =
177 $Object
.create(dataStream
.DataSourceClientStub
.prototype);
180 * Closes this DataReceiver.
182 DataReceiver
.prototype.close = function() {
185 this.shutDown_
= true;
186 this.router_
.close();
188 core
.close(this.receivePipe_
);
190 this.receive_
.dispatchFatalError(this.fatalErrorValue_
);
191 this.receive_
= null;
196 * Receive data from the DataSource.
197 * @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
199 * error containing the error code.
200 * @throws Will throw if this has encountered a fatal error or another receive
203 DataReceiver
.prototype.receive = function() {
205 throw new Error('System error');
207 throw new Error('Receive already in progress.');
208 var receive
= new PendingReceive();
209 var promise
= receive
.getPromise();
210 if (this.pendingError_
&&
211 receive
.dispatchError(this.pendingError_
, this.bytesReceived_
)) {
212 this.pendingError_
= null;
217 this.source_
.resume();
218 this.paused_
= false;
220 this.receive_
= receive
;
221 this.waiter_
.start();
226 * Invoked when |handle_| is ready to read. Reads from the data pipe if the
227 * wait is successful.
228 * @param {number} waitResult The result of the asynchronous wait.
231 DataReceiver
.prototype.onHandleReady_ = function(waitResult
) {
232 if (waitResult
!= core
.RESULT_OK
|| !this.receive_
) {
236 var result
= core
.readData(this.receivePipe_
, core
.READ_DATA_FLAG_NONE
);
237 if (result
.result
== core
.RESULT_OK
) {
238 // TODO(sammc): Handle overflow in the same fashion as the C++ receiver.
239 this.bytesReceived_
+= result
.buffer
.byteLength
;
240 this.receive_
.dispatchData(result
.buffer
);
241 this.receive_
= null;
242 } else if (result
.result
== core
.RESULT_SHOULD_WAIT
) {
243 this.waiter_
.start();
250 * Invoked by the DataSource when an error is encountered.
251 * @param {number} offset The location at which the error occurred.
252 * @param {number} error The error that occurred.
255 DataReceiver
.prototype.onError = function(offset
, error
) {
260 * @type module:data_receiver~PendingError
267 this.receive_
.dispatchError(pendingError
, this.bytesReceived_
)) {
268 this.receive_
= null;
273 this.pendingError_
= pendingError
;
276 return {DataReceiver
: DataReceiver
};