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 |
(...skipping 14 matching lines...) Expand all Loading... | |
25 /** | 25 /** |
26 * Interval that determines how often the web-app should send a new access token | 26 * Interval that determines how often the web-app should send a new access token |
27 * to the host. | 27 * to the host. |
28 * | 28 * |
29 * @const | 29 * @const |
30 * @type {number} | 30 * @type {number} |
31 */ | 31 */ |
32 remoting.ACCESS_TOKEN_RESEND_INTERVAL_MS = 15 * 60 * 1000; | 32 remoting.ACCESS_TOKEN_RESEND_INTERVAL_MS = 15 * 60 * 1000; |
33 | 33 |
34 /** | 34 /** |
35 * @param {remoting.ClientPlugin} plugin | |
35 * @param {remoting.Host} host The host to connect to. | 36 * @param {remoting.Host} host The host to connect to. |
36 * @param {remoting.SignalStrategy} signalStrategy Signal strategy. | 37 * @param {remoting.SignalStrategy} signalStrategy Signal strategy. |
37 * @param {remoting.CredentialsProvider} credentialsProvider | |
38 * The credentialsProvider to authenticate the client with the host. | |
39 * @param {HTMLElement} container Container element for the client view. | |
40 * @param {remoting.DesktopConnectedView.Mode} mode The mode of this connection. | 38 * @param {remoting.DesktopConnectedView.Mode} mode The mode of this connection. |
41 * @param {string} defaultRemapKeys The default set of remap keys, to use | |
42 * when the client doesn't define any. | |
43 * @constructor | 39 * @constructor |
44 * @extends {base.EventSourceImpl} | 40 * @extends {base.EventSourceImpl} |
45 * @implements {base.Disposable} | 41 * @implements {base.Disposable} |
46 */ | 42 */ |
47 remoting.ClientSession = function(host, signalStrategy, credentialsProvider, | 43 remoting.ClientSession = function(plugin, host, signalStrategy, mode) { |
kelvinp
2015/03/07 00:09:28
Awesome, right now the host is only used in the di
garykac
2015/03/07 01:53:10
Acknowledged.
| |
48 container, mode, defaultRemapKeys) { | |
49 /** @private */ | 44 /** @private */ |
50 this.state_ = remoting.ClientSession.State.CREATED; | 45 this.state_ = remoting.ClientSession.State.CREATED; |
51 | 46 |
52 /** @private */ | 47 /** @private */ |
53 this.error_ = remoting.Error.NONE; | 48 this.error_ = remoting.Error.NONE; |
54 | 49 |
55 /** @private */ | 50 /** @private */ |
56 this.host_ = host; | 51 this.host_ = host; |
57 | 52 |
58 /** @private */ | 53 /** @private */ |
59 this.credentialsProvider_ = credentialsProvider; | 54 this.sessionId_ = ''; |
60 | 55 |
61 /** @private */ | 56 /** @private */ |
62 this.uiHandler_ = new remoting.DesktopConnectedView( | |
63 this, container, this.host_, mode, defaultRemapKeys, | |
64 this.onPluginInitialized_.bind(this)); | |
65 remoting.desktopConnectedView = this.uiHandler_; | |
66 | |
67 /** @private */ | |
68 this.sessionId_ = ''; | |
69 /** @type {remoting.ClientPlugin} | |
70 * @private */ | |
71 this.plugin_ = null; | |
72 /** @private */ | |
73 this.hasReceivedFrame_ = false; | 57 this.hasReceivedFrame_ = false; |
74 this.logToServer = new remoting.LogToServer(signalStrategy, mode); | 58 this.logToServer = new remoting.LogToServer(signalStrategy, mode); |
75 | 59 |
76 /** @private */ | 60 /** @private */ |
77 this.signalStrategy_ = signalStrategy; | 61 this.signalStrategy_ = signalStrategy; |
78 base.debug.assert(this.signalStrategy_.getState() == | 62 base.debug.assert(this.signalStrategy_.getState() == |
79 remoting.SignalStrategy.State.CONNECTED); | 63 remoting.SignalStrategy.State.CONNECTED); |
80 this.signalStrategy_.setIncomingStanzaCallback( | 64 this.signalStrategy_.setIncomingStanzaCallback( |
81 this.onIncomingMessage_.bind(this)); | 65 this.onIncomingMessage_.bind(this)); |
82 remoting.formatIq.setJids(this.signalStrategy_.getJid(), host.jabberId); | 66 remoting.formatIq.setJids(this.signalStrategy_.getJid(), host.jabberId); |
83 | 67 |
84 /** | 68 /** |
85 * Allow host-offline error reporting to be suppressed in situations where it | 69 * Allow host-offline error reporting to be suppressed in situations where it |
86 * would not be useful, for example, when using a cached host JID. | 70 * would not be useful, for example, when using a cached host JID. |
87 * | 71 * |
88 * @type {boolean} @private | 72 * @type {boolean} @private |
89 */ | 73 */ |
90 this.logHostOfflineErrors_ = true; | 74 this.logHostOfflineErrors_ = true; |
91 | 75 |
92 /** @type {remoting.GnubbyAuthHandler} @private */ | 76 /** @type {remoting.GnubbyAuthHandler} @private */ |
93 this.gnubbyAuthHandler_ = null; | 77 this.gnubbyAuthHandler_ = null; |
94 | 78 |
95 /** @type {remoting.CastExtensionHandler} @private */ | 79 /** @type {remoting.CastExtensionHandler} @private */ |
96 this.castExtensionHandler_ = null; | 80 this.castExtensionHandler_ = null; |
97 | 81 |
82 /** @private {remoting.ClientPlugin} */ | |
83 this.plugin_ = plugin; | |
84 plugin.setOnOutgoingIqHandler(this.sendIq_.bind(this)); | |
85 plugin.setOnDebugMessageHandler(this.onDebugMessage_.bind(this)); | |
86 plugin.setConnectionStatusUpdateHandler( | |
87 this.onConnectionStatusUpdate_.bind(this)); | |
88 plugin.setRouteChangedHandler(this.onRouteChanged_.bind(this)); | |
89 plugin.setConnectionReadyHandler(this.onConnectionReady_.bind(this)); | |
90 plugin.setCapabilitiesHandler(this.onSetCapabilities_.bind(this)); | |
91 plugin.setGnubbyAuthHandler( | |
92 this.processGnubbyAuthMessage_.bind(this)); | |
93 plugin.setCastExtensionHandler( | |
94 this.processCastExtensionMessage_.bind(this)); | |
95 | |
98 this.defineEvents(Object.keys(remoting.ClientSession.Events)); | 96 this.defineEvents(Object.keys(remoting.ClientSession.Events)); |
99 }; | 97 }; |
100 | 98 |
101 base.extend(remoting.ClientSession, base.EventSourceImpl); | 99 base.extend(remoting.ClientSession, base.EventSourceImpl); |
102 | 100 |
103 /** @enum {string} */ | 101 /** @enum {string} */ |
104 remoting.ClientSession.Events = { | 102 remoting.ClientSession.Events = { |
105 stateChanged: 'stateChanged', | 103 stateChanged: 'stateChanged', |
106 videoChannelStateChanged: 'videoChannelStateChanged', | 104 videoChannelStateChanged: 'videoChannelStateChanged', |
107 }; | 105 }; |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
243 * the client and host. | 241 * the client and host. |
244 */ | 242 */ |
245 remoting.ClientSession.prototype.hasCapability = function(capability) { | 243 remoting.ClientSession.prototype.hasCapability = function(capability) { |
246 if (this.capabilities_ == null) | 244 if (this.capabilities_ == null) |
247 return false; | 245 return false; |
248 | 246 |
249 return this.capabilities_.indexOf(capability) > -1; | 247 return this.capabilities_.indexOf(capability) > -1; |
250 }; | 248 }; |
251 | 249 |
252 /** | 250 /** |
253 * Adds <embed> element to the UI container and readies the session object. | 251 * @return {void} Nothing. |
254 * | |
255 * @param {function(string, string):boolean} onExtensionMessage The handler for | |
256 * protocol extension messages. Returns true if a message is recognized; | |
257 * false otherwise. | |
258 * @param {Array<string>} requiredCapabilities A list of capabilities | |
259 * required by this application. | |
260 */ | 252 */ |
261 remoting.ClientSession.prototype.createPluginAndConnect = | 253 remoting.ClientSession.prototype.removePlugin = function() { |
262 function(onExtensionMessage, requiredCapabilities) { | 254 this.plugin_ = null; |
263 this.uiHandler_.createPluginAndConnect(onExtensionMessage, | |
264 requiredCapabilities); | |
265 }; | 255 }; |
266 | 256 |
267 /** | 257 /** |
268 * @param {remoting.Error} error | |
269 * @param {remoting.ClientPlugin} plugin | |
270 */ | |
271 remoting.ClientSession.prototype.onPluginInitialized_ = function( | |
272 error, plugin) { | |
273 if (error != remoting.Error.NONE) { | |
274 this.resetWithError_(error); | |
275 } | |
276 | |
277 this.plugin_ = plugin; | |
278 plugin.setOnOutgoingIqHandler(this.sendIq_.bind(this)); | |
279 plugin.setOnDebugMessageHandler(this.onDebugMessage_.bind(this)); | |
280 | |
281 plugin.setConnectionStatusUpdateHandler( | |
282 this.onConnectionStatusUpdate_.bind(this)); | |
283 plugin.setRouteChangedHandler(this.onRouteChanged_.bind(this)); | |
284 plugin.setConnectionReadyHandler(this.onConnectionReady_.bind(this)); | |
285 plugin.setCapabilitiesHandler(this.onSetCapabilities_.bind(this)); | |
286 plugin.setGnubbyAuthHandler( | |
287 this.processGnubbyAuthMessage_.bind(this)); | |
288 plugin.setCastExtensionHandler( | |
289 this.processCastExtensionMessage_.bind(this)); | |
290 | |
291 this.plugin_.connect( | |
292 this.host_, this.signalStrategy_.getJid(), this.credentialsProvider_); | |
293 }; | |
294 | |
295 /** | |
296 * @param {remoting.Error} error | |
297 */ | |
298 remoting.ClientSession.prototype.resetWithError_ = function(error) { | |
299 this.signalStrategy_.setIncomingStanzaCallback(null); | |
300 this.removePlugin(); | |
301 this.error_ = error; | |
302 this.setState_(remoting.ClientSession.State.FAILED); | |
303 }; | |
304 | |
305 /** | |
306 * Deletes the <embed> element from the container, without sending a | |
307 * session_terminate request. This is to be called when the session was | |
308 * disconnected by the Host. | |
309 * | |
310 * @return {void} Nothing. | |
311 */ | |
312 remoting.ClientSession.prototype.removePlugin = function() { | |
313 this.uiHandler_.removePlugin(); | |
314 this.plugin_ = null; | |
315 remoting.desktopConnectedView = null; | |
316 }; | |
317 | |
318 /** | |
319 * Disconnect the current session with a particular |error|. The session will | 258 * Disconnect the current session with a particular |error|. The session will |
320 * raise a |stateChanged| event in response to it. The caller should then call | 259 * raise a |stateChanged| event in response to it. The caller should then call |
321 * dispose() to remove and destroy the <embed> element. | 260 * dispose() to remove and destroy the <embed> element. |
322 * | 261 * |
323 * @param {remoting.Error} error The reason for the disconnection. Use | 262 * @param {remoting.Error} error The reason for the disconnection. Use |
324 * remoting.Error.NONE if there is no error. | 263 * remoting.Error.NONE if there is no error. |
325 * @return {void} Nothing. | 264 * @return {void} Nothing. |
326 */ | 265 */ |
327 remoting.ClientSession.prototype.disconnect = function(error) { | 266 remoting.ClientSession.prototype.disconnect = function(error) { |
328 var state = (error == remoting.Error.NONE) ? | 267 var state = (error == remoting.Error.NONE) ? |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
443 * Callback that the plugin invokes to indicate that the connection | 382 * Callback that the plugin invokes to indicate that the connection |
444 * status has changed. | 383 * status has changed. |
445 * | 384 * |
446 * @param {number} status The plugin's status. | 385 * @param {number} status The plugin's status. |
447 * @param {number} error The plugin's error state, if any. | 386 * @param {number} error The plugin's error state, if any. |
448 * @private | 387 * @private |
449 */ | 388 */ |
450 remoting.ClientSession.prototype.onConnectionStatusUpdate_ = | 389 remoting.ClientSession.prototype.onConnectionStatusUpdate_ = |
451 function(status, error) { | 390 function(status, error) { |
452 if (status == remoting.ClientSession.State.CONNECTED) { | 391 if (status == remoting.ClientSession.State.CONNECTED) { |
453 this.uiHandler_.updateClientSessionUi_(this); | 392 remoting.desktopConnectedView.updateClientSessionUi_(this); |
454 | 393 |
455 } else if (status == remoting.ClientSession.State.FAILED) { | 394 } else if (status == remoting.ClientSession.State.FAILED) { |
456 switch (error) { | 395 switch (error) { |
457 case remoting.ClientSession.ConnectionError.HOST_IS_OFFLINE: | 396 case remoting.ClientSession.ConnectionError.HOST_IS_OFFLINE: |
458 this.error_ = remoting.Error.HOST_IS_OFFLINE; | 397 this.error_ = remoting.Error.HOST_IS_OFFLINE; |
459 break; | 398 break; |
460 case remoting.ClientSession.ConnectionError.SESSION_REJECTED: | 399 case remoting.ClientSession.ConnectionError.SESSION_REJECTED: |
461 this.error_ = remoting.Error.INVALID_ACCESS_CODE; | 400 this.error_ = remoting.Error.INVALID_ACCESS_CODE; |
462 break; | 401 break; |
463 case remoting.ClientSession.ConnectionError.INCOMPATIBLE_PROTOCOL: | 402 case remoting.ClientSession.ConnectionError.INCOMPATIBLE_PROTOCOL: |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
502 // TODO(jamiewalch): Currently, the logic for determining whether or not the | 441 // TODO(jamiewalch): Currently, the logic for determining whether or not the |
503 // connection is available is based solely on whether or not any video frames | 442 // connection is available is based solely on whether or not any video frames |
504 // have been received recently. which leads to poor UX on slow connections. | 443 // have been received recently. which leads to poor UX on slow connections. |
505 // Re-enable this once crbug.com/435315 has been fixed. | 444 // Re-enable this once crbug.com/435315 has been fixed. |
506 var ignoreVideoChannelState = true; | 445 var ignoreVideoChannelState = true; |
507 if (ignoreVideoChannelState) { | 446 if (ignoreVideoChannelState) { |
508 console.log('Video channel ' + (ready ? '' : 'not ') + 'ready.'); | 447 console.log('Video channel ' + (ready ? '' : 'not ') + 'ready.'); |
509 return; | 448 return; |
510 } | 449 } |
511 | 450 |
512 this.uiHandler_.onConnectionReady(ready); | 451 remoting.desktopConnectedView.onConnectionReady(ready); |
513 | 452 |
514 this.raiseEvent(remoting.ClientSession.Events.videoChannelStateChanged, | 453 this.raiseEvent(remoting.ClientSession.Events.videoChannelStateChanged, |
515 ready); | 454 ready); |
516 }; | 455 }; |
517 | 456 |
518 /** | 457 /** |
519 * Called when the client-host capabilities negotiation is complete. | 458 * Called when the client-host capabilities negotiation is complete. |
520 * TODO(kelvinp): Move this function out of ClientSession. | 459 * TODO(kelvinp): Move this function out of ClientSession. |
521 * | 460 * |
522 * @param {!Array<string>} capabilities The set of capabilities negotiated | 461 * @param {!Array<string>} capabilities The set of capabilities negotiated |
523 * between the client and host. | 462 * between the client and host. |
524 * @return {void} Nothing. | 463 * @return {void} Nothing. |
525 * @private | 464 * @private |
526 */ | 465 */ |
527 remoting.ClientSession.prototype.onSetCapabilities_ = function(capabilities) { | 466 remoting.ClientSession.prototype.onSetCapabilities_ = function(capabilities) { |
528 if (this.capabilities_ != null) { | 467 if (this.capabilities_ != null) { |
529 console.error('onSetCapabilities_() is called more than once'); | 468 console.error('onSetCapabilities_() is called more than once'); |
530 return; | 469 return; |
531 } | 470 } |
532 | 471 |
533 this.capabilities_ = capabilities; | 472 this.capabilities_ = capabilities; |
534 if (this.hasCapability(remoting.ClientSession.Capability.GOOGLE_DRIVE)) { | 473 if (this.hasCapability(remoting.ClientSession.Capability.GOOGLE_DRIVE)) { |
535 this.sendGoogleDriveAccessToken_(); | 474 this.sendGoogleDriveAccessToken_(); |
536 } | 475 } |
537 if (this.hasCapability( | 476 if (this.hasCapability( |
538 remoting.ClientSession.Capability.VIDEO_RECORDER)) { | 477 remoting.ClientSession.Capability.VIDEO_RECORDER)) { |
539 this.uiHandler_.initVideoFrameRecorder(); | 478 remoting.desktopConnectedView.initVideoFrameRecorder(); |
540 } | 479 } |
541 }; | 480 }; |
542 | 481 |
543 /** | 482 /** |
544 * @param {remoting.ClientSession.State} newState The new state for the session. | 483 * @param {remoting.ClientSession.State} newState The new state for the session. |
545 * @return {void} Nothing. | 484 * @return {void} Nothing. |
546 * @private | 485 * @private |
547 */ | 486 */ |
548 remoting.ClientSession.prototype.setState_ = function(newState) { | 487 remoting.ClientSession.prototype.setState_ = function(newState) { |
549 var oldState = this.state_; | 488 var oldState = this.state_; |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
668 console.error('Received unexpected gnubby message'); | 607 console.error('Received unexpected gnubby message'); |
669 } | 608 } |
670 }; | 609 }; |
671 | 610 |
672 /** | 611 /** |
673 * Create a gnubby auth handler and inform the host that gnubby auth is | 612 * Create a gnubby auth handler and inform the host that gnubby auth is |
674 * supported. | 613 * supported. |
675 * @private | 614 * @private |
676 */ | 615 */ |
677 remoting.ClientSession.prototype.createGnubbyAuthHandler_ = function() { | 616 remoting.ClientSession.prototype.createGnubbyAuthHandler_ = function() { |
678 if (this.uiHandler_.getMode() == remoting.DesktopConnectedView.Mode.ME2ME) { | 617 if (remoting.desktopConnectedView.getMode() == |
618 remoting.DesktopConnectedView.Mode.ME2ME) { | |
679 this.gnubbyAuthHandler_ = new remoting.GnubbyAuthHandler(this); | 619 this.gnubbyAuthHandler_ = new remoting.GnubbyAuthHandler(this); |
680 // TODO(psj): Move to more generic capabilities mechanism. | 620 // TODO(psj): Move to more generic capabilities mechanism. |
681 this.sendGnubbyAuthMessage({'type': 'control', 'option': 'auth-v1'}); | 621 this.sendGnubbyAuthMessage({'type': 'control', 'option': 'auth-v1'}); |
682 } | 622 } |
683 }; | 623 }; |
684 | 624 |
685 /** | 625 /** |
686 * Timer callback to send the access token to the host. | 626 * Timer callback to send the access token to the host. |
687 * @private | 627 * @private |
688 */ | 628 */ |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
735 } | 675 } |
736 }; | 676 }; |
737 | 677 |
738 /** | 678 /** |
739 * Create a CastExtensionHandler and inform the host that cast extension | 679 * Create a CastExtensionHandler and inform the host that cast extension |
740 * is supported. | 680 * is supported. |
741 * @private | 681 * @private |
742 */ | 682 */ |
743 remoting.ClientSession.prototype.createCastExtensionHandler_ = function() { | 683 remoting.ClientSession.prototype.createCastExtensionHandler_ = function() { |
744 if (remoting.app.hasCapability(remoting.ClientSession.Capability.CAST) && | 684 if (remoting.app.hasCapability(remoting.ClientSession.Capability.CAST) && |
745 this.uiHandler_.getMode() == remoting.DesktopConnectedView.Mode.ME2ME) { | 685 remoting.desktopConnectedView.getMode() == |
686 remoting.DesktopConnectedView.Mode.ME2ME) { | |
746 this.castExtensionHandler_ = new remoting.CastExtensionHandler(this); | 687 this.castExtensionHandler_ = new remoting.CastExtensionHandler(this); |
747 } | 688 } |
748 }; | 689 }; |
749 | 690 |
750 /** | 691 /** |
751 * Handles protocol extension messages. | 692 * Handles protocol extension messages. |
752 * @param {string} type Type of extension message. | 693 * @param {string} type Type of extension message. |
753 * @param {Object} message The parsed extension message data. | 694 * @param {Object} message The parsed extension message data. |
754 * @return {boolean} True if the message was recognized, false otherwise. | 695 * @return {boolean} True if the message was recognized, false otherwise. |
755 */ | 696 */ |
756 remoting.ClientSession.prototype.handleExtensionMessage = | 697 remoting.ClientSession.prototype.handleExtensionMessage = |
757 function(type, message) { | 698 function(type, message) { |
758 if (this.uiHandler_.handleExtensionMessage(type, message)) { | 699 if (remoting.desktopConnectedView.handleExtensionMessage(type, message)) { |
759 return true; | 700 return true; |
760 } | 701 } |
761 return false; | 702 return false; |
762 }; | 703 }; |
763 | 704 |
764 /** | 705 /** |
765 * Enables or disables rendering of dirty regions for debugging. | 706 * Enables or disables rendering of dirty regions for debugging. |
766 * @param {boolean} enable True to enable rendering. | 707 * @param {boolean} enable True to enable rendering. |
767 */ | 708 */ |
768 remoting.ClientSession.prototype.enableDebugRegion = function(enable) { | 709 remoting.ClientSession.prototype.enableDebugRegion = function(enable) { |
769 if (enable) { | 710 if (enable) { |
770 this.plugin_.setDebugDirtyRegionHandler( | 711 this.plugin_.setDebugDirtyRegionHandler( |
771 this.uiHandler_.handleDebugRegion.bind(this.uiHandler_)); | 712 remoting.desktopConnectedView.handleDebugRegion.bind( |
713 remoting.desktopConnectedView)); | |
772 } else { | 714 } else { |
773 this.plugin_.setDebugDirtyRegionHandler(null); | 715 this.plugin_.setDebugDirtyRegionHandler(null); |
774 } | 716 } |
775 } | 717 } |
OLD | NEW |