| Index: remoting/webapp/crd/js/fallback_signal_strategy.js
|
| diff --git a/remoting/webapp/crd/js/fallback_signal_strategy.js b/remoting/webapp/crd/js/fallback_signal_strategy.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..bb58e4d45ae63da3adcf558a4581b61009ffb3bd
|
| --- /dev/null
|
| +++ b/remoting/webapp/crd/js/fallback_signal_strategy.js
|
| @@ -0,0 +1,329 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +'use strict';
|
| +
|
| +/** @suppress {duplicate} */
|
| +var remoting = remoting || {};
|
| +
|
| +/**
|
| + * A signal strategy encapsulating a primary and a back-up strategy. If the
|
| + * primary fails or times out, then the secondary is used. Information about
|
| + * which strategy was used, and why, is returned via |onProgressCallback|.
|
| + *
|
| + * @param {function(
|
| + * function(remoting.SignalStrategy.State)
|
| + * ):remoting.SignalStrategy} primaryFactory
|
| + * @param {function(
|
| + * function(remoting.SignalStrategy.State)
|
| + * ):remoting.SignalStrategy} secondaryFactory
|
| + * @param {function(remoting.SignalStrategy.State):void} onStateChangedCallback
|
| + * @param {function(remoting.FallbackSignalStrategy.Progress)}
|
| + * onProgressCallback
|
| + *
|
| + * @implements {remoting.SignalStrategy}
|
| + * @constructor
|
| + */
|
| +remoting.FallbackSignalStrategy = function(
|
| + primaryFactory, secondaryFactory,
|
| + onStateChangedCallback, onProgressCallback) {
|
| + /**
|
| + * @type {remoting.SignalStrategy}
|
| + * @private
|
| + */
|
| + this.primary_ = primaryFactory(this.onPrimaryStateChanged_.bind(this));
|
| +
|
| + /**
|
| + * @type {remoting.SignalStrategy}
|
| + * @private
|
| + */
|
| + this.secondary_ = secondaryFactory(this.onSecondaryStateChanged_.bind(this));
|
| +
|
| + /**
|
| + * @type {function(remoting.SignalStrategy.State)}
|
| + * @private
|
| + */
|
| + this.onStateChangedCallback_ = onStateChangedCallback;
|
| +
|
| + /**
|
| + * @type {function(remoting.FallbackSignalStrategy.Progress)}
|
| + * @private
|
| + */
|
| + this.onProgressCallback_ = onProgressCallback;
|
| +
|
| + /**
|
| + * @type {?function(Element):void}
|
| + * @private
|
| + */
|
| + this.onIncomingStanzaCallback_ = null;
|
| +
|
| + /**
|
| + * @type {number}
|
| + * @private
|
| + * @const
|
| + */
|
| + this.PRIMARY_CONNECT_TIMEOUT_MS_ = 10 * 1000;
|
| +
|
| + /**
|
| + * @enum {string}
|
| + * @private
|
| + */
|
| + this.State = {
|
| + NOT_CONNECTED: 'not-connected',
|
| + PRIMARY_PENDING: 'primary-pending',
|
| + PRIMARY_SUCCEEDED: 'primary-succeeded',
|
| + SECONDARY_PENDING: 'secondary-pending',
|
| + SECONDARY_SUCCEEDED: 'secondary-succeeded',
|
| + SECONDARY_FAILED: 'secondary-failed',
|
| + CLOSED: 'closed'
|
| + };
|
| +
|
| + /**
|
| + * @type {string}
|
| + * @private
|
| + */
|
| + this.state_ = this.State.NOT_CONNECTED;
|
| +
|
| + /**
|
| + * @type {?remoting.SignalStrategy.State}
|
| + * @private
|
| + */
|
| + this.externalState_ = null;
|
| +
|
| + /**
|
| + * @type {string}
|
| + * @private
|
| + */
|
| + this.server_ = '';
|
| +
|
| + /**
|
| + * @type {string}
|
| + * @private
|
| + */
|
| + this.username_ = '';
|
| +
|
| + /**
|
| + * @type {string}
|
| + * @private
|
| + */
|
| + this.authToken_ = '';
|
| +
|
| + /**
|
| + * @type {number}
|
| + * @private
|
| + */
|
| + this.primaryConnectTimerId_ = 0;
|
| +};
|
| +
|
| +/**
|
| + * @enum {string}
|
| + */
|
| +remoting.FallbackSignalStrategy.Progress = {
|
| + PRIMARY_SUCCEEDED: 'primary-succeeded',
|
| + PRIMARY_FAILED: 'primary-failed',
|
| + PRIMARY_TIMED_OUT: 'primary-timed-out',
|
| + PRIMARY_SUCCEEDED_LATE: 'primary-succeeded-late',
|
| + PRIMARY_FAILED_LATE: 'primary-failed-late',
|
| + SECONDARY_SUCCEEDED: 'secondary-succeeded',
|
| + SECONDARY_FAILED: 'secondary-failed'
|
| +};
|
| +
|
| +remoting.FallbackSignalStrategy.prototype.dispose = function() {
|
| + this.primary_.dispose();
|
| + this.secondary_.dispose();
|
| +};
|
| +
|
| +/**
|
| + * @param {?function(Element):void} onIncomingStanzaCallback Callback to call on
|
| + * incoming messages.
|
| + */
|
| +remoting.FallbackSignalStrategy.prototype.setIncomingStanzaCallback =
|
| + function(onIncomingStanzaCallback) {
|
| + this.onIncomingStanzaCallback_ = onIncomingStanzaCallback;
|
| + if (this.state_ == this.State.PRIMARY_PENDING ||
|
| + this.state_ == this.State.PRIMARY_SUCCEEDED) {
|
| + this.primary_.setIncomingStanzaCallback(onIncomingStanzaCallback);
|
| + } else if (this.state_ == this.State.SECONDARY_PENDING ||
|
| + this.state_ == this.State.SECONDARY_SUCCEEDED) {
|
| + this.secondary_.setIncomingStanzaCallback(onIncomingStanzaCallback);
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * @param {string} server
|
| + * @param {string} username
|
| + * @param {string} authToken
|
| + */
|
| +remoting.FallbackSignalStrategy.prototype.connect =
|
| + function(server, username, authToken) {
|
| + base.debug.assert(this.state_ == this.State.NOT_CONNECTED);
|
| + this.server_ = server;
|
| + this.username_ = username;
|
| + this.authToken_ = authToken;
|
| + this.state_ = this.State.PRIMARY_PENDING;
|
| + this.primary_.setIncomingStanzaCallback(this.onIncomingStanzaCallback_);
|
| + this.primary_.connect(server, username, authToken);
|
| + this.primaryConnectTimerId_ =
|
| + window.setTimeout(this.onPrimaryTimeout_.bind(this),
|
| + this.PRIMARY_CONNECT_TIMEOUT_MS_);
|
| +};
|
| +
|
| +/**
|
| + * Sends a message. Can be called only in CONNECTED state.
|
| + * @param {string} message
|
| + */
|
| +remoting.FallbackSignalStrategy.prototype.sendMessage = function(message) {
|
| + this.getConnectedSignalStrategy_().sendMessage(message);
|
| +};
|
| +
|
| +/** @return {remoting.SignalStrategy.State} Current state */
|
| +remoting.FallbackSignalStrategy.prototype.getState = function() {
|
| + return (this.externalState_ === null)
|
| + ? remoting.SignalStrategy.State.NOT_CONNECTED
|
| + : this.externalState_;
|
| +};
|
| +
|
| +/** @return {remoting.Error} Error when in FAILED state. */
|
| +remoting.FallbackSignalStrategy.prototype.getError = function() {
|
| + base.debug.assert(this.state_ == this.State.SECONDARY_FAILED);
|
| + base.debug.assert(
|
| + this.secondary_.getState() == remoting.SignalStrategy.State.FAILED);
|
| + return this.secondary_.getError();
|
| +};
|
| +
|
| +/** @return {string} Current JID when in CONNECTED state. */
|
| +remoting.FallbackSignalStrategy.prototype.getJid = function() {
|
| + return this.getConnectedSignalStrategy_().getJid();
|
| +};
|
| +
|
| +/**
|
| + * @return {remoting.SignalStrategy} The active signal strategy, if the
|
| + * connection has succeeded.
|
| + * @private
|
| + */
|
| +remoting.FallbackSignalStrategy.prototype.getConnectedSignalStrategy_ =
|
| + function() {
|
| + if (this.state_ == this.State.PRIMARY_SUCCEEDED) {
|
| + base.debug.assert(
|
| + this.primary_.getState() == remoting.SignalStrategy.State.CONNECTED);
|
| + return this.primary_;
|
| + } else if (this.state_ == this.State.SECONDARY_SUCCEEDED) {
|
| + base.debug.assert(
|
| + this.secondary_.getState() == remoting.SignalStrategy.State.CONNECTED);
|
| + return this.secondary_;
|
| + } else {
|
| + base.debug.assert(
|
| + false,
|
| + 'getConnectedSignalStrategy called in unconnected state');
|
| + return null;
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * @param {remoting.SignalStrategy.State} state
|
| + * @private
|
| + */
|
| +remoting.FallbackSignalStrategy.prototype.onPrimaryStateChanged_ =
|
| + function(state) {
|
| + switch (state) {
|
| + case remoting.SignalStrategy.State.CONNECTED:
|
| + if (this.state_ == this.State.PRIMARY_PENDING) {
|
| + window.clearTimeout(this.primaryConnectTimerId_);
|
| + this.onProgressCallback_(
|
| + remoting.FallbackSignalStrategy.Progress.PRIMARY_SUCCEEDED);
|
| + this.state_ = this.State.PRIMARY_SUCCEEDED;
|
| + } else {
|
| + this.onProgressCallback_(
|
| + remoting.FallbackSignalStrategy.Progress.PRIMARY_SUCCEEDED_LATE);
|
| + }
|
| + break;
|
| +
|
| + case remoting.SignalStrategy.State.FAILED:
|
| + if (this.state_ == this.State.PRIMARY_PENDING) {
|
| + window.clearTimeout(this.primaryConnectTimerId_);
|
| + this.onProgressCallback_(
|
| + remoting.FallbackSignalStrategy.Progress.PRIMARY_FAILED);
|
| + this.connectSecondary_();
|
| + } else {
|
| + this.onProgressCallback_(
|
| + remoting.FallbackSignalStrategy.Progress.PRIMARY_FAILED_LATE);
|
| + }
|
| + return; // Don't notify the external callback
|
| +
|
| + case remoting.SignalStrategy.State.CLOSED:
|
| + this.state_ = this.State.CLOSED;
|
| + break;
|
| + }
|
| +
|
| + this.notifyExternalCallback_(state);
|
| +};
|
| +
|
| +/**
|
| + * @param {remoting.SignalStrategy.State} state
|
| + * @private
|
| + */
|
| +remoting.FallbackSignalStrategy.prototype.onSecondaryStateChanged_ =
|
| + function(state) {
|
| + switch (state) {
|
| + case remoting.SignalStrategy.State.CONNECTED:
|
| + this.onProgressCallback_(
|
| + remoting.FallbackSignalStrategy.Progress.SECONDARY_SUCCEEDED);
|
| + this.state_ = this.State.SECONDARY_SUCCEEDED;
|
| + break;
|
| +
|
| + case remoting.SignalStrategy.State.FAILED:
|
| + this.onProgressCallback_(
|
| + remoting.FallbackSignalStrategy.Progress.SECONDARY_FAILED);
|
| + this.state_ = this.State.SECONDARY_FAILED;
|
| + break;
|
| +
|
| + case remoting.SignalStrategy.State.CLOSED:
|
| + this.state_ = this.State.CLOSED;
|
| + break;
|
| + }
|
| +
|
| + this.notifyExternalCallback_(state);
|
| +};
|
| +
|
| +/**
|
| + * Notify the external callback of a change in state if it's consistent with
|
| + * the allowed state transitions (ie, if it represents a later stage in the
|
| + * connection process). Suppress state transitions that would violate this,
|
| + * for example a CONNECTING -> NOT_CONNECTED transition when we switch from
|
| + * the primary to the secondary signal strategy.
|
| + *
|
| + * @param {remoting.SignalStrategy.State} state
|
| + * @private
|
| + */
|
| +remoting.FallbackSignalStrategy.prototype.notifyExternalCallback_ =
|
| + function(state) {
|
| + if (this.externalState_ === null || state > this.externalState_) {
|
| + this.externalState_ = state;
|
| + this.onStateChangedCallback_(state);
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * @private
|
| + */
|
| +remoting.FallbackSignalStrategy.prototype.connectSecondary_ = function() {
|
| + base.debug.assert(this.state_ == this.State.PRIMARY_PENDING);
|
| + base.debug.assert(this.server_ != '');
|
| + base.debug.assert(this.username_ != '');
|
| + base.debug.assert(this.authToken_ != '');
|
| +
|
| + this.state_ = this.State.SECONDARY_PENDING;
|
| + this.primary_.setIncomingStanzaCallback(null);
|
| + this.secondary_.setIncomingStanzaCallback(this.onIncomingStanzaCallback_);
|
| + this.secondary_.connect(this.server_, this.username_, this.authToken_);
|
| +};
|
| +
|
| +/**
|
| + * @private
|
| + */
|
| +remoting.FallbackSignalStrategy.prototype.onPrimaryTimeout_ = function() {
|
| + this.onProgressCallback_(
|
| + remoting.FallbackSignalStrategy.Progress.PRIMARY_TIMED_OUT);
|
| + this.connectSecondary_();
|
| +};
|
|
|