summaryrefslogtreecommitdiffstats
path: root/remoting/webapp/client_screen.js
diff options
context:
space:
mode:
Diffstat (limited to 'remoting/webapp/client_screen.js')
-rw-r--r--remoting/webapp/client_screen.js506
1 files changed, 87 insertions, 419 deletions
diff --git a/remoting/webapp/client_screen.js b/remoting/webapp/client_screen.js
index a5922e1..1140dc7 100644
--- a/remoting/webapp/client_screen.js
+++ b/remoting/webapp/client_screen.js
@@ -13,93 +13,29 @@
var remoting = remoting || {};
/**
- * @type {remoting.ClientSession} The client session object, set once the
- * access code has been successfully verified.
- */
-remoting.clientSession = null;
-
-/**
- * @type {string} The normalized access code.
- */
-remoting.accessCode = '';
-
-/**
- * @type {string} The host's JID, returned by the server.
- */
-remoting.hostJid = '';
-
-/**
- * @type {string} For Me2Me connections, the id of the current host.
- */
-remoting.hostId = '';
-
-/**
- * @type {boolean} For Me2Me connections. Set to true if connection
- * must be retried on failure.
- */
-remoting.retryIfOffline = false;
-
-/**
- * @type {string} The host's public key, returned by the server.
- */
-remoting.hostPublicKey = '';
-
-/**
- * @type {XMLHttpRequest} The XHR object corresponding to the current
- * support-hosts request, if there is one outstanding.
- * @private
+ * @type {remoting.SessionConnector} The connector object, set when a connection
+ * is initiated.
*/
-remoting.supportHostsXhr_ = null;
+remoting.connector = null;
/**
- * @type {remoting.ClientSession.Mode?}
+ * @type {remoting.ClientSession} The client session object, set once the
+ * connector has invoked its onOk callback.
*/
-remoting.currentConnectionType = null;
+remoting.clientSession = null;
/**
- * Entry point for the 'connect' functionality. This function defers to the
- * WCS loader to call it back with an access token.
+ * Initiate an IT2Me connection.
*/
-remoting.connectIt2Me = function() {
- remoting.currentConnectionType = remoting.ClientSession.Mode.IT2ME;
- /** @param {string} token */
- var startWcsAndConnect = function(token) {
- remoting.wcsSandbox.setOnReady(
- connectIt2MeWithAccessToken_.bind(null, token));
- remoting.wcsSandbox.setOnError(remoting.showErrorMessage);
- remoting.wcsSandbox.setAccessToken(token);
- startAccessTokenRefreshTimer_();
- };
- remoting.identity.callWithToken(startWcsAndConnect,
- remoting.showErrorMessage);
-};
-
-/**
- * Cancel an incomplete connect operation.
- *
- * Note that this function is not currently used. It is here for reference
- * because we'll need to reinstate something very like it when we transition
- * to Apps v2 where we can no longer change the URL (which is what we do in
- * lieu of calling this function to ensure correct Reload behaviour).
- *
- * @return {void} Nothing.
-remoting.cancelConnect = function() {
- if (remoting.supportHostsXhr_) {
- remoting.supportHostsXhr_.abort();
- remoting.supportHostsXhr_ = null;
- }
- if (remoting.clientSession) {
- remoting.clientSession.removePlugin();
- remoting.clientSession = null;
- }
- if (remoting.currentConnectionType == remoting.ConnectionType.Me2Me) {
- remoting.initDaemonUi();
- } else {
- remoting.setMode(remoting.AppMode.HOME);
- document.getElementById('access-code-entry').value = '';
- }
+remoting.connectIT2Me = function() {
+ remoting.connector = new remoting.SessionConnector(
+ document.getElementById('session-mode'),
+ remoting.onConnected,
+ remoting.showErrorMessage);
+ var accessCode = document.getElementById('access-code-entry').value;
+ remoting.setMode(remoting.AppMode.CLIENT_CONNECTING);
+ remoting.connector.connectIT2Me(accessCode);
};
-*/
/**
* Update the remoting client layout in response to a resize event.
@@ -107,8 +43,9 @@ remoting.cancelConnect = function() {
* @return {void} Nothing.
*/
remoting.onResize = function() {
- if (remoting.clientSession)
+ if (remoting.clientSession) {
remoting.clientSession.onResize();
+ }
};
/**
@@ -117,8 +54,9 @@ remoting.onResize = function() {
* @return {void} Nothing.
*/
remoting.onVisibilityChanged = function() {
- if (remoting.clientSession)
+ if (remoting.clientSession) {
remoting.clientSession.pauseVideo(document.webkitHidden);
+ }
}
/**
@@ -127,16 +65,17 @@ remoting.onVisibilityChanged = function() {
* @return {void} Nothing.
*/
remoting.disconnect = function() {
- if (remoting.clientSession) {
- remoting.clientSession.disconnect(true);
- remoting.clientSession = null;
- console.log('Disconnected.');
- if (remoting.currentConnectionType == remoting.ClientSession.Mode.IT2ME) {
- remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_IT2ME);
- } else {
- remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_ME2ME);
- }
+ if (!remoting.clientSession) {
+ return;
}
+ if (remoting.clientSession.mode == remoting.ClientSession.Mode.IT2ME) {
+ remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_IT2ME);
+ } else {
+ remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_ME2ME);
+ }
+ remoting.clientSession.disconnect(true);
+ remoting.clientSession = null;
+ console.log('Disconnected.');
};
/**
@@ -164,178 +103,41 @@ remoting.sendPrintScreen = function() {
};
/**
- * If WCS was successfully loaded, proceed with the connection, otherwise
- * report an error.
- *
- * @param {string} token The OAuth2 access token.
- * @param {string} clientJid The full JID of the WCS client.
- * @return {void} Nothing.
- */
-function connectIt2MeWithAccessToken_(token, clientJid) {
- var accessCode = document.getElementById('access-code-entry').value;
- remoting.accessCode = normalizeAccessCode_(accessCode);
- // At present, only 12-digit access codes are supported, of which the first
- // 7 characters are the supportId.
- var kSupportIdLen = 7;
- var kHostSecretLen = 5;
- var kAccessCodeLen = kSupportIdLen + kHostSecretLen;
- if (remoting.accessCode.length != kAccessCodeLen) {
- console.error('Bad access code length');
- showConnectError_(remoting.Error.INVALID_ACCESS_CODE);
- } else {
- var supportId = remoting.accessCode.substring(0, kSupportIdLen);
- remoting.setMode(remoting.AppMode.CLIENT_CONNECTING);
- resolveSupportId(clientJid, supportId, token);
- }
-}
-
-/**
* Callback function called when the state of the client plugin changes. The
* current state is available via the |state| member variable.
*
* @param {number} oldState The previous state of the plugin.
* @param {number} newState The current state of the plugin.
*/
-// TODO(jamiewalch): Make this pass both the current and old states to avoid
-// race conditions.
function onClientStateChange_(oldState, newState) {
- if (!remoting.clientSession) {
- // If the connection has been cancelled, then we no longer have a reference
- // to the session object and should ignore any state changes.
- return;
- }
-
- // Clear the PIN on successful connection, or on error if we're not going to
- // automatically retry.
- var clearPin = false;
-
- if (newState == remoting.ClientSession.State.CREATED) {
- console.log('Created plugin');
-
- } else if (newState == remoting.ClientSession.State.BAD_PLUGIN_VERSION) {
- showConnectError_(remoting.Error.BAD_PLUGIN_VERSION);
-
- } else if (newState == remoting.ClientSession.State.CONNECTING) {
- console.log('Connecting as ' + remoting.identity.getCachedEmail());
-
- } else if (newState == remoting.ClientSession.State.INITIALIZING) {
- console.log('Initializing connection');
-
- } else if (newState == remoting.ClientSession.State.CONNECTED) {
- if (remoting.clientSession) {
- clearPin = true;
- setConnectionInterruptedButtonsText_();
- remoting.retryIfOffline = false;
- remoting.setMode(remoting.AppMode.IN_SESSION);
- remoting.toolbar.center();
- remoting.toolbar.preview();
- remoting.clipboard.startSession();
- updateStatistics_();
- }
-
- } else if (newState == remoting.ClientSession.State.CLOSED) {
- if (oldState == remoting.ClientSession.State.CONNECTED) {
- remoting.clientSession.removePlugin();
- remoting.clientSession = null;
+ switch (newState) {
+ case remoting.ClientSession.State.CLOSED:
console.log('Connection closed by host');
- if (remoting.currentConnectionType == remoting.ClientSession.Mode.IT2ME) {
+ if (remoting.clientSession.mode == remoting.ClientSession.Mode.IT2ME) {
remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_IT2ME);
} else {
remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_ME2ME);
}
- } else {
- // A state transition from CONNECTING -> CLOSED can happen if the host
- // closes the connection without an error message instead of accepting it.
- // For example, it does this if it fails to activate curtain mode. Since
- // there's no way of knowing exactly what went wrong, we rely on server-
- // side logs in this case and show a generic error message.
- showConnectError_(remoting.Error.UNEXPECTED);
- }
-
- } else if (newState == remoting.ClientSession.State.FAILED) {
- console.error('Client plugin reported connection failed: ' +
- remoting.clientSession.error);
- clearPin = true;
- if (remoting.clientSession.error ==
- remoting.ClientSession.ConnectionError.HOST_IS_OFFLINE) {
- clearPin = false;
- retryConnectOrReportOffline_();
- } else if (remoting.clientSession.error ==
- remoting.ClientSession.ConnectionError.SESSION_REJECTED) {
- showConnectError_(remoting.Error.INVALID_ACCESS_CODE);
- } else if (remoting.clientSession.error ==
- remoting.ClientSession.ConnectionError.INCOMPATIBLE_PROTOCOL) {
- showConnectError_(remoting.Error.INCOMPATIBLE_PROTOCOL);
- } else if (remoting.clientSession.error ==
- remoting.ClientSession.ConnectionError.NETWORK_FAILURE) {
- showConnectError_(remoting.Error.NETWORK_FAILURE);
- } else if (remoting.clientSession.error ==
- remoting.ClientSession.ConnectionError.HOST_OVERLOAD) {
- showConnectError_(remoting.Error.HOST_OVERLOAD);
- } else {
- showConnectError_(remoting.Error.UNEXPECTED);
- }
-
- if (clearPin) {
- document.getElementById('pin-entry').value = '';
- }
+ break;
- } else {
- 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 allow compatibility.
- showConnectError_(remoting.Error.MISSING_PLUGIN);
- }
-}
-
-/**
- * If we have a hostId to retry, try refreshing it and connecting again. If not,
- * then show the 'host offline' error message.
- *
- * @return {void} Nothing.
- */
-function retryConnectOrReportOffline_() {
- if (remoting.clientSession) {
- remoting.clientSession.removePlugin();
- remoting.clientSession = null;
- }
- if (remoting.hostId && remoting.retryIfOffline) {
- console.warn('Connection failed. Retrying.');
- /** @param {boolean} success True if the refresh was successful. */
- var onDone = function(success) {
- if (success) {
- remoting.retryIfOffline = false;
- remoting.connectMe2MeWithPin();
- } else {
- showConnectError_(remoting.Error.HOST_IS_OFFLINE);
+ case remoting.ClientSession.State.FAILED:
+ var error = remoting.clientSession.getError();
+ console.error('Client plugin reported connection failed: ' + error);
+ if (error == null) {
+ error = remoting.Error.UNEXPECTED;
}
- };
- remoting.hostList.refresh(onDone);
- } else {
- console.error('Connection failed. Not retrying.');
- showConnectError_(remoting.Error.HOST_IS_OFFLINE);
- }
-}
-
-/**
- * Create the client session object and initiate the connection.
- *
- * @param {string} clientJid The full JID of the WCS client.
- * @return {void} Nothing.
- */
-function startSession_(clientJid) {
- console.log('Starting session...');
- var accessCode = document.getElementById('access-code-entry');
- accessCode.value = ''; // The code has been validated and won't work again.
- remoting.clientSession =
- new remoting.ClientSession(
- remoting.hostJid, clientJid,
- remoting.hostPublicKey,
- remoting.accessCode, 'spake2_plain', '',
- remoting.ClientSession.Mode.IT2ME,
- onClientStateChange_);
- remoting.clientSession.createPluginAndConnect(
- document.getElementById('session-mode'));
+ showConnectError_(error);
+ break;
+
+ default:
+ console.error('Unexpected client plugin state: ' + newState);
+ // This should only happen if the web-app and client plugin get out of
+ // sync, so MISSING_PLUGIN is a suitable error.
+ showConnectError_(remoting.Error.MISSING_PLUGIN);
+ break;
+ }
+ remoting.clientSession.removePlugin();
+ remoting.clientSession = null;
}
/**
@@ -350,15 +152,15 @@ function showConnectError_(errorTag) {
var errorDiv = document.getElementById('connect-error-message');
l10n.localizeElementFromTag(errorDiv, /** @type {string} */ (errorTag));
remoting.accessCode = '';
- if (remoting.clientSession) {
- remoting.clientSession.disconnect(false);
- remoting.clientSession = null;
- }
- if (remoting.currentConnectionType == remoting.ClientSession.Mode.IT2ME) {
+ if (remoting.clientSession.mode == remoting.ClientSession.Mode.IT2ME) {
remoting.setMode(remoting.AppMode.CLIENT_CONNECT_FAILED_IT2ME);
} else {
remoting.setMode(remoting.AppMode.CLIENT_CONNECT_FAILED_ME2ME);
}
+ if (remoting.clientSession) {
+ remoting.clientSession.disconnect(false);
+ remoting.clientSession = null;
+ }
}
/**
@@ -376,75 +178,6 @@ function setConnectionInterruptedButtonsText_() {
}
/**
- * Parse the response from the server to a request to resolve a support id.
- *
- * @param {string} clientJid The full JID of the WCS client.
- * @param {XMLHttpRequest} xhr The XMLHttpRequest object.
- * @return {void} Nothing.
- */
-function parseServerResponse_(clientJid, xhr) {
- remoting.supportHostsXhr_ = null;
- console.log('parseServerResponse: xhr =', xhr);
- if (xhr.status == 200) {
- var host = /** @type {{data: {jabberId: string, publicKey: string}}} */
- jsonParseSafe(xhr.responseText);
- if (host && host.data && host.data.jabberId && host.data.publicKey) {
- remoting.hostJid = host.data.jabberId;
- remoting.hostPublicKey = host.data.publicKey;
- var split = remoting.hostJid.split('/');
- document.getElementById('connected-to').innerText = split[0];
- startSession_(clientJid);
- return;
- } else {
- console.error('Invalid "support-hosts" response from server.');
- }
- }
- var errorMsg = remoting.Error.UNEXPECTED;
- if (xhr.status == 404) {
- errorMsg = remoting.Error.INVALID_ACCESS_CODE;
- } else if (xhr.status == 0) {
- errorMsg = remoting.Error.NO_RESPONSE;
- } else if (xhr.status == 502 || xhr.status == 503) {
- errorMsg = remoting.Error.SERVICE_UNAVAILABLE;
- } else {
- console.error('The server responded: ' + xhr.responseText);
- }
- showConnectError_(errorMsg);
-}
-
-/**
- * Normalize the access code entered by the user.
- *
- * @param {string} accessCode The access code, as entered by the user.
- * @return {string} The normalized form of the code (whitespace removed).
- */
-function normalizeAccessCode_(accessCode) {
- // Trim whitespace.
- // TODO(sergeyu): Do we need to do any other normalization here?
- return accessCode.replace(/\s/g, '');
-}
-
-/**
- * Initiate a request to the server to resolve a support ID.
- *
- * @param {string} clientJid The full JID of the WCS client.
- * @param {string} supportId The canonicalized support ID.
- * @param {string} token The OAuth access token.
- */
-function resolveSupportId(clientJid, supportId, token) {
- var headers = {
- 'Authorization': 'OAuth ' + token
- };
-
- remoting.supportHostsXhr_ = remoting.xhr.get(
- remoting.settings.DIRECTORY_API_BASE_URL + '/support-hosts/' +
- encodeURIComponent(supportId),
- parseServerResponse_.bind(null, clientJid),
- '',
- headers);
-}
-
-/**
* Timer callback to update the statistics panel.
*/
function updateStatistics_() {
@@ -460,114 +193,49 @@ function updateStatistics_() {
}
/**
- * Shows PIN entry screen.
+ * Shows PIN entry screen localized to include the host name, and registers
+ * a host-specific one-shot event handler for the form submission.
*
* @param {string} hostId The unique id of the host.
- * @param {boolean} retryIfOffline If true and the host can't be contacted,
- * refresh the host list and try again. This allows bookmarked hosts to
- * work even if they reregister with Talk and get a different Jid.
* @return {void} Nothing.
*/
-remoting.connectMe2Me = function(hostId, retryIfOffline) {
- remoting.currentConnectionType = remoting.ClientSession.Mode.ME2ME;
- remoting.hostId = hostId;
- remoting.retryIfOffline = retryIfOffline;
-
- var host = remoting.hostList.getHostForId(remoting.hostId);
- // If we're re-loading a tab for a host that has since been unregistered
- // then the hostId may no longer resolve.
+remoting.connectMe2Me = function(hostId) {
+ var host = remoting.hostList.getHostForId(hostId);
if (!host) {
showConnectError_(remoting.Error.HOST_IS_OFFLINE);
return;
}
+
+ remoting.connector = new remoting.SessionConnector(
+ document.getElementById('session-mode'),
+ remoting.onConnected,
+ remoting.showErrorMessage);
+ /** @type {Element} */
+ var pinForm = document.getElementById('pin-form');
+ /** @param {Event} event */
+ var onSubmit = function(event) {
+ pinForm.removeEventListener('submit', onSubmit, false);
+ var pin = document.getElementById('pin-entry').value;
+ remoting.connector.connectMe2Me(host, pin);
+ remoting.setMode(remoting.AppMode.CLIENT_CONNECTING);
+ event.preventDefault();
+ };
+ pinForm.addEventListener('submit', onSubmit, false);
+
var message = document.getElementById('pin-message');
l10n.localizeElement(message, host.hostName);
remoting.setMode(remoting.AppMode.CLIENT_PIN_PROMPT);
};
-/**
- * Start a connection to the specified host, using the cached details
- * and the PIN entered by the user.
- *
- * @return {void} Nothing.
- */
-remoting.connectMe2MeWithPin = function() {
- console.log('Connecting to host...');
- remoting.setMode(remoting.AppMode.CLIENT_CONNECTING);
-
- var host = remoting.hostList.getHostForId(remoting.hostId);
- // If the user clicked on a cached host that has since been removed then we
- // won't find the hostId. If the user clicked on the entry for the local host
- // immediately after having enabled it then we won't know it's JID or public
- // key until the host heartbeats and we pull a fresh host list.
- if (!host || !host.jabberId || !host.publicKey) {
- retryConnectOrReportOffline_();
- return;
- }
- remoting.hostJid = host.jabberId;
- remoting.hostPublicKey = host.publicKey;
- document.getElementById('connected-to').innerText = host.hostName;
- document.title = host.hostName + ' - ' +
- chrome.i18n.getMessage('PRODUCT_NAME');
-
- /** @param {string} token */
- var startWcsAndConnect = function(token) {
- remoting.wcsSandbox.setOnReady(
- connectMe2MeWithAccessToken_.bind(null, token));
- remoting.wcsSandbox.setOnError(remoting.showErrorMessage);
- remoting.wcsSandbox.setAccessToken(token);
- startAccessTokenRefreshTimer_();
- };
- remoting.identity.callWithToken(startWcsAndConnect,
- remoting.showErrorMessage);
+/** @param {remoting.ClientSession} clientSession */
+remoting.onConnected = function(clientSession) {
+ remoting.connector = null;
+ remoting.clientSession = clientSession;
+ remoting.clientSession.setOnStateChange(onClientStateChange_);
+ setConnectionInterruptedButtonsText_();
+ remoting.setMode(remoting.AppMode.IN_SESSION);
+ remoting.toolbar.center();
+ remoting.toolbar.preview();
+ remoting.clipboard.startSession();
+ updateStatistics_();
};
-
-/**
- * Continue making the connection to a host, once WCS has initialized.
- *
- * @param {string} token The OAuth2 access token.
- * @param {string} clientJid The full JID of the WCS client.
- * @return {void} Nothing.
- */
-function connectMe2MeWithAccessToken_(token, clientJid) {
- /** @type {string} */
- var pin = document.getElementById('pin-entry').value;
-
- remoting.clientSession =
- new remoting.ClientSession(
- remoting.hostJid, clientJid, remoting.hostPublicKey,
- pin, 'spake2_hmac,spake2_plain', remoting.hostId,
- remoting.ClientSession.Mode.ME2ME, onClientStateChange_);
- // Don't log host offline errors for cached JIDs.
- remoting.clientSession.logHostOfflineErrors(!remoting.retryIfOffline);
- remoting.clientSession.createPluginAndConnect(
- document.getElementById('session-mode'));
-}
-
-/** @type {number} */
-remoting.wcsAccessTokenRefreshTimer = 0;
-
-function startAccessTokenRefreshTimer_() {
- if (remoting.wcsAccessTokenRefreshTimer != 0) {
- return;
- }
-
- /** @param {string} token */
- var updateAccessToken = function(token) {
- remoting.wcsSandbox.setAccessToken(token);
- };
- /** @param {remoting.Error} error */
- var logError = function(error) {
- console.error('updateAccessToken: Authentication failed: ' + error);
- };
- var refreshAccessToken = function() {
- remoting.identity.callWithToken(updateAccessToken, logError);
- };
- /**
- * A timer that polls for an updated access token.
- * @type {number}
- * @private
- */
- remoting.wcsAccessTokenRefreshTimer = setInterval(refreshAccessToken,
- 60 * 1000);
-}