Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(402)

Unified Diff: remoting/webapp/me2mom/client_screen.js

Issue 8416007: Refactored web-app (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added consistency comment. Moved debug log keyboard shortcut handling. Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: remoting/webapp/me2mom/client_screen.js
diff --git a/remoting/webapp/me2mom/client_screen.js b/remoting/webapp/me2mom/client_screen.js
new file mode 100644
index 0000000000000000000000000000000000000000..6065672b9e34e6a95b4974e480b33f5ae55e87b7
--- /dev/null
+++ b/remoting/webapp/me2mom/client_screen.js
@@ -0,0 +1,401 @@
+// Copyright (c) 2011 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.
+
+/**
+ * @fileoverview
+ * Functions related to the 'client screen' for Chromoting.
+ */
+
+'use strict';
+
+/** @suppress {duplicate} */
+var remoting = remoting || {};
+
+/** @enum {string} */
+remoting.ClientError = {
+ NO_RESPONSE: /*i18n-content*/'ERROR_NO_RESPONSE',
+ INVALID_ACCESS_CODE: /*i18n-content*/'ERROR_INVALID_ACCESS_CODE',
+ MISSING_PLUGIN: /*i18n-content*/'ERROR_MISSING_PLUGIN',
+ OAUTH_FETCH_FAILED: /*i18n-content*/'ERROR_AUTHENTICATION_FAILED',
+ HOST_IS_OFFLINE: /*i18n-content*/'ERROR_HOST_IS_OFFLINE',
+ INCOMPATIBLE_PROTOCOL: /*i18n-content*/'ERROR_INCOMPATIBLE_PROTOCOL',
+ BAD_PLUGIN_VERSION: /*i18n-content*/'ERROR_BAD_PLUGIN_VERSION',
+ OTHER_ERROR: /*i18n-content*/'ERROR_GENERIC'
+};
+
+(function() {
+
+/**
+ * @type {boolean} Whether or not the plugin should scale itself.
+ */
+remoting.scaleToFit = false;
garykac 2011/10/27 22:32:39 nit: I assume these should have underscores at the
Jamie 2011/10/27 22:51:37 No, anything exported to the remoting namespace is
+
+/**
+ * @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} 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.
+ */
+remoting.supportHostsXhr_ = null;
+
+/**
+ * Entry point for the 'connect' functionality. This function checks for the
+ * existence of an OAuth2 token, and either requests one asynchronously, or
+ * calls through directly to tryConnectWithAccessToken_.
+ */
+remoting.tryConnect = function() {
+ document.getElementById('cancel-button').disabled = false;
+ if (remoting.oauth2.needsNewAccessToken()) {
+ remoting.oauth2.refreshAccessToken(function(xhr) {
+ if (remoting.oauth2.needsNewAccessToken()) {
+ // Failed to get access token
+ remoting.debug.log('tryConnect: OAuth2 token fetch failed');
+ showConnectError_(remoting.ClientError.OAUTH_FETCH_FAILED);
+ return;
+ }
+ tryConnectWithAccessToken_();
+ });
+ } else {
+ tryConnectWithAccessToken_();
+ }
+}
+
+/**
+ * Cancel an incomplete connect operation.
+ *
+ * @return {void} Nothing.
+ */
+remoting.cancelConnect = function() {
+ if (remoting.supportHostsXhr_) {
+ remoting.supportHostsXhr_.abort();
+ remoting.supportHostsXhr_ = null;
+ }
+ if (remoting.clientSession) {
+ remoting.clientSession.removePlugin();
+ remoting.clientSession = null;
+ }
+ remoting.setMode(remoting.AppMode.HOME);
+}
+
+/**
+ * Enable or disable scale-to-fit.
+ *
+ * @param {Element} button The scale-to-fit button. The style of this button is
+ * updated to reflect the new scaling state.
+ * @return {void} Nothing.
+ */
+remoting.toggleScaleToFit = function(button) {
+ remoting.scaleToFit = !remoting.scaleToFit;
+ if (remoting.scaleToFit) {
+ addClass(button, 'toggle-button-active');
+ } else {
+ removeClass(button, 'toggle-button-active');
+ }
+ remoting.clientSession.updateDimensions();
+}
+
+/**
+ * Update the remoting client layout in response to a resize event.
+ *
+ * @return {void} Nothing.
+ */
+remoting.onResize = function() {
+ if (remoting.clientSession)
+ remoting.clientSession.onWindowSizeChanged();
+ recenterToolbar_();
+}
+
+/**
+ * Disconnect the remoting client.
+ *
+ * @return {void} Nothing.
+ */
+remoting.disconnect = function() {
+ if (remoting.clientSession) {
+ remoting.clientSession.disconnect();
+ remoting.clientSession = null;
+ remoting.debug.log('Disconnected.');
+ remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED);
+ }
+}
+
+/**
+ * Second stage of the 'connect' functionality. Once an access token is
+ * available, load the WCS widget asynchronously and call through to
+ * tryConnectWithWcs_ when ready.
+ */
+function tryConnectWithAccessToken_() {
+ if (!remoting.wcsLoader) {
+ remoting.wcsLoader = new remoting.WcsLoader();
+ }
+ /** @param {function(string):void} setToken The callback function. */
+ var callWithToken = function(setToken) {
+ remoting.oauth2.callWithToken(setToken);
+ };
+ remoting.wcsLoader.start(
+ remoting.oauth2.getAccessToken(),
+ callWithToken,
+ tryConnectWithWcs_);
+}
+
+/**
+ * Final stage of the 'connect' functionality, called when the wcs widget has
+ * been loaded, or on error.
+ *
+ * @param {boolean} success True if the script was loaded successfully.
+ */
+function tryConnectWithWcs_(success) {
+ if (success) {
+ 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) {
+ remoting.debug.log('Bad access code length');
+ showConnectError_(remoting.ClientError.INVALID_ACCESS_CODE);
+ } else {
+ var supportId = remoting.accessCode.substring(0, kSupportIdLen);
+ remoting.setMode(remoting.AppMode.CLIENT_CONNECTING);
+ resolveSupportId(supportId);
+ }
+ } else {
+ showConnectError_(remoting.ClientError.OAUTH_FETCH_FAILED);
+ }
+}
+
+/**
+ * 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.
+ */
+// TODO(jamiewalch): Make this pass both the current and old states to avoid
+// race conditions.
+function onClientStateChange_(oldState) {
+ 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;
+ }
+ var state = remoting.clientSession.state;
+ if (state == remoting.ClientSession.State.CREATED) {
+ remoting.debug.log('Created plugin');
+
+ } else if (state == remoting.ClientSession.State.BAD_PLUGIN_VERSION) {
+ showConnectError_(remoting.ClientError.BAD_PLUGIN_VERSION);
+
+ } else if (state == remoting.ClientSession.State.CONNECTING) {
+ remoting.debug.log('Connecting as ' + remoting.oauth2.getCachedEmail());
+
+ } else if (state == remoting.ClientSession.State.INITIALIZING) {
+ remoting.debug.log('Initializing connection');
+
+ } else if (state == remoting.ClientSession.State.CONNECTED) {
+ if (remoting.clientSession) {
+ remoting.setMode(remoting.AppMode.IN_SESSION);
+ recenterToolbar_();
+ showToolbarPreview_();
+ updateStatistics_();
+ }
+
+ } else if (state == remoting.ClientSession.State.CLOSED) {
+ if (oldState == remoting.ClientSession.State.CONNECTED) {
+ remoting.clientSession.removePlugin();
+ remoting.clientSession = null;
+ remoting.debug.log('Connection closed by host');
+ remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED);
+ } else {
+ // The transition from CONNECTING to CLOSED state may happen
+ // only with older client plugins. Current version should go the
+ // FAILED state when connection fails.
+ showConnectError_(remoting.ClientError.INVALID_ACCESS_CODE);
+ }
+
+ } else if (state == remoting.ClientSession.State.CONNECTION_FAILED) {
+ remoting.debug.log('Client plugin reported connection failed: ' +
+ remoting.clientSession.error);
+ if (remoting.clientSession.error ==
+ remoting.ClientSession.ConnectionError.HOST_IS_OFFLINE) {
+ showConnectError_(remoting.ClientError.HOST_IS_OFFLINE);
+ } else if (remoting.clientSession.error ==
+ remoting.ClientSession.ConnectionError.SESSION_REJECTED) {
+ showConnectError_(remoting.ClientError.INVALID_ACCESS_CODE);
+ } else if (remoting.clientSession.error ==
+ remoting.ClientSession.ConnectionError.INCOMPATIBLE_PROTOCOL) {
+ showConnectError_(remoting.ClientError.INCOMPATIBLE_PROTOCOL);
+ } else if (remoting.clientSession.error ==
+ remoting.ClientSession.ConnectionError.NETWORK_FAILURE) {
+ showConnectError_(remoting.ClientError.OTHER_ERROR);
+ } else {
+ showConnectError_(remoting.ClientError.OTHER_ERROR);
+ }
+
+ } else {
+ remoting.debug.log('Unexpected client plugin state: ' + state);
+ // 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.ClientError.MISSING_PLUGIN);
+ }
+}
+
+/**
+ * Create the client session object and initiate the connection.
+ *
+ * @return {void} Nothing.
+ */
+function startSession_() {
+ remoting.debug.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, remoting.hostPublicKey,
+ remoting.accessCode,
+ /** @type {string} */ (remoting.oauth2.getCachedEmail()),
+ onClientStateChange_);
+ /** @param {string} token The auth token. */
+ var createPluginAndConnect = function(token) {
+ remoting.clientSession.createPluginAndConnect(
+ document.getElementById('session-mode'),
+ token);
+ };
+ remoting.oauth2.callWithToken(createPluginAndConnect);
+}
+
+/**
+ * Show a client-side error message.
+ *
+ * @param {remoting.ClientError} errorTag The error to be localized and
+ * displayed.
+ * @return {void} Nothing.
+ */
+function showConnectError_(errorTag) {
+ remoting.debug.log('Connection failed: ' + errorTag);
+ var errorDiv = document.getElementById('connect-error-message');
+ l10n.localizeElementFromTag(errorDiv, /** @type {string} */ (errorTag));
+ remoting.accessCode = '';
+ if (remoting.clientSession) {
+ remoting.clientSession.disconnect();
+ remoting.clientSession = null;
+ }
+ remoting.setMode(remoting.AppMode.CLIENT_CONNECT_FAILED);
+}
+
+/**
+ * Parse the response from the server to a request to resolve a support id.
+ *
+ * @param {XMLHttpRequest} xhr The XMLHttpRequest object.
+ * @return {void} Nothing.
+ */
+function parseServerResponse_(xhr) {
+ remoting.supportHostsXhr_ = null;
+ remoting.debug.log('parseServerResponse: status = ' + xhr.status);
+ if (xhr.status == 200) {
+ var host = /** @type {{data: {jabberId: string, publicKey: string}}} */
+ JSON.parse(xhr.responseText);
+ if (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_();
+ return;
+ }
+ }
+ var errorMsg = remoting.ClientError.OTHER_ERROR;
+ if (xhr.status == 404) {
+ errorMsg = remoting.ClientError.INVALID_ACCESS_CODE;
+ } else if (xhr.status == 0) {
+ errorMsg = remoting.ClientError.NO_RESPONSE;
+ } else {
+ remoting.debug.log('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} supportId The canonicalized support ID.
+ */
+function resolveSupportId(supportId) {
+ var headers = {
+ 'Authorization': 'OAuth ' + remoting.oauth2.getAccessToken()
+ };
+
+ remoting.supportHostsXhr_ = remoting.xhr.get(
+ 'https://www.googleapis.com/chromoting/v1/support-hosts/' +
+ encodeURIComponent(supportId),
+ parseServerResponse_,
+ '',
+ headers);
+}
+
+/**
+ * Timer callback to update the statistics panel.
+ */
+function updateStatistics_() {
+ if (!remoting.clientSession ||
+ remoting.clientSession.state != remoting.ClientSession.State.CONNECTED) {
+ return;
+ }
+ remoting.debug.updateStatistics(remoting.clientSession.stats());
+ // Update the stats once per second.
+ window.setTimeout(updateStatistics_, 1000);
+}
+
+/**
+ * Force-show the tool-bar for three seconds to aid discoverability.
+ */
+function showToolbarPreview_() {
+ var toolbar = document.getElementById('session-toolbar');
+ addClass(toolbar, 'toolbar-preview');
+ window.setTimeout(removeClass, 3000, toolbar, 'toolbar-preview');
+}
+
+/**
+ * Update the horizontal position of the tool-bar to center it.
+ */
+function recenterToolbar_() {
+ var toolbar = document.getElementById('session-toolbar');
+ var toolbarX = (window.innerWidth - toolbar.clientWidth) / 2;
+ toolbar.style['left'] = toolbarX + 'px';
+}
+
+
+}());

Powered by Google App Engine
This is Rietveld 408576698