Home | History | Annotate | Download | only in webapp
      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} */
     18 var 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  */
     29 remoting.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.
     63 remoting.SmartReconnector.kReconnectDelay = 2000;
     64 
     65 // If the video channel is inactive for 10 seconds reconnect the session.
     66 remoting.SmartReconnector.kConnectionTimeout = 10000;
     67 
     68 remoting.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