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

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

Issue 9148043: Rename webapp_it2me to remoting_webapp and move it from webapp/me2mom to webapp/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add webapp_it2me back Created 8 years, 11 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 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) 2012 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 /**
16 * @type {boolean} Whether or not the plugin should scale itself.
17 */
18 remoting.scaleToFit = false;
19
20 /**
21 * @type {remoting.ClientSession} The client session object, set once the
22 * access code has been successfully verified.
23 */
24 remoting.clientSession = null;
25
26 /**
27 * @type {string} The normalized access code.
28 */
29 remoting.accessCode = '';
30
31 /**
32 * @type {string} The host's JID, returned by the server.
33 */
34 remoting.hostJid = '';
35
36 /**
37 * @type {string} For Me2Me connections, the id of the current host.
38 */
39 remoting.hostId = '';
40
41 /**
42 * @type {boolean} For Me2Me connections. Set to true if connection
43 * must be retried on failure.
44 */
45 remoting.retryIfOffline = false;
46
47 /**
48 * @type {string} The host's public key, returned by the server.
49 */
50 remoting.hostPublicKey = '';
51
52 /**
53 * @type {XMLHttpRequest} The XHR object corresponding to the current
54 * support-hosts request, if there is one outstanding.
55 * @private
56 */
57 remoting.supportHostsXhr_ = null;
58
59 /**
60 * @enum {string}
61 */
62 remoting.ConnectionType = {
63 It2Me: 'It2Me',
64 Me2Me: 'Me2Me'
65 };
66
67 /**
68 * @type {remoting.ConnectionType?}
69 */
70 remoting.currentConnectionType = null;
71
72 /**
73 * Entry point for the 'connect' functionality. This function defers to the
74 * WCS loader to call it back with an access token.
75 */
76 remoting.connectIt2Me = function() {
77 remoting.currentConnectionType = remoting.ConnectionType.It2Me;
78 document.getElementById('cancel-button').disabled = false;
79 remoting.WcsLoader.load(connectIt2MeWithAccessToken_);
80 };
81
82 /**
83 * Cancel an incomplete connect operation.
84 *
85 * @return {void} Nothing.
86 */
87 remoting.cancelConnect = function() {
88 if (remoting.supportHostsXhr_) {
89 remoting.supportHostsXhr_.abort();
90 remoting.supportHostsXhr_ = null;
91 }
92 if (remoting.clientSession) {
93 remoting.clientSession.removePlugin();
94 remoting.clientSession = null;
95 }
96 remoting.setMode(remoting.AppMode.HOME);
97 };
98
99 /**
100 * Enable or disable scale-to-fit.
101 *
102 * @param {Event} event The click event. The style of the target is updated to
103 * reflect the new scaling state.
104 * @return {void} Nothing.
105 */
106 remoting.toggleScaleToFit = function(event) {
107 var button = /** @type Element */(event.target);
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.onResize();
125 };
126
127 /**
128 * Disconnect the remoting client.
129 *
130 * @return {void} Nothing.
131 */
132 remoting.disconnect = function() {
133 if (remoting.clientSession) {
134 remoting.clientSession.disconnect();
135 remoting.clientSession = null;
136 remoting.debug.log('Disconnected.');
137 if (remoting.currentConnectionType == remoting.ConnectionType.It2Me) {
138 remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_IT2ME);
139 } else {
140 remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_ME2ME);
141 }
142 }
143 };
144
145 /**
146 * If WCS was successfully loaded, proceed with the connection, otherwise
147 * report an error.
148 *
149 * @param {string?} token The OAuth2 access token, or null if an error occurred.
150 * @return {void} Nothing.
151 */
152 function connectIt2MeWithAccessToken_(token) {
153 if (token) {
154 var accessCode = document.getElementById('access-code-entry').value;
155 remoting.accessCode = normalizeAccessCode_(accessCode);
156 // At present, only 12-digit access codes are supported, of which the first
157 // 7 characters are the supportId.
158 var kSupportIdLen = 7;
159 var kHostSecretLen = 5;
160 var kAccessCodeLen = kSupportIdLen + kHostSecretLen;
161 if (remoting.accessCode.length != kAccessCodeLen) {
162 remoting.debug.log('Bad access code length');
163 showConnectError_(remoting.Error.INVALID_ACCESS_CODE);
164 } else {
165 var supportId = remoting.accessCode.substring(0, kSupportIdLen);
166 remoting.setMode(remoting.AppMode.CLIENT_CONNECTING);
167 resolveSupportId(supportId);
168 }
169 } else {
170 showConnectError_(remoting.Error.AUTHENTICATION_FAILED);
171 }
172 }
173
174 /**
175 * Callback function called when the state of the client plugin changes. The
176 * current state is available via the |state| member variable.
177 *
178 * @param {number} oldState The previous state of the plugin.
179 * @param {number} newState The current state of the plugin.
180 */
181 // TODO(jamiewalch): Make this pass both the current and old states to avoid
182 // race conditions.
183 function onClientStateChange_(oldState, newState) {
184 if (!remoting.clientSession) {
185 // If the connection has been cancelled, then we no longer have a reference
186 // to the session object and should ignore any state changes.
187 return;
188 }
189 if (newState == remoting.ClientSession.State.CREATED) {
190 remoting.debug.log('Created plugin');
191
192 } else if (newState == remoting.ClientSession.State.BAD_PLUGIN_VERSION) {
193 showConnectError_(remoting.Error.BAD_PLUGIN_VERSION);
194
195 } else if (newState == remoting.ClientSession.State.CONNECTING) {
196 remoting.debug.log('Connecting as ' + remoting.oauth2.getCachedEmail());
197
198 } else if (newState == remoting.ClientSession.State.INITIALIZING) {
199 remoting.debug.log('Initializing connection');
200
201 } else if (newState == remoting.ClientSession.State.CONNECTED) {
202 if (remoting.clientSession) {
203 remoting.setMode(remoting.AppMode.IN_SESSION);
204 remoting.toolbar.center();
205 remoting.toolbar.preview();
206 updateStatistics_();
207 }
208
209 } else if (newState == remoting.ClientSession.State.CLOSED) {
210 if (oldState == remoting.ClientSession.State.CONNECTED) {
211 remoting.clientSession.removePlugin();
212 remoting.clientSession = null;
213 remoting.debug.log('Connection closed by host');
214 if (remoting.currentConnectionType == remoting.ConnectionType.It2Me) {
215 remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_IT2ME);
216 } else {
217 remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_ME2ME);
218 }
219 } else {
220 // The transition from CONNECTING to CLOSED state may happen
221 // only with older client plugins. Current version should go the
222 // FAILED state when connection fails.
223 showConnectError_(remoting.Error.INVALID_ACCESS_CODE);
224 }
225
226 } else if (newState == remoting.ClientSession.State.CONNECTION_FAILED) {
227 remoting.debug.log('Client plugin reported connection failed: ' +
228 remoting.clientSession.error);
229 if (remoting.clientSession.error ==
230 remoting.ClientSession.ConnectionError.HOST_IS_OFFLINE) {
231 retryConnectOrReportOffline_();
232 } else if (remoting.clientSession.error ==
233 remoting.ClientSession.ConnectionError.SESSION_REJECTED) {
234 showConnectError_(remoting.Error.INVALID_ACCESS_CODE);
235 } else if (remoting.clientSession.error ==
236 remoting.ClientSession.ConnectionError.INCOMPATIBLE_PROTOCOL) {
237 showConnectError_(remoting.Error.INCOMPATIBLE_PROTOCOL);
238 } else if (remoting.clientSession.error ==
239 remoting.ClientSession.ConnectionError.NETWORK_FAILURE) {
240 showConnectError_(remoting.Error.GENERIC);
241 } else {
242 showConnectError_(remoting.Error.GENERIC);
243 }
244
245 } else {
246 remoting.debug.log('Unexpected client plugin state: ' + newState);
247 // This should only happen if the web-app and client plugin get out of
248 // sync, and even then the version check should allow compatibility.
249 showConnectError_(remoting.Error.MISSING_PLUGIN);
250 }
251 }
252
253 /**
254 * If we have a hostId to retry, try refreshing it and connecting again. If not,
255 * then show the 'host offline' error message.
256 *
257 * @return {void} Nothing.
258 */
259 function retryConnectOrReportOffline_() {
260 if (remoting.hostId && remoting.retryIfOffline) {
261 console.log('Connection failed. Retrying.');
262 /** @param {boolean} success True if the refresh was successful. */
263 var onDone = function(success) {
264 if (success) {
265 remoting.connectMe2Me(remoting.hostId, false);
266 } else {
267 showConnectError_(remoting.Error.HOST_IS_OFFLINE);
268 }
269 };
270 remoting.hostList.refresh(onDone);
271 } else {
272 console.log('Connection failed. Not retrying.');
273 showConnectError_(remoting.Error.HOST_IS_OFFLINE);
274 }
275 }
276
277 /**
278 * Create the client session object and initiate the connection.
279 *
280 * @return {void} Nothing.
281 */
282 function startSession_() {
283 remoting.debug.log('Starting session...');
284 var accessCode = document.getElementById('access-code-entry');
285 accessCode.value = ''; // The code has been validated and won't work again.
286 remoting.clientSession =
287 new remoting.ClientSession(
288 remoting.hostJid, remoting.hostPublicKey,
289 remoting.accessCode,
290 /** @type {string} */ (remoting.oauth2.getCachedEmail()),
291 onClientStateChange_);
292 /** @param {string} token The auth token. */
293 var createPluginAndConnect = function(token) {
294 remoting.clientSession.createPluginAndConnect(
295 document.getElementById('session-mode'),
296 token);
297 };
298 remoting.oauth2.callWithToken(createPluginAndConnect);
299 }
300
301 /**
302 * Show a client-side error message.
303 *
304 * @param {remoting.Error} errorTag The error to be localized and
305 * displayed.
306 * @return {void} Nothing.
307 */
308 function showConnectError_(errorTag) {
309 remoting.debug.log('Connection failed: ' + errorTag);
310 var errorDiv = document.getElementById('connect-error-message');
311 l10n.localizeElementFromTag(errorDiv, /** @type {string} */ (errorTag));
312 remoting.accessCode = '';
313 if (remoting.clientSession) {
314 remoting.clientSession.disconnect();
315 remoting.clientSession = null;
316 }
317 if (remoting.currentConnectionType == remoting.ConnectionType.It2Me) {
318 remoting.setMode(remoting.AppMode.CLIENT_CONNECT_FAILED_IT2ME);
319 } else {
320 remoting.setMode(remoting.AppMode.CLIENT_CONNECT_FAILED_ME2ME);
321 }
322 }
323
324 /**
325 * Parse the response from the server to a request to resolve a support id.
326 *
327 * @param {XMLHttpRequest} xhr The XMLHttpRequest object.
328 * @return {void} Nothing.
329 */
330 function parseServerResponse_(xhr) {
331 remoting.supportHostsXhr_ = null;
332 remoting.debug.log('parseServerResponse: status = ' + xhr.status);
333 if (xhr.status == 200) {
334 var host = /** @type {{data: {jabberId: string, publicKey: string}}} */
335 JSON.parse(xhr.responseText);
336 if (host.data && host.data.jabberId && host.data.publicKey) {
337 remoting.hostJid = host.data.jabberId;
338 remoting.hostPublicKey = host.data.publicKey;
339 var split = remoting.hostJid.split('/');
340 document.getElementById('connected-to').innerText = split[0];
341 startSession_();
342 return;
343 }
344 }
345 var errorMsg = remoting.Error.GENERIC;
346 if (xhr.status == 404) {
347 errorMsg = remoting.Error.INVALID_ACCESS_CODE;
348 } else if (xhr.status == 0) {
349 errorMsg = remoting.Error.NO_RESPONSE;
350 } else if (xhr.status == 503) {
351 errorMsg = remoting.Error.SERVICE_UNAVAILABLE;
352 } else {
353 remoting.debug.log('The server responded: ' + xhr.responseText);
354 }
355 showConnectError_(errorMsg);
356 }
357
358 /**
359 * Normalize the access code entered by the user.
360 *
361 * @param {string} accessCode The access code, as entered by the user.
362 * @return {string} The normalized form of the code (whitespace removed).
363 */
364 function normalizeAccessCode_(accessCode) {
365 // Trim whitespace.
366 // TODO(sergeyu): Do we need to do any other normalization here?
367 return accessCode.replace(/\s/g, '');
368 }
369
370 /**
371 * Initiate a request to the server to resolve a support ID.
372 *
373 * @param {string} supportId The canonicalized support ID.
374 */
375 function resolveSupportId(supportId) {
376 var headers = {
377 'Authorization': 'OAuth ' + remoting.oauth2.getAccessToken()
378 };
379
380 remoting.supportHostsXhr_ = remoting.xhr.get(
381 'https://www.googleapis.com/chromoting/v1/support-hosts/' +
382 encodeURIComponent(supportId),
383 parseServerResponse_,
384 '',
385 headers);
386 }
387
388 /**
389 * Timer callback to update the statistics panel.
390 */
391 function updateStatistics_() {
392 if (!remoting.clientSession ||
393 remoting.clientSession.state != remoting.ClientSession.State.CONNECTED) {
394 return;
395 }
396 var stats = remoting.clientSession.stats();
397 remoting.debug.updateStatistics(stats);
398 remoting.clientSession.logStatistics(stats);
399 // Update the stats once per second.
400 window.setTimeout(updateStatistics_, 1000);
401 }
402
403
404 /**
405 * Shows PIN entry screen.
406 *
407 * @param {string} hostId The unique id of the host.
408 * @param {boolean} retryIfOffline If true and the host can't be contacted,
409 * refresh the host list and try again. This allows bookmarked hosts to
410 * work even if they reregister with Talk and get a different Jid.
411 * @return {void} Nothing.
412 */
413 remoting.connectMe2Me = function(hostId, retryIfOffline) {
414 remoting.currentConnectionType = remoting.ConnectionType.Me2Me;
415 remoting.hostId = hostId;
416 remoting.retryIfOffline = retryIfOffline;
417
418 // TODO(jamiewalch): Reinstate the PIN screen once it's supported.
419 // remoting.setMode(remoting.AppMode.CLIENT_PIN_PROMPT);
420 remoting.connectMe2MeWithPin();
421 }
422
423 /**
424 * Start a connection to the specified host, using the cached details
425 * and the PIN entered by the user.
426 *
427 * @return {void} Nothing.
428 */
429 remoting.connectMe2MeWithPin = function() {
430 remoting.debug.log('Connecting to host...');
431 remoting.setMode(remoting.AppMode.CLIENT_CONNECTING);
432
433 var host = remoting.hostList.getHostForId(remoting.hostId);
434 if (!host) {
435 retryConnectOrReportOffline_();
436 return;
437 }
438 remoting.hostJid = host.jabberId;
439 remoting.hostPublicKey = host.publicKey;
440 document.getElementById('connected-to').innerText = host.hostName;
441 document.title = document.title + ': ' + host.hostName;
442
443 remoting.WcsLoader.load(connectMe2MeWithAccessToken_);
444 };
445
446 /**
447 * Continue making the connection to a host, once WCS has initialized.
448 *
449 * @param {string?} token The OAuth2 access token, or null if an error occurred.
450 * @return {void} Nothing.
451 */
452 function connectMe2MeWithAccessToken_(token) {
453 if (token) {
454 /** @type {string} */
455 var pin = document.getElementById('pin-entry').value;
456 document.getElementById('pin-entry').value = '';
457
458 remoting.clientSession =
459 new remoting.ClientSession(
460 remoting.hostJid, remoting.hostPublicKey,
461 pin, /** @type {string} */ (remoting.oauth2.getCachedEmail()),
462 onClientStateChange_);
463 remoting.clientSession.createPluginAndConnect(
464 document.getElementById('session-mode'),
465 token);
466 } else {
467 showConnectError_(remoting.Error.AUTHENTICATION_FAILED);
468 }
469 }
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