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

Side by Side Diff: remoting/webapp/me2mom/client_screen.js

Issue 8416007: Refactored web-app (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 9 years, 1 month 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « remoting/webapp/me2mom/choice.html ('k') | remoting/webapp/me2mom/client_session.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6 * @fileoverview
7 * Functions related to the 'client screen' for Chromoting.
8 */
9
10 'use strict';
11
12 /** @suppress {duplicate} */
13 var remoting = remoting || {};
14
15 /** @enum {string} */
16 remoting.ClientError = {
17 NO_RESPONSE: /*i18n-content*/'ERROR_NO_RESPONSE',
18 INVALID_ACCESS_CODE: /*i18n-content*/'ERROR_INVALID_ACCESS_CODE',
19 MISSING_PLUGIN: /*i18n-content*/'ERROR_MISSING_PLUGIN',
20 OAUTH_FETCH_FAILED: /*i18n-content*/'ERROR_AUTHENTICATION_FAILED',
21 HOST_IS_OFFLINE: /*i18n-content*/'ERROR_HOST_IS_OFFLINE',
22 INCOMPATIBLE_PROTOCOL: /*i18n-content*/'ERROR_INCOMPATIBLE_PROTOCOL',
23 BAD_PLUGIN_VERSION: /*i18n-content*/'ERROR_BAD_PLUGIN_VERSION',
24 OTHER_ERROR: /*i18n-content*/'ERROR_GENERIC'
25 };
26
27 (function() {
28
29 /**
30 * @type {boolean} Whether or not the plugin should scale itself.
31 */
32 remoting.scaleToFit = false;
33
34 /**
35 * @type {remoting.ClientSession} The client session object, set once the
36 * access code has been successfully verified.
37 */
38 remoting.clientSession = null;
39
40 /**
41 * @type {string} The normalized access code.
42 */
43 remoting.accessCode = '';
44
45 /**
46 * @type {string} The host's JID, returned by the server.
47 */
48 remoting.hostJid = '';
49
50 /**
51 * @type {string} The host's public key, returned by the server.
52 */
53 remoting.hostPublicKey = '';
54
55 /**
56 * @type {XMLHttpRequest} The XHR object corresponding to the current
57 * support-hosts request, if there is one outstanding.
58 */
59 remoting.supportHostsXhr_ = null;
60
61 /**
62 * Entry point for the 'connect' functionality. This function checks for the
63 * existence of an OAuth2 token, and either requests one asynchronously, or
64 * calls through directly to tryConnectWithAccessToken_.
65 */
66 remoting.tryConnect = function() {
67 document.getElementById('cancel-button').disabled = false;
68 if (remoting.oauth2.needsNewAccessToken()) {
69 remoting.oauth2.refreshAccessToken(function(xhr) {
70 if (remoting.oauth2.needsNewAccessToken()) {
71 // Failed to get access token
72 remoting.debug.log('tryConnect: OAuth2 token fetch failed');
73 showConnectError_(remoting.ClientError.OAUTH_FETCH_FAILED);
74 return;
75 }
76 tryConnectWithAccessToken_();
77 });
78 } else {
79 tryConnectWithAccessToken_();
80 }
81 }
82
83 /**
84 * Cancel an incomplete connect operation.
85 *
86 * @return {void} Nothing.
87 */
88 remoting.cancelConnect = function() {
89 if (remoting.supportHostsXhr_) {
90 remoting.supportHostsXhr_.abort();
91 remoting.supportHostsXhr_ = null;
92 }
93 if (remoting.clientSession) {
94 remoting.clientSession.removePlugin();
95 remoting.clientSession = null;
96 }
97 remoting.setMode(remoting.AppMode.HOME);
98 }
99
100 /**
101 * Enable or disable scale-to-fit.
102 *
103 * @param {Element} button The scale-to-fit button. The style of this button is
104 * updated to reflect the new scaling state.
105 * @return {void} Nothing.
106 */
107 remoting.toggleScaleToFit = function(button) {
108 remoting.scaleToFit = !remoting.scaleToFit;
109 if (remoting.scaleToFit) {
110 addClass(button, 'toggle-button-active');
111 } else {
112 removeClass(button, 'toggle-button-active');
113 }
114 remoting.clientSession.updateDimensions();
115 }
116
117 /**
118 * Update the remoting client layout in response to a resize event.
119 *
120 * @return {void} Nothing.
121 */
122 remoting.onResize = function() {
123 if (remoting.clientSession)
124 remoting.clientSession.onWindowSizeChanged();
125 recenterToolbar_();
126 }
127
128 /**
129 * Disconnect the remoting client.
130 *
131 * @return {void} Nothing.
132 */
133 remoting.disconnect = function() {
134 if (remoting.clientSession) {
135 remoting.clientSession.disconnect();
136 remoting.clientSession = null;
137 remoting.debug.log('Disconnected.');
138 remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED);
139 }
140 }
141
142 /**
143 * Second stage of the 'connect' functionality. Once an access token is
144 * available, load the WCS widget asynchronously and call through to
145 * tryConnectWithWcs_ when ready.
146 */
147 function tryConnectWithAccessToken_() {
148 if (!remoting.wcsLoader) {
149 remoting.wcsLoader = new remoting.WcsLoader();
150 }
151 /** @param {function(string):void} setToken The callback function. */
152 var callWithToken = function(setToken) {
153 remoting.oauth2.callWithToken(setToken);
154 };
155 remoting.wcsLoader.start(
156 remoting.oauth2.getAccessToken(),
157 callWithToken,
158 tryConnectWithWcs_);
159 }
160
161 /**
162 * Final stage of the 'connect' functionality, called when the wcs widget has
163 * been loaded, or on error.
164 *
165 * @param {boolean} success True if the script was loaded successfully.
166 */
167 function tryConnectWithWcs_(success) {
168 if (success) {
169 var accessCode = document.getElementById('access-code-entry').value;
170 remoting.accessCode = normalizeAccessCode_(accessCode);
171 // At present, only 12-digit access codes are supported, of which the first
172 // 7 characters are the supportId.
173 var kSupportIdLen = 7;
174 var kHostSecretLen = 5;
175 var kAccessCodeLen = kSupportIdLen + kHostSecretLen;
176 if (remoting.accessCode.length != kAccessCodeLen) {
177 remoting.debug.log('Bad access code length');
178 showConnectError_(remoting.ClientError.INVALID_ACCESS_CODE);
179 } else {
180 var supportId = remoting.accessCode.substring(0, kSupportIdLen);
181 remoting.setMode(remoting.AppMode.CLIENT_CONNECTING);
182 resolveSupportId(supportId);
183 }
184 } else {
185 showConnectError_(remoting.ClientError.OAUTH_FETCH_FAILED);
186 }
187 }
188
189 /**
190 * Callback function called when the state of the client plugin changes. The
191 * current state is available via the |state| member variable.
192 *
193 * @param {number} oldState The previous state of the plugin.
194 */
195 // TODO(jamiewalch): Make this pass both the current and old states to avoid
196 // race conditions.
197 function onClientStateChange_(oldState) {
198 if (!remoting.clientSession) {
199 // If the connection has been cancelled, then we no longer have a reference
200 // to the session object and should ignore any state changes.
201 return;
202 }
203 var state = remoting.clientSession.state;
204 if (state == remoting.ClientSession.State.CREATED) {
205 remoting.debug.log('Created plugin');
206
207 } else if (state == remoting.ClientSession.State.BAD_PLUGIN_VERSION) {
208 showConnectError_(remoting.ClientError.BAD_PLUGIN_VERSION);
209
210 } else if (state == remoting.ClientSession.State.CONNECTING) {
211 remoting.debug.log('Connecting as ' + remoting.oauth2.getCachedEmail());
212
213 } else if (state == remoting.ClientSession.State.INITIALIZING) {
214 remoting.debug.log('Initializing connection');
215
216 } else if (state == remoting.ClientSession.State.CONNECTED) {
217 if (remoting.clientSession) {
218 remoting.setMode(remoting.AppMode.IN_SESSION);
219 recenterToolbar_();
220 showToolbarPreview_();
221 updateStatistics_();
222 }
223
224 } else if (state == remoting.ClientSession.State.CLOSED) {
225 if (oldState == remoting.ClientSession.State.CONNECTED) {
226 remoting.clientSession.removePlugin();
227 remoting.clientSession = null;
228 remoting.debug.log('Connection closed by host');
229 remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED);
230 } else {
231 // The transition from CONNECTING to CLOSED state may happen
232 // only with older client plugins. Current version should go the
233 // FAILED state when connection fails.
234 showConnectError_(remoting.ClientError.INVALID_ACCESS_CODE);
235 }
236
237 } else if (state == remoting.ClientSession.State.CONNECTION_FAILED) {
238 remoting.debug.log('Client plugin reported connection failed: ' +
239 remoting.clientSession.error);
240 if (remoting.clientSession.error ==
241 remoting.ClientSession.ConnectionError.HOST_IS_OFFLINE) {
242 showConnectError_(remoting.ClientError.HOST_IS_OFFLINE);
243 } else if (remoting.clientSession.error ==
244 remoting.ClientSession.ConnectionError.SESSION_REJECTED) {
245 showConnectError_(remoting.ClientError.INVALID_ACCESS_CODE);
246 } else if (remoting.clientSession.error ==
247 remoting.ClientSession.ConnectionError.INCOMPATIBLE_PROTOCOL) {
248 showConnectError_(remoting.ClientError.INCOMPATIBLE_PROTOCOL);
249 } else if (remoting.clientSession.error ==
250 remoting.ClientSession.ConnectionError.NETWORK_FAILURE) {
251 showConnectError_(remoting.ClientError.OTHER_ERROR);
252 } else {
253 showConnectError_(remoting.ClientError.OTHER_ERROR);
254 }
255
256 } else {
257 remoting.debug.log('Unexpected client plugin state: ' + state);
258 // This should only happen if the web-app and client plugin get out of
259 // sync, and even then the version check should allow compatibility.
260 showConnectError_(remoting.ClientError.MISSING_PLUGIN);
261 }
262 }
263
264 /**
265 * Create the client session object and initiate the connection.
266 *
267 * @return {void} Nothing.
268 */
269 function startSession_() {
270 remoting.debug.log('Starting session...');
271 var accessCode = document.getElementById('access-code-entry');
272 accessCode.value = ''; // The code has been validated and won't work again.
273 remoting.clientSession =
274 new remoting.ClientSession(
275 remoting.hostJid, remoting.hostPublicKey,
276 remoting.accessCode,
277 /** @type {string} */ (remoting.oauth2.getCachedEmail()),
278 onClientStateChange_);
279 /** @param {string} token The auth token. */
280 var createPluginAndConnect = function(token) {
281 remoting.clientSession.createPluginAndConnect(
282 document.getElementById('session-mode'),
283 token);
284 };
285 remoting.oauth2.callWithToken(createPluginAndConnect);
286 }
287
288 /**
289 * Show a client-side error message.
290 *
291 * @param {remoting.ClientError} errorTag The error to be localized and
292 * displayed.
293 * @return {void} Nothing.
294 */
295 function showConnectError_(errorTag) {
296 remoting.debug.log('Connection failed: ' + errorTag);
297 var errorDiv = document.getElementById('connect-error-message');
298 l10n.localizeElementFromTag(errorDiv, /** @type {string} */ (errorTag));
299 remoting.accessCode = '';
300 if (remoting.clientSession) {
301 remoting.clientSession.disconnect();
302 remoting.clientSession = null;
303 }
304 remoting.setMode(remoting.AppMode.CLIENT_CONNECT_FAILED);
305 }
306
307 /**
308 * Parse the response from the server to a request to resolve a support id.
309 *
310 * @param {XMLHttpRequest} xhr The XMLHttpRequest object.
311 * @return {void} Nothing.
312 */
313 function parseServerResponse_(xhr) {
314 remoting.supportHostsXhr_ = null;
315 remoting.debug.log('parseServerResponse: status = ' + xhr.status);
316 if (xhr.status == 200) {
317 var host = /** @type {{data: {jabberId: string, publicKey: string}}} */
318 JSON.parse(xhr.responseText);
319 if (host.data && host.data.jabberId && host.data.publicKey) {
320 remoting.hostJid = host.data.jabberId;
321 remoting.hostPublicKey = host.data.publicKey;
322 var split = remoting.hostJid.split('/');
323 document.getElementById('connected-to').innerText = split[0];
324 startSession_();
325 return;
326 }
327 }
328 var errorMsg = remoting.ClientError.OTHER_ERROR;
329 if (xhr.status == 404) {
330 errorMsg = remoting.ClientError.INVALID_ACCESS_CODE;
331 } else if (xhr.status == 0) {
332 errorMsg = remoting.ClientError.NO_RESPONSE;
333 } else {
334 remoting.debug.log('The server responded: ' + xhr.responseText);
335 }
336 showConnectError_(errorMsg);
337 }
338
339 /**
340 * Normalize the access code entered by the user.
341 *
342 * @param {string} accessCode The access code, as entered by the user.
343 * @return {string} The normalized form of the code (whitespace removed).
344 */
345 function normalizeAccessCode_(accessCode) {
346 // Trim whitespace.
347 // TODO(sergeyu): Do we need to do any other normalization here?
348 return accessCode.replace(/\s/g, '');
349 }
350
351 /**
352 * Initiate a request to the server to resolve a support ID.
353 *
354 * @param {string} supportId The canonicalized support ID.
355 */
356 function resolveSupportId(supportId) {
357 var headers = {
358 'Authorization': 'OAuth ' + remoting.oauth2.getAccessToken()
359 };
360
361 remoting.supportHostsXhr_ = remoting.xhr.get(
362 'https://www.googleapis.com/chromoting/v1/support-hosts/' +
363 encodeURIComponent(supportId),
364 parseServerResponse_,
365 '',
366 headers);
367 }
368
369 /**
370 * Timer callback to update the statistics panel.
371 */
372 function updateStatistics_() {
373 if (!remoting.clientSession ||
374 remoting.clientSession.state != remoting.ClientSession.State.CONNECTED) {
375 return;
376 }
377 remoting.debug.updateStatistics(remoting.clientSession.stats());
378 // Update the stats once per second.
379 window.setTimeout(updateStatistics_, 1000);
380 }
381
382 /**
383 * Force-show the tool-bar for three seconds to aid discoverability.
384 */
385 function showToolbarPreview_() {
386 var toolbar = document.getElementById('session-toolbar');
387 addClass(toolbar, 'toolbar-preview');
388 window.setTimeout(removeClass, 3000, toolbar, 'toolbar-preview');
389 }
390
391 /**
392 * Update the horizontal position of the tool-bar to center it.
393 */
394 function recenterToolbar_() {
395 var toolbar = document.getElementById('session-toolbar');
396 var toolbarX = (window.innerWidth - toolbar.clientWidth) / 2;
397 toolbar.style['left'] = toolbarX + 'px';
398 }
399
400
401 }());
OLDNEW
« no previous file with comments | « remoting/webapp/me2mom/choice.html ('k') | remoting/webapp/me2mom/client_session.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698