103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// found in the LICENSE file.
403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)define('data_receiver', [
603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    'async_waiter',
703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    'device/serial/data_stream.mojom',
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    'device/serial/data_stream_serialization.mojom',
903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    'mojo/public/js/bindings/core',
1003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    'mojo/public/js/bindings/router',
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci], function(asyncWaiter, dataStream, serialization, core, router) {
1203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  /**
1303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @module data_receiver
1403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   */
1503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
1603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  /**
1703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * A pending receive operation.
1803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @constructor
1903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @alias module:data_receiver~PendingReceive
2003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @private
2103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   */
2203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  function PendingReceive() {
2303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    /**
2403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * The promise that will be resolved or rejected when this receive completes
2503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * or fails, respectively.
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * @type {!Promise.<ArrayBuffer>}
2703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * @private
2803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     */
2903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    this.promise_ = new Promise(function(resolve, reject) {
3003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      /**
3103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)       * The callback to call with the data received on success.
3203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)       * @type {Function}
3303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)       * @private
3403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)       */
3503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      this.dataCallback_ = resolve;
3603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      /**
3703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)       * The callback to call with the error on failure.
3803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)       * @type {Function}
3903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)       * @private
4003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)       */
4103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      this.errorCallback_ = reject;
4203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }.bind(this));
4303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
4403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
4503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  /**
4603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * Returns the promise that will be resolved when this operation completes or
4703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * rejected if an error occurs.
4803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @return {Promise.<ArrayBuffer>} A promise to the data received.
4903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   */
5003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  PendingReceive.prototype.getPromise = function() {
5103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return this.promise_;
5203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  };
5303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
5403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  /**
5503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * Dispatches received data to the promise returned by
5603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * [getPromise]{@link module:data_receiver.PendingReceive#getPromise}.
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @param {!ArrayBuffer} data The data to dispatch.
5803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   */
5903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  PendingReceive.prototype.dispatchData = function(data) {
6003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    this.dataCallback_(data);
6103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  };
6203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
6303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  /**
6403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * Dispatches an error if the offset of the error has been reached.
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @param {!PendingReceiveError} error The error to dispatch.
6603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @param {number} bytesReceived The number of bytes that have been received.
6703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   */
6803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  PendingReceive.prototype.dispatchError = function(error, bytesReceived) {
6903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (bytesReceived != error.offset)
7003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return false;
7103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
7203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    var e = new Error();
7303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    e.error = error.error;
7403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    this.errorCallback_(e);
7503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return true;
7603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  };
7703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
7803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  /**
7903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * Unconditionally dispatches an error.
8003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @param {number} error The error to dispatch.
8103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   */
8203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  PendingReceive.prototype.dispatchFatalError = function(error) {
8303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    var e = new Error();
8403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    e.error = error;
8503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    this.errorCallback_(e);
8603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  };
8703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
8803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  /**
8903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * A DataReceiver that receives data from a DataSource.
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @param {!MojoHandle} handle The handle to the DataSource.
9103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @param {number} bufferSize How large a buffer the data pipe should use.
9203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @param {number} fatalErrorValue The receive error value to report in the
9303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   *     event of a fatal error.
9403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @constructor
9503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @alias module:data_receiver.DataReceiver
9603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   */
9703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  function DataReceiver(handle, bufferSize, fatalErrorValue) {
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    var dataPipeOptions = {
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      flags: core.CREATE_DATA_PIPE_OPTIONS_FLAG_NONE,
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      elementNumBytes: 1,
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      capacityNumBytes: bufferSize,
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    };
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    var receivePipe = core.createDataPipe(dataPipeOptions);
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.init_(
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        handle, receivePipe.consumerHandle, fatalErrorValue, 0, null, false);
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.source_.init(receivePipe.producerHandle);
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DataReceiver.prototype =
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      $Object.create(dataStream.DataSourceClientStub.prototype);
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  /**
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * Closes this DataReceiver.
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   */
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DataReceiver.prototype.close = function() {
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (this.shutDown_)
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return;
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.shutDown_ = true;
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.router_.close();
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.waiter_.stop();
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    core.close(this.receivePipe_);
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (this.receive_) {
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      this.receive_.dispatchFatalError(this.fatalErrorValue_);
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      this.receive_ = null;
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  };
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  /**
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * Initialize this DataReceiver.
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @param {!MojoHandle} source A handle to the DataSource
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @param {!MojoHandle} dataPipe A handle to use for receiving data from the
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   *     DataSource.
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @param {number} fatalErrorValue The error to dispatch in the event of a
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   *     fatal error.
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @param {number} bytesReceived The number of bytes already received.
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @param {PendingReceiveError} pendingError The pending error if there is
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * one.
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @param {boolean} paused Whether the DataSource is paused.
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @private
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   */
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DataReceiver.prototype.init_ = function(source,
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                          dataPipe,
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                          fatalErrorValue,
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                          bytesReceived,
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                          pendingError,
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                          paused) {
14703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    /**
14803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * The [Router]{@link module:mojo/public/js/bindings/router.Router} for the
14903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * connection to the DataSource.
15003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * @private
15103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     */
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.router_ = new router.Router(source);
15303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    /**
15403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * The connection to the DataSource.
15503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * @private
15603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     */
15703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    this.source_ = new dataStream.DataSourceProxy(this.router_);
15803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    this.router_.setIncomingReceiver(this);
15903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    /**
16003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * The handle to the data pipe to use for receiving data.
16103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * @private
16203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     */
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.receivePipe_ = dataPipe;
16403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    /**
16503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * The current receive operation.
16603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * @type {module:data_receiver~PendingReceive}
16703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * @private
16803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     */
16903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    this.receive_ = null;
17003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    /**
17103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * The error to be dispatched in the event of a fatal error.
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * @const {number}
17303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * @private
17403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     */
17503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    this.fatalErrorValue_ = fatalErrorValue;
17603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    /**
17703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * The async waiter used to wait for
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * |[receivePipe_]{@link module:data_receiver.DataReceiver#receivePipe_}| to
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     *     be readable.
1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * @type {!module:async_waiter.AsyncWaiter}
18103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * @private
18203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     */
18303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    this.waiter_ = new asyncWaiter.AsyncWaiter(this.receivePipe_,
18403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                               core.HANDLE_SIGNAL_READABLE,
18503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                               this.onHandleReady_.bind(this));
18603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    /**
18703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * The number of bytes received from the DataSource.
18803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * @type {number}
18903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * @private
19003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     */
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.bytesReceived_ = bytesReceived;
19203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    /**
19303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * The pending error if there is one.
1941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * @type {PendingReceiveError}
19503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * @private
19603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     */
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.pendingError_ = pendingError;
19803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    /**
19903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * Whether the DataSource is paused.
20003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * @type {boolean}
20103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * @private
20203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     */
2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.paused_ = paused;
20403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    /**
20503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * Whether this DataReceiver has shut down.
20603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * @type {boolean}
20703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * @private
20803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     */
20903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    this.shutDown_ = false;
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  };
21103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
21203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  /**
2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * Serializes this DataReceiver.
2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * This will cancel a receive if one is in progress.
2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @return {!Promise.<SerializedDataReceiver>} A promise that will resolve to
2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   *     the serialization of this DataReceiver. If this DataReceiver has shut
2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   *     down, the promise will resolve to null.
21803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   */
2191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DataReceiver.prototype.serialize = function() {
22003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (this.shutDown_)
2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return Promise.resolve(null);
2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
22303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    this.waiter_.stop();
22403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (this.receive_) {
22503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      this.receive_.dispatchFatalError(this.fatalErrorValue_);
22603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      this.receive_ = null;
22703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    var serialized = new serialization.SerializedDataReceiver();
2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    serialized.source = this.router_.connector_.handle_;
2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    serialized.data_pipe = this.receivePipe_;
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    serialized.fatal_error_value = this.fatalErrorValue_;
2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    serialized.bytes_received = this.bytesReceived_;
2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    serialized.paused = this.paused_;
2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    serialized.pending_error = this.pendingError_;
2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.router_.connector_.handle_ = null;
2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.router_.close();
2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.shutDown_ = true;
2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return Promise.resolve(serialized);
2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  };
2401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  /**
2421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * Deserializes a SerializedDataReceiver.
2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @param {SerializedDataReceiver} serialized The serialized DataReceiver.
2441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @return {!DataReceiver} The deserialized DataReceiver.
2451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   */
2461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DataReceiver.deserialize = function(serialized) {
2471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    var receiver = $Object.create(DataReceiver.prototype);
2481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    receiver.deserialize_(serialized);
2491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return receiver;
2501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  };
2511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  /**
2531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * Deserializes a SerializedDataReceiver into this DataReceiver.
2541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @param {SerializedDataReceiver} serialized The serialized DataReceiver.
2551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @private
2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   */
2571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DataReceiver.prototype.deserialize_ = function(serialized) {
2581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!serialized) {
2591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      this.shutDown_ = true;
2601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return;
2611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
2621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.init_(serialized.source,
2631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               serialized.data_pipe,
2641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               serialized.fatal_error_value,
2651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               serialized.bytes_received,
2661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               serialized.pending_error,
2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               serialized.paused);
26803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  };
26903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
27003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  /**
27103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * Receive data from the DataSource.
27203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @return {Promise.<ArrayBuffer>} A promise to the received data. If an error
27303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   *     occurs, the promise will reject with an Error object with a property
27403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   *     error containing the error code.
27503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @throws Will throw if this has encountered a fatal error or another receive
27603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   *     is in progress.
27703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   */
27803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DataReceiver.prototype.receive = function() {
27903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (this.shutDown_)
2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      throw new Error('DataReceiver has been closed');
28103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (this.receive_)
28203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      throw new Error('Receive already in progress.');
28303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    var receive = new PendingReceive();
28403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    var promise = receive.getPromise();
28503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (this.pendingError_ &&
28603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        receive.dispatchError(this.pendingError_, this.bytesReceived_)) {
28703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      this.pendingError_ = null;
28803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      this.paused_ = true;
28903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return promise;
29003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
29103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (this.paused_) {
29203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      this.source_.resume();
29303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      this.paused_ = false;
29403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
29503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    this.receive_ = receive;
29603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    this.waiter_.start();
29703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return promise;
29803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  };
29903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
30003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  /**
3011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * Invoked when
3021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * |[receivePipe_]{@link module:data_receiver.DataReceiver#receivePipe_}| is
3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * ready to read. Reads from the data pipe if the wait is successful.
30403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @param {number} waitResult The result of the asynchronous wait.
30503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @private
30603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   */
30703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DataReceiver.prototype.onHandleReady_ = function(waitResult) {
30803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (waitResult != core.RESULT_OK || !this.receive_) {
30903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      this.close();
31003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return;
31103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
31203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    var result = core.readData(this.receivePipe_, core.READ_DATA_FLAG_NONE);
31303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (result.result == core.RESULT_OK) {
31403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // TODO(sammc): Handle overflow in the same fashion as the C++ receiver.
31503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      this.bytesReceived_ += result.buffer.byteLength;
31603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      this.receive_.dispatchData(result.buffer);
31703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      this.receive_ = null;
31803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    } else if (result.result == core.RESULT_SHOULD_WAIT) {
31903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      this.waiter_.start();
32003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    } else {
32103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      this.close();
32203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
32303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  };
32403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
32503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  /**
32603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * Invoked by the DataSource when an error is encountered.
32703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @param {number} offset The location at which the error occurred.
32803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @param {number} error The error that occurred.
32903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * @private
33003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   */
33103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DataReceiver.prototype.onError = function(offset, error) {
33203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (this.shutDown_)
33303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return;
33403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
3351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    var pendingError = new serialization.PendingReceiveError();
3361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    pendingError.error = error;
3371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    pendingError.offset = offset;
33803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (this.receive_ &&
33903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        this.receive_.dispatchError(pendingError, this.bytesReceived_)) {
34003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      this.receive_ = null;
34103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      this.waiter_.stop();
34203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      this.paused_ = true;
34303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return;
34403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
34503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    this.pendingError_ = pendingError;
34603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  };
34703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
34803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return {DataReceiver: DataReceiver};
34903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)});
350