All files / realtime TransportManager.ts

86.67% Statements 26/30
72.22% Branches 13/18
100% Functions 7/7
86.21% Lines 25/29
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107                                12x 12x 12x                       12x             12x 5x             18x             12x   18x   18x   18x                 18x 13x   5x 5x     10x 10x                     12x 18x 18x                   12x 17x 4x   13x     12x  
/**
 * Copyright 2017 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
import { BrowserPollConnection } from './BrowserPollConnection';
import { WebSocketConnection } from './WebSocketConnection';
import { warn, each } from '../core/util/util';
import { TransportConstructor } from './Transport';
import { RepoInfo } from '../core/RepoInfo';
 
/**
 * Currently simplistic, this class manages what transport a Connection should use at various stages of its
 * lifecycle.
 *
 * It starts with longpolling in a browser, and httppolling on node. It then upgrades to websockets if
 * they are available.
 * @constructor
 */
export class TransportManager {
  private transports_: TransportConstructor[];
 
  /**
   * @const
   * @type {!Array.<function(new:Transport, string, RepoInfo, string=)>}
   */
  static get ALL_TRANSPORTS() {
    return [BrowserPollConnection, WebSocketConnection];
  }
 
  /**
   * @param {!RepoInfo} repoInfo Metadata around the namespace we're connecting to
   */
  constructor(repoInfo: RepoInfo) {
    this.initTransports_(repoInfo);
  }
 
  /**
   * @param {!RepoInfo} repoInfo
   * @private
   */
  private initTransports_(repoInfo: RepoInfo) {
    const isWebSocketsAvailable: boolean =
      WebSocketConnection && WebSocketConnection['isAvailable']();
    let isSkipPollConnection =
      isWebSocketsAvailable && !WebSocketConnection.previouslyFailed();
 
    Iif (repoInfo.webSocketOnly) {
      if (!isWebSocketsAvailable)
        warn(
          "wss:// URL used, but browser isn't known to support websockets.  Trying anyway."
        );
 
      isSkipPollConnection = true;
    }
 
    if (isSkipPollConnection) {
      this.transports_ = [WebSocketConnection];
    } else {
      const transports = (this.transports_ = [] as TransportConstructor[]);
      each(
        TransportManager.ALL_TRANSPORTS,
        (i: number, transport: TransportConstructor) => {
          Eif (transport && transport['isAvailable']()) {
            transports.push(transport);
          }
        }
      );
    }
  }
 
  /**
   * @return {function(new:Transport, !string, !RepoInfo, string=, string=)} The constructor for the
   * initial transport to use
   */
  initialTransport(): TransportConstructor {
    Eif (this.transports_.length > 0) {
      return this.transports_[0];
    } else {
      throw new Error('No transports available');
    }
  }
 
  /**
   * @return {?function(new:Transport, function(),function(), string=)} The constructor for the next
   * transport, or null
   */
  upgradeTransport(): TransportConstructor | null {
    if (this.transports_.length > 1) {
      return this.transports_[1];
    } else {
      return null;
    }
  }
}