1// Copyright 2014 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 * Class handling reconnecting the session when it is disconnected due to 8 * network failure. 9 * 10 * The SmartReconnector listens for changes in connection state of 11 * |clientSession| to determine if a reconnection is needed. It then calls into 12 * |connector| to reconnect the session. 13 */ 14 15'use strict'; 16 17/** @suppress {duplicate} */ 18var remoting = remoting || {}; 19 20/** 21 * @constructor 22 * @param {remoting.SessionConnector} connector This is used to reconnect the 23 * the session when necessary 24 * @param {remoting.ClientSession} clientSession This represents the current 25 * remote desktop connection. It is used to monitor the changes in 26 * connection state. 27 * @implements {base.Disposable} 28 */ 29remoting.SmartReconnector = function(connector, clientSession) { 30 /** @private */ 31 this.connector_ = connector; 32 33 /** @private */ 34 this.clientSession_ = clientSession; 35 36 /** @private */ 37 this.reconnectTimerId_ = null; 38 39 /** @private */ 40 this.connectionTimeoutTimerId_ = null; 41 42 /** @private */ 43 this.bound_ = { 44 reconnect: this.reconnect_.bind(this), 45 reconnectAsync: this.reconnectAsync_.bind(this), 46 startReconnectTimeout: this.startReconnectTimeout_.bind(this), 47 stateChanged: this.stateChanged_.bind(this), 48 videoChannelStateChanged: this.videoChannelStateChanged_.bind(this) 49 }; 50 51 clientSession.addEventListener( 52 remoting.ClientSession.Events.stateChanged, 53 this.bound_.stateChanged); 54 clientSession.addEventListener( 55 remoting.ClientSession.Events.videoChannelStateChanged, 56 this.bound_.videoChannelStateChanged); 57}; 58 59// The online event only means the network adapter is enabled, but 60// it doesn't necessarily mean that we have a working internet connection. 61// Therefore, delay the connection by |kReconnectDelay| to allow for the network 62// to connect. 63remoting.SmartReconnector.kReconnectDelay = 2000; 64 65// If the video channel is inactive for 10 seconds reconnect the session. 66remoting.SmartReconnector.kConnectionTimeout = 10000; 67 68remoting.SmartReconnector.prototype = { 69 reconnect_: function() { 70 this.cancelPending_(); 71 remoting.disconnect(); 72 remoting.setMode(remoting.AppMode.CLIENT_CONNECTING); 73 this.connector_.reconnect(); 74 }, 75 76 reconnectAsync_: function() { 77 this.cancelPending_(); 78 remoting.setMode(remoting.AppMode.CLIENT_CONNECTING); 79 this.reconnectTimerId_ = window.setTimeout( 80 this.bound_.reconnect, remoting.SmartReconnector.kReconnectDelay); 81 }, 82 83 /** 84 * @param {remoting.ClientSession.StateEvent} event 85 */ 86 stateChanged_: function(event) { 87 var State = remoting.ClientSession.State; 88 if (event.previous === State.CONNECTED && event.current === State.FAILED) { 89 this.cancelPending_(); 90 if (navigator.onLine) { 91 this.reconnect_(); 92 } else { 93 window.addEventListener('online', this.bound_.reconnectAsync, false); 94 } 95 } 96 }, 97 98 /** 99 * @param {boolean} active True if the video channel is active. 100 */ 101 videoChannelStateChanged_: function (active) { 102 this.cancelPending_(); 103 if (!active) { 104 window.addEventListener( 105 'online', this.bound_.startReconnectTimeout, false); 106 } 107 }, 108 109 startReconnectTimeout_: function () { 110 this.cancelPending_(); 111 this.connectionTimeoutTimerId_ = window.setTimeout( 112 this.bound_.reconnect, remoting.SmartReconnector.kConnectionTimeout); 113 }, 114 115 cancelPending_: function() { 116 window.removeEventListener( 117 'online', this.bound_.startReconnectTimeout, false); 118 window.removeEventListener('online', this.bound_.reconnectAsync, false); 119 window.clearTimeout(this.reconnectTimerId_); 120 window.clearTimeout(this.connectionTimeoutTimerId_); 121 this.reconnectTimerId_ = null; 122 this.connectionTimeoutTimerId_ = null; 123 }, 124 125 dispose: function() { 126 this.clientSession_.removeEventListener( 127 remoting.ClientSession.Events.stateChanged, 128 this.bound_.stateChanged); 129 this.clientSession_.removeEventListener( 130 remoting.ClientSession.Events.videoChannelStateChanged, 131 this.bound_.videoChannelStateChanged); 132 } 133}; 134