Commit e45afacc authored by kelvinp's avatar kelvinp Committed by Commit bot

[Webapp Refactor] Reliably cancels a connection.

Prior to this CL, clicking cancel on the connecting dialog simply
returns the user to the home screen, without disconnecting the session or
cleaning up any related resources.

This CL provides a cleaner way to cancel a session with by implementing
remoting.ConnectingDialog which calls stop() on the activity.

BUG=477522

Review URL: https://codereview.chromium.org/1101613003

Cr-Commit-Position: refs/heads/master@{#326926}
parent 375d6d1d
......@@ -56,17 +56,17 @@ remoting.InputDialog.prototype.show = function() {
/** @return {HTMLElement} */
remoting.InputDialog.prototype.inputField = function() {
return this.inputField_;
}
};
/** @private */
remoting.InputDialog.prototype.onSubmit_ = function() {
this.deferred_.resolve(this.inputField_.value);
}
};
/** @private */
remoting.InputDialog.prototype.onCancel_ = function() {
this.deferred_.reject(new remoting.Error(remoting.Error.Tag.CANCELLED));
}
};
/**
* @param {function():void} handler
......@@ -97,7 +97,9 @@ remoting.InputDialog.prototype.createFormEventHandler_ = function(handler) {
* @param {remoting.AppMode} mode
* @param {HTMLElement} primaryButton
* @param {HTMLElement=} opt_secondaryButton
*
* @constructor
* @implements {base.Disposable}
*/
remoting.MessageDialog = function(mode, primaryButton, opt_secondaryButton) {
/** @private @const */
......@@ -136,6 +138,15 @@ remoting.MessageDialog.prototype.show = function() {
return this.deferred_.promise();
};
remoting.MessageDialog.prototype.dispose = function() {
base.dispose(this.eventHooks_);
this.eventHooks_ = null;
if (this.deferred_) {
this.deferred_.reject(new remoting.Error(remoting.Error.Tag.CANCELLED));
}
this.deferred_ = null;
};
/**
* @param {remoting.MessageDialog.Result} result
* @return {Function}
......@@ -143,9 +154,35 @@ remoting.MessageDialog.prototype.show = function() {
*/
remoting.MessageDialog.prototype.onClicked_ = function(result) {
this.deferred_.resolve(result);
base.dispose(this.eventHooks_);
this.eventHooks_ = null;
this.deferred_ = null;
this.dispose();
};
/**
* @param {Function} cancelCallback The callback to invoke when the user clicks
* on the cancel button.
* @constructor
*/
remoting.ConnectingDialog = function(cancelCallback) {
/** @private */
this.dialog_ = new remoting.MessageDialog(
remoting.AppMode.CLIENT_CONNECTING,
document.getElementById('cancel-connect-button'));
/** @private */
this.onCancel_ = cancelCallback;
};
remoting.ConnectingDialog.prototype.show = function() {
var that = this;
this.dialog_.show().then(function() {
remoting.setMode(remoting.AppMode.HOME);
that.onCancel_();
// The promise rejects when the dialog is hidden. Don't report that as error.
}).catch(remoting.Error.handler(base.doNothing));
};
remoting.ConnectingDialog.prototype.hide = function() {
this.dialog_.dispose();
};
})();
......
......@@ -269,6 +269,8 @@ remoting.ClientSession.prototype.connect = function(host, credentialsProvider) {
*/
remoting.ClientSession.prototype.disconnect = function(error) {
if (this.isFinished()) {
// Do not send the session-terminate Iq if disconnect() is already called or
// if it is initiated by the host.
return;
}
......
......@@ -11,13 +11,6 @@ remoting.initElementEventHandlers = function() {
var goHome = function() {
remoting.setMode(remoting.AppMode.HOME);
};
var goFinishedIT2Me = function() {
if (remoting.currentMode == remoting.AppMode.CLIENT_CONNECT_FAILED_IT2ME) {
remoting.setMode(remoting.AppMode.CLIENT_UNCONNECTED);
} else {
goHome();
}
};
/** @type {Array<{event: string, id: string, fn: function(Event):void}>} */
var it2me_actions = [
{ event: 'click', id: 'cancel-share-button', fn: remoting.cancelShare },
......@@ -44,7 +37,6 @@ remoting.initElementEventHandlers = function() {
];
/** @type {Array<{event: string, id: string, fn: function(Event):void}>} */
var auth_actions = [
{ event: 'click', id: 'cancel-connect-button', fn: goHome },
{ event: 'click', id: 'sign-out', fn:remoting.signOut },
{ event: 'click', id: 'token-refresh-error-ok', fn: goHome },
{ event: 'click', id: 'token-refresh-error-sign-in',
......
......@@ -209,7 +209,7 @@ remoting.DesktopRemoting.prototype.disconnect_ = function() {
remoting.DesktopRemoting.prototype.connectMe2Me_ = function(hostId) {
var host = remoting.hostList.getHostForId(hostId);
base.dispose(this.activity_);
this.activity_ = new remoting.Me2MeActivity(host);
this.activity_ = new remoting.Me2MeActivity(host, remoting.hostList);
this.activity_.start();
};
......
......@@ -30,6 +30,9 @@ remoting.DesktopRemotingActivity = function(parentActivity) {
remoting.app_capabilities());
/** @private {remoting.ClientSession} */
this.session_ = null;
/** @private {remoting.ConnectingDialog} */
this.connectingDialog_ =
new remoting.ConnectingDialog(parentActivity.stop.bind(parentActivity));
};
/**
......@@ -49,7 +52,10 @@ remoting.DesktopRemotingActivity.prototype.start =
session.logHostOfflineErrors(!opt_suppressOfflineError);
session.getLogger().setHostVersion(host.hostVersion);
session.connect(host, credentialsProvider);
});
}).catch(remoting.Error.handler(
function(/** !remoting.Error */ error) {
that.parentActivity_.onConnectionFailed(error);
}));
};
remoting.DesktopRemotingActivity.prototype.stop = function() {
......@@ -64,6 +70,7 @@ remoting.DesktopRemotingActivity.prototype.stop = function() {
*/
remoting.DesktopRemotingActivity.prototype.onConnected =
function(connectionInfo) {
this.connectingDialog_.hide();
remoting.setMode(remoting.AppMode.IN_SESSION);
if (!base.isAppsV2()) {
remoting.toolbar.center();
......@@ -126,6 +133,7 @@ remoting.DesktopRemotingActivity.prototype.dispose = function() {
this.connectedView_ = null;
base.dispose(this.session_);
this.session_ = null;
this.connectingDialog_.hide();
};
/** @return {remoting.DesktopConnectedView} */
......@@ -140,4 +148,9 @@ remoting.DesktopRemotingActivity.prototype.getSession = function() {
return this.session_;
};
/** @return {remoting.ConnectingDialog} */
remoting.DesktopRemotingActivity.prototype.getConnectingDialog = function() {
return this.connectingDialog_;
};
})();
......@@ -44,8 +44,11 @@ remoting.It2MeActivity.prototype.dispose = function() {
remoting.It2MeActivity.prototype.start = function() {
var that = this;
this.desktopActivity_ = new remoting.DesktopRemotingActivity(this);
remoting.app.setConnectionMode(remoting.Application.Mode.IT2ME);
this.accessCodeDialog_.show().then(function(/** string */ accessCode) {
remoting.setMode(remoting.AppMode.CLIENT_CONNECTING);
that.desktopActivity_.getConnectingDialog().show();
return that.verifyAccessCode_(accessCode);
}).then(function() {
return remoting.identity.getToken();
......@@ -55,7 +58,7 @@ remoting.It2MeActivity.prototype.start = function() {
return that.onHostInfo_(response);
}).then(function(/** remoting.Host */ host) {
that.connect_(host);
}).catch(function(/** remoting.Error */ error) {
}).catch(remoting.Error.handler(function(/** remoting.Error */ error) {
if (error.hasTag(remoting.Error.Tag.CANCELLED)) {
remoting.setMode(remoting.AppMode.HOME);
} else {
......@@ -63,7 +66,7 @@ remoting.It2MeActivity.prototype.start = function() {
l10n.localizeElementFromTag(errorDiv, error.getTag());
remoting.setMode(remoting.AppMode.CLIENT_CONNECT_FAILED_IT2ME);
}
});
}));
};
remoting.It2MeActivity.prototype.stop = function() {
......@@ -193,9 +196,6 @@ remoting.It2MeActivity.prototype.onHostInfo_ = function(xhrResponse) {
* @private
*/
remoting.It2MeActivity.prototype.connect_ = function(host) {
base.dispose(this.desktopActivity_);
this.desktopActivity_ = new remoting.DesktopRemotingActivity(this);
remoting.app.setConnectionMode(remoting.Application.Mode.IT2ME);
this.desktopActivity_.start(
host, new remoting.CredentialsProvider({ accessCode: this.passCode_ }));
};
......
......@@ -11,14 +11,17 @@ var remoting = remoting || {};
/**
* @param {remoting.Host} host
* @param {remoting.HostList} hostList
*
* @constructor
* @implements {remoting.Activity}
*/
remoting.Me2MeActivity = function(host) {
remoting.Me2MeActivity = function(host, hostList) {
/** @private */
this.host_ = host;
/** @private */
this.hostList_ = hostList;
/** @private */
this.pinDialog_ =
new remoting.PinDialog(document.getElementById('pin-dialog'), host);
/** @private */
......@@ -48,11 +51,11 @@ remoting.Me2MeActivity.prototype.start = function() {
return that.host_.options.load();
}).then(function() {
that.connect_(true);
}).catch(function(/** remoting.Error */ error) {
}).catch(remoting.Error.handler(function(/** remoting.Error */ error) {
if (error.hasTag(remoting.Error.Tag.CANCELLED)) {
remoting.setMode(remoting.AppMode.HOME);
}
});
}));
};
remoting.Me2MeActivity.prototype.stop = function() {
......@@ -69,9 +72,9 @@ remoting.Me2MeActivity.prototype.getDesktopActivity = function() {
* @private
*/
remoting.Me2MeActivity.prototype.connect_ = function(suppressHostOfflineError) {
remoting.setMode(remoting.AppMode.CLIENT_CONNECTING);
base.dispose(this.desktopActivity_);
this.desktopActivity_ = new remoting.DesktopRemotingActivity(this);
this.desktopActivity_.getConnectingDialog().show();
remoting.app.setConnectionMode(remoting.Application.Mode.ME2ME);
this.desktopActivity_.start(this.host_, this.createCredentialsProvider_(),
suppressHostOfflineError);
......@@ -106,16 +109,18 @@ remoting.Me2MeActivity.prototype.createCredentialsProvider_ = function() {
var requestPin = function(supportsPairing, onPinFetched) {
// Set time when PIN was requested.
var authStartTime = new Date().getTime();
that.desktopActivity_.getConnectingDialog().hide();
that.pinDialog_.show(supportsPairing).then(function(/** string */ pin) {
remoting.setMode(remoting.AppMode.CLIENT_CONNECTING);
// Done obtaining PIN information. Log time taken for PIN entry.
var logToServer = that.desktopActivity_.getSession().getLogger();
logToServer.setAuthTotalTime(new Date().getTime() - authStartTime);
onPinFetched(pin);
}).catch(function(/** remoting.Error */ error) {
}).catch(remoting.Error.handler(function(/** remoting.Error */ error) {
base.debug.assert(error.hasTag(remoting.Error.Tag.CANCELLED));
remoting.setMode(remoting.AppMode.HOME);
});
that.stop();
}));
};
return new remoting.CredentialsProvider({
......@@ -136,7 +141,7 @@ remoting.Me2MeActivity.prototype.onConnectionFailed = function(error) {
var onHostListRefresh = function(/** boolean */ success) {
if (success) {
// Get the host from the hostList for the refreshed JID.
that.host_ = remoting.hostList.getHostForId(that.host_.hostId);
that.host_ = that.hostList_.getHostForId(that.host_.hostId);
that.connect_(false);
return;
}
......@@ -145,7 +150,7 @@ remoting.Me2MeActivity.prototype.onConnectionFailed = function(error) {
this.retryOnHostOffline_ = false;
// The plugin will be re-created when the host finished refreshing
remoting.hostList.refresh(onHostListRefresh);
this.hostList_.refresh(onHostListRefresh);
} else if (!error.isNone()) {
this.showErrorMessage_(error);
}
......@@ -170,6 +175,7 @@ remoting.Me2MeActivity.prototype.onConnected = function(connectionInfo) {
base.dispose(this.reconnector_);
this.reconnector_ = new remoting.SmartReconnector(
this.desktopActivity_.getConnectingDialog(),
this.connect_.bind(this, false),
this.stop.bind(this),
connectionInfo.session());
......
......@@ -21,6 +21,7 @@ var remoting = remoting || {};
/**
* @constructor
* @param {remoting.ConnectingDialog} connectingDialog
* @param {function()} reconnectCallback
* @param {function()} disconnectCallback
* @param {remoting.ClientSession} clientSession This represents the current
......@@ -28,8 +29,8 @@ var remoting = remoting || {};
* connection state.
* @implements {base.Disposable}
*/
remoting.SmartReconnector =
function(reconnectCallback, disconnectCallback, clientSession) {
remoting.SmartReconnector = function(connectingDialog, reconnectCallback,
disconnectCallback, clientSession) {
/** @private */
this.reconnectCallback_ = reconnectCallback;
......@@ -47,6 +48,9 @@ remoting.SmartReconnector =
*/
this.pending_ = null;
/** @private */
this.connectingDialog_ = connectingDialog;
var Events = remoting.ClientSession.Events;
/** @private */
this.eventHook_ =
......@@ -66,13 +70,12 @@ var CONNECTION_TIMEOUT_MS = 10000;
remoting.SmartReconnector.prototype.reconnect_ = function() {
this.cancelPending_();
this.disconnectCallback_();
remoting.setMode(remoting.AppMode.CLIENT_CONNECTING);
this.reconnectCallback_();
};
remoting.SmartReconnector.prototype.reconnectAsync_ = function() {
this.cancelPending_();
remoting.setMode(remoting.AppMode.CLIENT_CONNECTING);
this.connectingDialog_.show();
this.pending_ =
new base.OneShotTimer(this.reconnect_.bind(this), RECONNECT_DELAY_MS);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment