Commit 79a9a66e authored by kelvinp's avatar kelvinp Committed by Commit bot

[Webapp Refactor] Cleans up the ClientSession.EventHandler interface.

This CL provides a cleaner way to report session state changes with the following:
1. Removes onError() callback on ClientSession Handler.  Instead, if an error
   is encountered before the session connects, onConnectionFailed() will be called,
   and similarly, onDisconnected() will be called for errors encountered after
   a session is connected.
2. Removes the sessionStateChanged event on clientSession, so session state
   are reported consistently through the ClientSession.EventHandler interface.

BUG=477522

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

Cr-Commit-Position: refs/heads/master@{#326853}
parent ea69e722
...@@ -140,12 +140,12 @@ remoting.AppRemotingActivity.prototype.onAppHostResponse_ = ...@@ -140,12 +140,12 @@ remoting.AppRemotingActivity.prototype.onAppHostResponse_ =
session.connect(host, credentialsProvider); session.connect(host, credentialsProvider);
}); });
} else if (response && response.status == 'pending') { } else if (response && response.status == 'pending') {
this.onError(new remoting.Error( this.onConnectionFailed(new remoting.Error(
remoting.Error.Tag.SERVICE_UNAVAILABLE)); remoting.Error.Tag.SERVICE_UNAVAILABLE));
} }
} else { } else {
console.error('Invalid "runApplication" response from server.'); console.error('Invalid "runApplication" response from server.');
this.onError(remoting.Error.fromHttpStatus(xhrResponse.status)); this.onConnectionFailed(remoting.Error.fromHttpStatus(xhrResponse.status));
} }
}; };
...@@ -166,28 +166,36 @@ remoting.AppRemotingActivity.prototype.onConnected = function(connectionInfo) { ...@@ -166,28 +166,36 @@ remoting.AppRemotingActivity.prototype.onConnected = function(connectionInfo) {
} }
}; };
remoting.AppRemotingActivity.prototype.onDisconnected = function() { /**
* @param {remoting.Error} error
*/
remoting.AppRemotingActivity.prototype.onDisconnected = function(error) {
if (error.isNone()) {
chrome.app.window.current().close();
} else {
this.showErrorMessage_(error);
}
this.cleanup_(); this.cleanup_();
chrome.app.window.current().close();
}; };
/** /**
* @param {!remoting.Error} error * @param {!remoting.Error} error
*/ */
remoting.AppRemotingActivity.prototype.onConnectionFailed = function(error) { remoting.AppRemotingActivity.prototype.onConnectionFailed = function(error) {
this.onError(error); remoting.LoadingWindow.close();
this.showErrorMessage_(error);
this.cleanup_();
}; };
/** /**
* @param {!remoting.Error} error The error to be localized and displayed. * @param {!remoting.Error} error The error to be localized and displayed.
* @private
*/ */
remoting.AppRemotingActivity.prototype.onError = function(error) { remoting.AppRemotingActivity.prototype.showErrorMessage_ = function(error) {
console.error('Connection failed: ' + error.toString()); console.error('Connection failed: ' + error.toString());
remoting.LoadingWindow.close();
remoting.MessageWindow.showErrorMessage( remoting.MessageWindow.showErrorMessage(
chrome.i18n.getMessage(/*i18n-content*/'CONNECTION_FAILED'), chrome.i18n.getMessage(/*i18n-content*/'CONNECTION_FAILED'),
chrome.i18n.getMessage(error.getTag())); chrome.i18n.getMessage(error.getTag()));
this.cleanup_();
}; };
})(); })();
...@@ -88,17 +88,15 @@ remoting.ClientSession = function(plugin, signalStrategy, listener) { ...@@ -88,17 +88,15 @@ remoting.ClientSession = function(plugin, signalStrategy, listener) {
/** @enum {string} */ /** @enum {string} */
remoting.ClientSession.Events = { remoting.ClientSession.Events = {
stateChanged: 'stateChanged', // deprecated. videoChannelStateChanged: 'videoChannelStateChanged'
videoChannelStateChanged: 'videoChannelStateChanged',
}; };
/** /**
* @interface * @interface
* [START]-------> [onConnected] ------> [onDisconnected] * [START]-------> [onConnected] ------> [onDisconnected]
* | | * |
* |-----> [OnConnectionFailed] |----> [onError] * |-----> [OnConnectionFailed]
* *
* TODO(kelvinp): Route session state changes through this interface.
*/ */
remoting.ClientSession.EventHandler = function() {}; remoting.ClientSession.EventHandler = function() {};
...@@ -112,7 +110,7 @@ remoting.ClientSession.EventHandler.prototype.onConnectionFailed = ...@@ -112,7 +110,7 @@ remoting.ClientSession.EventHandler.prototype.onConnectionFailed =
/** /**
* Called when a new session has been connected. The |connectionInfo| will be * Called when a new session has been connected. The |connectionInfo| will be
* valid until onDisconnected() or onError() is called. * valid until onDisconnected() is called.
* *
* @param {!remoting.ConnectionInfo} connectionInfo * @param {!remoting.ConnectionInfo} connectionInfo
*/ */
...@@ -121,14 +119,12 @@ remoting.ClientSession.EventHandler.prototype.onConnected = ...@@ -121,14 +119,12 @@ remoting.ClientSession.EventHandler.prototype.onConnected =
/** /**
* Called when the current session has been disconnected. * Called when the current session has been disconnected.
*
* @param {!remoting.Error} reason Reason that the session is disconnected.
* Set to remoting.Error.none() if there is no error.
*/ */
remoting.ClientSession.EventHandler.prototype.onDisconnected = function() {}; remoting.ClientSession.EventHandler.prototype.onDisconnected =
function(reason) {};
/**
* Called when an error needs to be displayed to the user.
* @param {!remoting.Error} error
*/
remoting.ClientSession.EventHandler.prototype.onError = function(error) {};
// Note that the positive values in both of these enums are copied directly // Note that the positive values in both of these enums are copied directly
// from connection_to_host.h and must be kept in sync. Code in // from connection_to_host.h and must be kept in sync. Code in
...@@ -165,19 +161,6 @@ remoting.ClientSession.State.fromString = function(state) { ...@@ -165,19 +161,6 @@ remoting.ClientSession.State.fromString = function(state) {
return remoting.ClientSession.State[state]; return remoting.ClientSession.State[state];
}; };
/**
@param {remoting.ClientSession.State} current
@param {remoting.ClientSession.State} previous
@constructor
*/
remoting.ClientSession.StateEvent = function(current, previous) {
/** @type {remoting.ClientSession.State} */
this.previous = previous
/** @type {remoting.ClientSession.State} */
this.current = current;
};
/** @enum {number} */ /** @enum {number} */
remoting.ClientSession.ConnectionError = { remoting.ClientSession.ConnectionError = {
UNKNOWN: -1, UNKNOWN: -1,
...@@ -285,6 +268,10 @@ remoting.ClientSession.prototype.connect = function(host, credentialsProvider) { ...@@ -285,6 +268,10 @@ remoting.ClientSession.prototype.connect = function(host, credentialsProvider) {
* @return {void} Nothing. * @return {void} Nothing.
*/ */
remoting.ClientSession.prototype.disconnect = function(error) { remoting.ClientSession.prototype.disconnect = function(error) {
if (this.isFinished()) {
return;
}
this.sendIq_( this.sendIq_(
'<cli:iq ' + '<cli:iq ' +
'to="' + this.host_.jabberId + '" ' + 'to="' + this.host_.jabberId + '" ' +
...@@ -551,7 +538,7 @@ remoting.ClientSession.prototype.notifyStateChanges_ = ...@@ -551,7 +538,7 @@ remoting.ClientSession.prototype.notifyStateChanges_ =
case remoting.ClientSession.State.CLOSED: case remoting.ClientSession.State.CLOSED:
console.log('Connection closed.'); console.log('Connection closed.');
this.listener_.onDisconnected(); this.listener_.onDisconnected(remoting.Error.none());
break; break;
case remoting.ClientSession.State.CONNECTION_CANCELED: case remoting.ClientSession.State.CONNECTION_CANCELED:
...@@ -566,20 +553,12 @@ remoting.ClientSession.prototype.notifyStateChanges_ = ...@@ -566,20 +553,12 @@ remoting.ClientSession.prototype.notifyStateChanges_ =
case remoting.ClientSession.State.CONNECTION_DROPPED: case remoting.ClientSession.State.CONNECTION_DROPPED:
error = this.getError(); error = this.getError();
console.error('Connection dropped: ' + error.toString()); console.error('Connection dropped: ' + error.toString());
this.listener_.onError(error); this.listener_.onDisconnected(error);
break; break;
default: default:
console.error('Unexpected client plugin state: ' + newState); console.error('Unexpected client plugin state: ' + newState);
// This should only happen if the web-app and client plugin get out of
// sync, and even then the version check should ensure compatibility.
this.listener_.onError(
new remoting.Error(remoting.Error.Tag.MISSING_PLUGIN));
} }
this.raiseEvent(remoting.ClientSession.Events.stateChanged,
new remoting.ClientSession.StateEvent(newState, oldState)
);
}; };
/** /**
......
...@@ -20,7 +20,7 @@ var listener; ...@@ -20,7 +20,7 @@ var listener;
var SessionListener = function() {}; var SessionListener = function() {};
SessionListener.prototype.onConnectionFailed = function(error) {}; SessionListener.prototype.onConnectionFailed = function(error) {};
SessionListener.prototype.onConnected = function(connectionInfo) {}; SessionListener.prototype.onConnected = function(connectionInfo) {};
SessionListener.prototype.onDisconnected = function() {}; SessionListener.prototype.onDisconnected = function(reason) {};
SessionListener.prototype.onError = function(error) {}; SessionListener.prototype.onError = function(error) {};
QUnit.module('ClientSessionFactory', { QUnit.module('ClientSessionFactory', {
......
...@@ -22,8 +22,7 @@ var logToServerStub; ...@@ -22,8 +22,7 @@ var logToServerStub;
var SessionListener = function() {}; var SessionListener = function() {};
SessionListener.prototype.onConnectionFailed = function(error) {}; SessionListener.prototype.onConnectionFailed = function(error) {};
SessionListener.prototype.onConnected = function(connectionInfo) {}; SessionListener.prototype.onConnected = function(connectionInfo) {};
SessionListener.prototype.onDisconnected = function() {}; SessionListener.prototype.onDisconnected = function(error) {};
SessionListener.prototype.onError = function(error) {};
/** /**
* @param {remoting.ClientSession.ConnectionError=} opt_error * @param {remoting.ClientSession.ConnectionError=} opt_error
...@@ -142,9 +141,9 @@ QUnit.test( ...@@ -142,9 +141,9 @@ QUnit.test(
var State = remoting.ClientSession.State; var State = remoting.ClientSession.State;
return connect().then(function() { return connect().then(function() {
var onError = sinon.stub(listener, 'onError'); var onDisconnected = sinon.stub(listener, 'onDisconnected');
session.disconnect(new remoting.Error(remoting.Error.Tag.P2P_FAILURE)); session.disconnect(new remoting.Error(remoting.Error.Tag.P2P_FAILURE));
assert.equal(onError.callCount, 1); assert.equal(onDisconnected.callCount, 1);
assert.equal(logToServerStub.args[2][0], State.CONNECTION_DROPPED); assert.equal(logToServerStub.args[2][0], State.CONNECTION_DROPPED);
}); });
}); });
......
...@@ -88,9 +88,11 @@ remoting.DesktopRemotingActivity.prototype.onConnected = ...@@ -88,9 +88,11 @@ remoting.DesktopRemotingActivity.prototype.onConnected =
this.parentActivity_.onConnected(connectionInfo); this.parentActivity_.onConnected(connectionInfo);
}; };
remoting.DesktopRemotingActivity.prototype.onDisconnected = function() { remoting.DesktopRemotingActivity.prototype.onDisconnected = function(reason) {
this.parentActivity_.onDisconnected(); if (this.handleError_(reason)) {
this.dispose(); return;
}
this.parentActivity_.onDisconnected(reason);
}; };
/** /**
...@@ -98,24 +100,24 @@ remoting.DesktopRemotingActivity.prototype.onDisconnected = function() { ...@@ -98,24 +100,24 @@ remoting.DesktopRemotingActivity.prototype.onDisconnected = function() {
*/ */
remoting.DesktopRemotingActivity.prototype.onConnectionFailed = remoting.DesktopRemotingActivity.prototype.onConnectionFailed =
function(error) { function(error) {
if (this.handleError_(error)) {
return;
}
this.parentActivity_.onConnectionFailed(error); this.parentActivity_.onConnectionFailed(error);
}; };
/** /**
* @param {!remoting.Error} error The error to be localized and displayed. * @param {!remoting.Error} error The error to be localized and displayed.
* @return {boolean} returns true if the error is handled.
* @private
*/ */
remoting.DesktopRemotingActivity.prototype.onError = function(error) { remoting.DesktopRemotingActivity.prototype.handleError_ = function(error) {
console.error('Connection failed: ' + error.toString());
if (error.hasTag(remoting.Error.Tag.AUTHENTICATION_FAILED)) { if (error.hasTag(remoting.Error.Tag.AUTHENTICATION_FAILED)) {
remoting.setMode(remoting.AppMode.HOME); remoting.setMode(remoting.AppMode.HOME);
remoting.handleAuthFailureAndRelaunch(); remoting.handleAuthFailureAndRelaunch();
return; return true;
} }
return false;
this.parentActivity_.onError(error);
this.dispose();
}; };
remoting.DesktopRemotingActivity.prototype.dispose = function() { remoting.DesktopRemotingActivity.prototype.dispose = function() {
......
...@@ -74,7 +74,9 @@ remoting.It2MeActivity.prototype.stop = function() { ...@@ -74,7 +74,9 @@ remoting.It2MeActivity.prototype.stop = function() {
* @param {!remoting.Error} error * @param {!remoting.Error} error
*/ */
remoting.It2MeActivity.prototype.onConnectionFailed = function(error) { remoting.It2MeActivity.prototype.onConnectionFailed = function(error) {
this.onError(error); this.showErrorMessage_(error);
base.dispose(this.desktopActivity_);
this.desktopActivity_ = null;
}; };
/** /**
...@@ -84,14 +86,22 @@ remoting.It2MeActivity.prototype.onConnected = function(connectionInfo) { ...@@ -84,14 +86,22 @@ remoting.It2MeActivity.prototype.onConnected = function(connectionInfo) {
this.accessCodeDialog_.inputField().value = ''; this.accessCodeDialog_.inputField().value = '';
}; };
remoting.It2MeActivity.prototype.onDisconnected = function() { remoting.It2MeActivity.prototype.onDisconnected = function(error) {
this.showFinishDialog_(remoting.AppMode.CLIENT_SESSION_FINISHED_IT2ME); if (error.isNone()) {
this.showFinishDialog_(remoting.AppMode.CLIENT_SESSION_FINISHED_IT2ME);
} else {
this.showErrorMessage_(error);
}
base.dispose(this.desktopActivity_);
this.desktopActivity_ = null;
}; };
/** /**
* @param {!remoting.Error} error * @param {!remoting.Error} error
* @private
*/ */
remoting.It2MeActivity.prototype.onError = function(error) { remoting.It2MeActivity.prototype.showErrorMessage_ = function(error) {
var errorDiv = document.getElementById('connect-error-message'); var errorDiv = document.getElementById('connect-error-message');
l10n.localizeElementFromTag(errorDiv, error.getTag()); l10n.localizeElementFromTag(errorDiv, error.getTag());
this.showFinishDialog_(remoting.AppMode.CLIENT_CONNECT_FAILED_IT2ME); this.showFinishDialog_(remoting.AppMode.CLIENT_CONNECT_FAILED_IT2ME);
......
...@@ -140,15 +140,18 @@ remoting.Me2MeActivity.prototype.onConnectionFailed = function(error) { ...@@ -140,15 +140,18 @@ remoting.Me2MeActivity.prototype.onConnectionFailed = function(error) {
that.connect_(false); that.connect_(false);
return; return;
} }
that.onError(error); that.showErrorMessage_(error);
}; };
this.retryOnHostOffline_ = false; this.retryOnHostOffline_ = false;
// The plugin will be re-created when the host finished refreshing // The plugin will be re-created when the host finished refreshing
remoting.hostList.refresh(onHostListRefresh); remoting.hostList.refresh(onHostListRefresh);
} else { } else if (!error.isNone()) {
this.onError(error); this.showErrorMessage_(error);
} }
base.dispose(this.desktopActivity_);
this.desktopActivity_ = null;
}; };
/** /**
...@@ -172,14 +175,23 @@ remoting.Me2MeActivity.prototype.onConnected = function(connectionInfo) { ...@@ -172,14 +175,23 @@ remoting.Me2MeActivity.prototype.onConnected = function(connectionInfo) {
connectionInfo.session()); connectionInfo.session());
}; };
remoting.Me2MeActivity.prototype.onDisconnected = function() { remoting.Me2MeActivity.prototype.onDisconnected = function(error) {
this.showFinishDialog_(remoting.AppMode.CLIENT_SESSION_FINISHED_ME2ME); if (error.isNone()) {
this.showFinishDialog_(remoting.AppMode.CLIENT_SESSION_FINISHED_ME2ME);
} else {
this.reconnector_.onConnectionDropped(error);
this.showErrorMessage_(error);
}
base.dispose(this.desktopActivity_);
this.desktopActivity_ = null;
}; };
/** /**
* @param {!remoting.Error} error * @param {!remoting.Error} error
* @private
*/ */
remoting.Me2MeActivity.prototype.onError = function(error) { remoting.Me2MeActivity.prototype.showErrorMessage_ = function(error) {
var errorDiv = document.getElementById('connect-error-message'); var errorDiv = document.getElementById('connect-error-message');
l10n.localizeElementFromTag(errorDiv, error.getTag()); l10n.localizeElementFromTag(errorDiv, error.getTag());
this.showFinishDialog_(remoting.AppMode.CLIENT_CONNECT_FAILED_ME2ME); this.showFinishDialog_(remoting.AppMode.CLIENT_CONNECT_FAILED_ME2ME);
......
...@@ -49,11 +49,9 @@ remoting.SmartReconnector = ...@@ -49,11 +49,9 @@ remoting.SmartReconnector =
var Events = remoting.ClientSession.Events; var Events = remoting.ClientSession.Events;
/** @private */ /** @private */
this.eventHooks_ = new base.Disposables( this.eventHook_ =
new base.EventHook(clientSession, Events.stateChanged,
this.stateChanged_.bind(this)),
new base.EventHook(clientSession, Events.videoChannelStateChanged, new base.EventHook(clientSession, Events.videoChannelStateChanged,
this.videoChannelStateChanged_.bind(this))); this.videoChannelStateChanged_.bind(this));
}; };
// The online event only means the network adapter is enabled, but // The online event only means the network adapter is enabled, but
...@@ -80,18 +78,15 @@ remoting.SmartReconnector.prototype.reconnectAsync_ = function() { ...@@ -80,18 +78,15 @@ remoting.SmartReconnector.prototype.reconnectAsync_ = function() {
}; };
/** /**
* @param {remoting.ClientSession.StateEvent=} event * @param {!remoting.Error} reason
*/ */
remoting.SmartReconnector.prototype.stateChanged_ = function(event) { remoting.SmartReconnector.prototype.onConnectionDropped = function(reason) {
var State = remoting.ClientSession.State; this.cancelPending_();
if (event.previous === State.CONNECTED && event.current === State.FAILED) { if (navigator.onLine) {
this.cancelPending_(); this.reconnect_();
if (navigator.onLine) { } else {
this.reconnect_(); this.pending_ = new base.DomEventHook(
} else { window, 'online', this.reconnectAsync_.bind(this), false);
this.pending_ = new base.DomEventHook(
window, 'online', this.reconnectAsync_.bind(this), false);
}
} }
}; };
...@@ -121,8 +116,8 @@ remoting.SmartReconnector.prototype.cancelPending_ = function() { ...@@ -121,8 +116,8 @@ remoting.SmartReconnector.prototype.cancelPending_ = function() {
remoting.SmartReconnector.prototype.dispose = function() { remoting.SmartReconnector.prototype.dispose = function() {
this.cancelPending_(); this.cancelPending_();
base.dispose(this.eventHooks_); base.dispose(this.eventHook_);
this.eventHooks_ = null; this.eventHook_ = null;
}; };
})(); })();
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