OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview | 6 * @fileoverview |
7 * Class handling creation and teardown of a remoting client session. | 7 * Class handling creation and teardown of a remoting client session. |
8 * | 8 * |
9 * The ClientSession class controls lifetime of the client plugin | 9 * The ClientSession class controls lifetime of the client plugin |
10 * object and provides the plugin with the functionality it needs to | 10 * object and provides the plugin with the functionality it needs to |
11 * establish connection. Specifically it: | 11 * establish connection. Specifically it: |
12 * - Delivers incoming/outgoing signaling messages, | 12 * - Delivers incoming/outgoing signaling messages, |
13 * - Adjusts plugin size and position when destop resolution changes, | 13 * - Adjusts plugin size and position when destop resolution changes, |
14 * | 14 * |
15 * This class should not access the plugin directly, instead it should | 15 * This class should not access the plugin directly, instead it should |
16 * do it through ClientPlugin class which abstracts plugin version | 16 * do it through ClientPlugin class which abstracts plugin version |
17 * differences. | 17 * differences. |
18 */ | 18 */ |
19 | 19 |
20 'use strict'; | 20 'use strict'; |
21 | 21 |
22 /** @suppress {duplicate} */ | 22 /** @suppress {duplicate} */ |
23 var remoting = remoting || {}; | 23 var remoting = remoting || {}; |
24 | 24 |
25 /** | 25 /** |
26 * @param {string} hostJid The jid of the host to connect to. | 26 * @param {string} hostJid The jid of the host to connect to. |
27 * @param {string} clientJid The jid of the WCS client. | 27 * @param {string} clientJid The jid of the WCS client. |
28 * @param {string} hostPublicKey The base64 encoded version of the host's | 28 * @param {string} hostPublicKey The base64 encoded version of the host's |
29 * public key. | 29 * public key. |
30 * @param {string} sharedSecret The access code for IT2Me or the PIN | 30 * @param {string} accessCode The IT2Me access code. Blank for Me2Me. |
31 * for Me2Me. | 31 * @param {function(function(string): void): void} fetchPin Called by Me2Me |
| 32 * connections when a PIN needs to be obtained interactively. |
32 * @param {string} authenticationMethods Comma-separated list of | 33 * @param {string} authenticationMethods Comma-separated list of |
33 * authentication methods the client should attempt to use. | 34 * authentication methods the client should attempt to use. |
34 * @param {string} hostId The host identifier for Me2Me, or empty for IT2Me. | 35 * @param {string} hostId The host identifier for Me2Me, or empty for IT2Me. |
35 * Mixed into authentication hashes for some authentication methods. | 36 * Mixed into authentication hashes for some authentication methods. |
36 * @param {remoting.ClientSession.Mode} mode The mode of this connection. | 37 * @param {remoting.ClientSession.Mode} mode The mode of this connection. |
37 * @param {string} hostDisplayName The name of the host for display purposes. | 38 * @param {string} hostDisplayName The name of the host for display purposes. |
38 * @constructor | 39 * @constructor |
39 */ | 40 */ |
40 remoting.ClientSession = function(hostJid, clientJid, | 41 remoting.ClientSession = function(hostJid, clientJid, hostPublicKey, accessCode, |
41 hostPublicKey, sharedSecret, | 42 fetchPin, authenticationMethods, hostId, |
42 authenticationMethods, hostId, mode, | 43 mode, hostDisplayName) { |
43 hostDisplayName) { | |
44 this.state = remoting.ClientSession.State.CREATED; | 44 this.state = remoting.ClientSession.State.CREATED; |
45 | 45 |
46 this.hostJid = hostJid; | 46 this.hostJid = hostJid; |
47 this.clientJid = clientJid; | 47 this.clientJid = clientJid; |
48 this.hostPublicKey = hostPublicKey; | 48 this.hostPublicKey = hostPublicKey; |
49 this.sharedSecret = sharedSecret; | 49 /** @private */ |
| 50 this.accessCode_ = accessCode; |
| 51 /** @private */ |
| 52 this.fetchPin_ = fetchPin; |
50 this.authenticationMethods = authenticationMethods; | 53 this.authenticationMethods = authenticationMethods; |
51 this.hostId = hostId; | 54 this.hostId = hostId; |
52 /** @type {string} */ | 55 /** @type {string} */ |
53 this.hostDisplayName = hostDisplayName; | 56 this.hostDisplayName = hostDisplayName; |
54 /** @type {remoting.ClientSession.Mode} */ | 57 /** @type {remoting.ClientSession.Mode} */ |
55 this.mode = mode; | 58 this.mode = mode; |
56 this.sessionId = ''; | 59 this.sessionId = ''; |
57 /** @type {remoting.ClientPlugin} */ | 60 /** @type {remoting.ClientPlugin} */ |
58 this.plugin = null; | 61 this.plugin = null; |
59 /** @private */ | 62 /** @private */ |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 this.resizeToClient_ = /** @type {boolean} */ | 290 this.resizeToClient_ = /** @type {boolean} */ |
288 options[remoting.ClientSession.KEY_RESIZE_TO_CLIENT]; | 291 options[remoting.ClientSession.KEY_RESIZE_TO_CLIENT]; |
289 } | 292 } |
290 if (remoting.ClientSession.KEY_SHRINK_TO_FIT in options && | 293 if (remoting.ClientSession.KEY_SHRINK_TO_FIT in options && |
291 typeof(options[remoting.ClientSession.KEY_SHRINK_TO_FIT]) == | 294 typeof(options[remoting.ClientSession.KEY_SHRINK_TO_FIT]) == |
292 'boolean') { | 295 'boolean') { |
293 this.shrinkToFit_ = /** @type {boolean} */ | 296 this.shrinkToFit_ = /** @type {boolean} */ |
294 options[remoting.ClientSession.KEY_SHRINK_TO_FIT]; | 297 options[remoting.ClientSession.KEY_SHRINK_TO_FIT]; |
295 } | 298 } |
296 | 299 |
297 this.plugin.element().focus(); | |
298 | |
299 /** @param {boolean} result */ | 300 /** @param {boolean} result */ |
300 this.plugin.initialize(this.onPluginInitialized_.bind(this)); | 301 this.plugin.initialize(this.onPluginInitialized_.bind(this)); |
| 302 }; |
| 303 |
| 304 /** |
| 305 * Constrains the focus to the plugin element. |
| 306 * @private |
| 307 */ |
| 308 remoting.ClientSession.prototype.setFocusHandlers_ = function() { |
301 this.plugin.element().addEventListener( | 309 this.plugin.element().addEventListener( |
302 'focus', this.callPluginGotFocus_, false); | 310 'focus', this.callPluginGotFocus_, false); |
303 this.plugin.element().addEventListener( | 311 this.plugin.element().addEventListener( |
304 'blur', this.callPluginLostFocus_, false); | 312 'blur', this.callPluginLostFocus_, false); |
| 313 this.plugin.element().focus(); |
305 }; | 314 }; |
306 | 315 |
307 /** | 316 /** |
308 * @param {boolean} initialized | 317 * @param {boolean} initialized |
309 */ | 318 */ |
310 remoting.ClientSession.prototype.onPluginInitialized_ = function(initialized) { | 319 remoting.ClientSession.prototype.onPluginInitialized_ = function(initialized) { |
311 if (!initialized) { | 320 if (!initialized) { |
312 console.error('ERROR: remoting plugin not loaded'); | 321 console.error('ERROR: remoting plugin not loaded'); |
313 this.plugin.cleanup(); | 322 this.plugin.cleanup(); |
314 delete this.plugin; | 323 delete this.plugin; |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
585 }; | 594 }; |
586 | 595 |
587 /** | 596 /** |
588 * Connects the plugin to WCS. | 597 * Connects the plugin to WCS. |
589 * | 598 * |
590 * @private | 599 * @private |
591 * @return {void} Nothing. | 600 * @return {void} Nothing. |
592 */ | 601 */ |
593 remoting.ClientSession.prototype.connectPluginToWcs_ = function() { | 602 remoting.ClientSession.prototype.connectPluginToWcs_ = function() { |
594 remoting.formatIq.setJids(this.clientJid, this.hostJid); | 603 remoting.formatIq.setJids(this.clientJid, this.hostJid); |
| 604 /** @type {remoting.ClientPlugin} */ |
595 var plugin = this.plugin; | 605 var plugin = this.plugin; |
596 var forwardIq = plugin.onIncomingIq.bind(plugin); | 606 var forwardIq = plugin.onIncomingIq.bind(plugin); |
597 /** @param {string} stanza The IQ stanza received. */ | 607 /** @param {string} stanza The IQ stanza received. */ |
598 var onIncomingIq = function(stanza) { | 608 var onIncomingIq = function(stanza) { |
599 // HACK: Remove 'x' prefix added to the id in sendIq_(). | 609 // HACK: Remove 'x' prefix added to the id in sendIq_(). |
600 try { | 610 try { |
601 var parser = new DOMParser(); | 611 var parser = new DOMParser(); |
602 var iqNode = parser.parseFromString(stanza, 'text/xml').firstChild; | 612 var iqNode = parser.parseFromString(stanza, 'text/xml').firstChild; |
603 var type = iqNode.getAttribute('type'); | 613 var type = iqNode.getAttribute('type'); |
604 var id = iqNode.getAttribute('id'); | 614 var id = iqNode.getAttribute('id'); |
605 if (type != 'set' && id.charAt(0) == 'x') { | 615 if (type != 'set' && id.charAt(0) == 'x') { |
606 iqNode.setAttribute('id', id.substr(1)); | 616 iqNode.setAttribute('id', id.substr(1)); |
607 stanza = (new XMLSerializer()).serializeToString(iqNode); | 617 stanza = (new XMLSerializer()).serializeToString(iqNode); |
608 } | 618 } |
609 } catch (err) { | 619 } catch (err) { |
610 // Pass message as is when it is malformed. | 620 // Pass message as is when it is malformed. |
611 } | 621 } |
612 | 622 |
613 console.log(remoting.timestamp(), | 623 console.log(remoting.timestamp(), |
614 remoting.formatIq.prettifyReceiveIq(stanza)); | 624 remoting.formatIq.prettifyReceiveIq(stanza)); |
615 forwardIq(stanza); | 625 forwardIq(stanza); |
| 626 }; |
| 627 remoting.wcsSandbox.setOnIq(onIncomingIq); |
| 628 |
| 629 if (this.accessCode_) { |
| 630 // Shared secret was already supplied before connecting (It2Me case). |
| 631 this.connectToHost_(this.accessCode_); |
| 632 |
| 633 } else if (plugin.hasFeature( |
| 634 remoting.ClientPlugin.Feature.ASYNC_PIN)) { |
| 635 // Plugin supports asynchronously asking for the PIN. |
| 636 plugin.useAsyncPinDialog(); |
| 637 /** @type remoting.ClientSession */ |
| 638 var that = this; |
| 639 var fetchPin = function() { |
| 640 that.fetchPin_(plugin.onPinFetched.bind(plugin)); |
| 641 }; |
| 642 plugin.fetchPinHandler = fetchPin; |
| 643 this.connectToHost_(''); |
| 644 |
| 645 } else { |
| 646 // Plugin doesn't support asynchronously asking for the PIN, ask now. |
| 647 this.fetchPin_(this.connectToHost_.bind(this)); |
616 } | 648 } |
617 remoting.wcsSandbox.setOnIq(onIncomingIq); | 649 }; |
| 650 |
| 651 /** |
| 652 * Connects to the host. |
| 653 * |
| 654 * @param {string} sharedSecret Shared secret for SPAKE negotiation. |
| 655 * @return {void} Nothing. |
| 656 * @private |
| 657 */ |
| 658 remoting.ClientSession.prototype.connectToHost_ = function(sharedSecret) { |
618 this.plugin.connect(this.hostJid, this.hostPublicKey, this.clientJid, | 659 this.plugin.connect(this.hostJid, this.hostPublicKey, this.clientJid, |
619 this.sharedSecret, this.authenticationMethods, | 660 sharedSecret, this.authenticationMethods, |
620 this.hostId); | 661 this.hostId); |
621 }; | 662 }; |
622 | 663 |
623 /** | 664 /** |
624 * Callback that the plugin invokes to indicate that the connection | 665 * Callback that the plugin invokes to indicate that the connection |
625 * status has changed. | 666 * status has changed. |
626 * | 667 * |
627 * @private | 668 * @private |
628 * @param {number} status The plugin's status. | 669 * @param {number} status The plugin's status. |
629 * @param {number} error The plugin's error state, if any. | 670 * @param {number} error The plugin's error state, if any. |
630 */ | 671 */ |
631 remoting.ClientSession.prototype.onConnectionStatusUpdate_ = | 672 remoting.ClientSession.prototype.onConnectionStatusUpdate_ = |
632 function(status, error) { | 673 function(status, error) { |
633 if (status == remoting.ClientSession.State.CONNECTED) { | 674 if (status == remoting.ClientSession.State.CONNECTED) { |
| 675 this.setFocusHandlers_(); |
634 this.onDesktopSizeChanged_(); | 676 this.onDesktopSizeChanged_(); |
635 if (this.resizeToClient_) { | 677 if (this.resizeToClient_) { |
636 this.plugin.notifyClientResolution(window.innerWidth, | 678 this.plugin.notifyClientResolution(window.innerWidth, |
637 window.innerHeight, | 679 window.innerHeight, |
638 window.devicePixelRatio); | 680 window.devicePixelRatio); |
639 } | 681 } |
640 } else if (status == remoting.ClientSession.State.FAILED) { | 682 } else if (status == remoting.ClientSession.State.FAILED) { |
641 this.error_ = /** @type {remoting.ClientSession.ConnectionError} */ (error); | 683 this.error_ = /** @type {remoting.ClientSession.ConnectionError} */ (error); |
642 } | 684 } |
643 this.setState_(/** @type {remoting.ClientSession.State} */ (status)); | 685 this.setState_(/** @type {remoting.ClientSession.State} */ (status)); |
(...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1028 var lateAdjustment = 1 + (now - expected) / timeout; | 1070 var lateAdjustment = 1 + (now - expected) / timeout; |
1029 if (!that.scroll_(lateAdjustment * dx, lateAdjustment * dy)) { | 1071 if (!that.scroll_(lateAdjustment * dx, lateAdjustment * dy)) { |
1030 that.bumpScrollTimer_ = window.setTimeout( | 1072 that.bumpScrollTimer_ = window.setTimeout( |
1031 function() { repeatScroll(now + timeout); }, | 1073 function() { repeatScroll(now + timeout); }, |
1032 timeout); | 1074 timeout); |
1033 } | 1075 } |
1034 }; | 1076 }; |
1035 repeatScroll(new Date().getTime()); | 1077 repeatScroll(new Date().getTime()); |
1036 } | 1078 } |
1037 }; | 1079 }; |
OLD | NEW |