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', [
6 'device/serial/data_stream.mojom',
7 'device/serial/data_stream_serialization.mojom',
9 'mojo/public/js/router',
10 ], function(dataStream, serialization, core, router) {
12 * @module data_receiver
16 * A pending receive operation.
18 * @alias module:data_receiver~PendingReceive
21 function PendingReceive() {
23 * The promise that will be resolved or rejected when this receive completes
24 * or fails, respectively.
25 * @type {!Promise.<ArrayBuffer>}
28 this.promise_ = new Promise(function(resolve, reject) {
30 * The callback to call with the data received on success.
34 this.dataCallback_ = resolve;
36 * The callback to call with the error on failure.
40 this.errorCallback_ = reject;
45 * Returns the promise that will be resolved when this operation completes or
46 * rejected if an error occurs.
47 * @return {Promise.<ArrayBuffer>} A promise to the data received.
49 PendingReceive.prototype.getPromise = function() {
54 * Dispatches received data to the promise returned by
55 * [getPromise]{@link module:data_receiver.PendingReceive#getPromise}.
56 * @param {!ArrayBuffer} data The data to dispatch.
58 PendingReceive.prototype.dispatchData = function(data) {
59 this.dataCallback_(data);
63 * Dispatches an error if the offset of the error has been reached.
64 * @param {!PendingReceiveError} error The error to dispatch.
65 * @param {number} bytesReceived The number of bytes that have been received.
67 PendingReceive.prototype.dispatchError = function(error) {
68 if (error.queuePosition > 0)
72 e.error = error.error;
73 this.errorCallback_(e);
78 * Unconditionally dispatches an error.
79 * @param {number} error The error to dispatch.
81 PendingReceive.prototype.dispatchFatalError = function(error) {
84 this.errorCallback_(e);
88 * A DataReceiver that receives data from a DataSource.
89 * @param {!MojoHandle} handle The handle to the DataSource.
90 * @param {number} bufferSize How large a buffer to use.
91 * @param {number} fatalErrorValue The receive error value to report in the
92 * event of a fatal error.
94 * @alias module:data_receiver.DataReceiver
96 function DataReceiver(handle, bufferSize, fatalErrorValue) {
97 this.init_(handle, fatalErrorValue, 0, null, [], false);
98 this.source_.init(bufferSize);
101 DataReceiver.prototype =
102 $Object.create(dataStream.DataSourceClient.stubClass.prototype);
105 * Closes this DataReceiver.
107 DataReceiver.prototype.close = function() {
110 this.shutDown_ = true;
111 this.router_.close();
113 this.receive_.dispatchFatalError(this.fatalErrorValue_);
114 this.receive_ = null;
119 * Initialize this DataReceiver.
120 * @param {!MojoHandle} source A handle to the DataSource
121 * @param {number} fatalErrorValue The error to dispatch in the event of a
123 * @param {number} bytesReceived The number of bytes already received.
124 * @param {PendingReceiveError} pendingError The pending error if there is
126 * @param {!Array.<!ArrayBuffer>} pendingData Data received from the
127 * DataSource not yet requested by the client.
128 * @param {boolean} paused Whether the DataSource is paused.
131 DataReceiver.prototype.init_ = function(source,
138 * The [Router]{@link module:mojo/public/js/router.Router} for the
139 * connection to the DataSource.
142 this.router_ = new router.Router(source);
144 * The connection to the DataSource.
147 this.source_ = new dataStream.DataSource.proxyClass(this.router_);
148 this.router_.setIncomingReceiver(this);
150 * The current receive operation.
151 * @type {module:data_receiver~PendingReceive}
154 this.receive_ = null;
156 * The error to be dispatched in the event of a fatal error.
160 this.fatalErrorValue_ = fatalErrorValue;
162 * The pending error if there is one.
163 * @type {PendingReceiveError}
166 this.pendingError_ = pendingError;
168 * Whether the DataSource is paused.
172 this.paused_ = paused;
174 * A queue of data that has been received from the DataSource, but not
175 * consumed by the client.
176 * @type {module:data_receiver~PendingData[]}
179 this.pendingDataBuffers_ = pendingData;
181 * Whether this DataReceiver has shut down.
185 this.shutDown_ = false;
189 * Serializes this DataReceiver.
190 * This will cancel a receive if one is in progress.
191 * @return {!Promise.<SerializedDataReceiver>} A promise that will resolve to
192 * the serialization of this DataReceiver. If this DataReceiver has shut
193 * down, the promise will resolve to null.
195 DataReceiver.prototype.serialize = function() {
197 return Promise.resolve(null);
200 this.receive_.dispatchFatalError(this.fatalErrorValue_);
201 this.receive_ = null;
203 var serialized = new serialization.SerializedDataReceiver();
204 serialized.source = this.router_.connector_.handle_;
205 serialized.fatal_error_value = this.fatalErrorValue_;
206 serialized.paused = this.paused_;
207 serialized.pending_error = this.pendingError_;
208 serialized.pending_data = [];
209 $Array.forEach(this.pendingDataBuffers_, function(buffer) {
210 serialized.pending_data.push(new Uint8Array(buffer));
212 this.router_.connector_.handle_ = null;
213 this.router_.close();
214 this.shutDown_ = true;
215 return Promise.resolve(serialized);
219 * Deserializes a SerializedDataReceiver.
220 * @param {SerializedDataReceiver} serialized The serialized DataReceiver.
221 * @return {!DataReceiver} The deserialized DataReceiver.
223 DataReceiver.deserialize = function(serialized) {
224 var receiver = $Object.create(DataReceiver.prototype);
225 receiver.deserialize_(serialized);
230 * Deserializes a SerializedDataReceiver into this DataReceiver.
231 * @param {SerializedDataReceiver} serialized The serialized DataReceiver.
234 DataReceiver.prototype.deserialize_ = function(serialized) {
236 this.shutDown_ = true;
239 var pendingData = [];
240 $Array.forEach(serialized.pending_data, function(data) {
241 var buffer = new Uint8Array(data.length);
243 pendingData.push(buffer.buffer);
245 this.init_(serialized.source,
246 serialized.fatal_error_value,
247 serialized.bytes_received,
248 serialized.pending_error,
254 * Receive data from the DataSource.
255 * @return {Promise.<ArrayBuffer>} A promise to the received data. If an error
256 * occurs, the promise will reject with an Error object with a property
257 * error containing the error code.
258 * @throws Will throw if this has encountered a fatal error or another receive
261 DataReceiver.prototype.receive = function() {
263 throw new Error('DataReceiver has been closed');
265 throw new Error('Receive already in progress.');
266 var receive = new PendingReceive();
267 var promise = receive.getPromise();
268 if (this.pendingError_ &&
269 receive.dispatchError(this.pendingError_)) {
270 this.pendingError_ = null;
275 this.source_.resume();
276 this.paused_ = false;
278 this.receive_ = receive;
279 this.dispatchData_();
283 DataReceiver.prototype.dispatchData_ = function() {
284 if (!this.receive_) {
288 if (this.pendingDataBuffers_.length) {
289 this.receive_.dispatchData(this.pendingDataBuffers_[0]);
290 this.source_.reportBytesReceived(this.pendingDataBuffers_[0].byteLength);
291 this.receive_ = null;
292 this.pendingDataBuffers_.shift();
293 if (this.pendingError_)
294 this.pendingError_.queuePosition--;
299 * Invoked by the DataSource when an error is encountered.
300 * @param {number} offset The location at which the error occurred.
301 * @param {number} error The error that occurred.
304 DataReceiver.prototype.onError = function(error) {
308 var pendingError = new serialization.PendingReceiveError();
309 pendingError.error = error;
310 pendingError.queuePosition = this.pendingDataBuffers_.length;
311 if (this.receive_ && this.receive_.dispatchError(pendingError)) {
312 this.receive_ = null;
316 this.pendingError_ = pendingError;
319 DataReceiver.prototype.onData = function(data) {
320 var buffer = new ArrayBuffer(data.length);
321 var uintView = new Uint8Array(buffer);
323 this.pendingDataBuffers_.push(buffer);
325 this.dispatchData_();
328 return {DataReceiver: DataReceiver};