Javascript  |  147行  |  4.43 KB

/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/**
 * @fileoverview
 * A class that loads a WCS IQ client and constructs remoting.wcs as a
 * wrapper for it.
 */

'use strict';

/** @suppress {duplicate} */
var remoting = remoting || {};

/** @type {remoting.WcsLoader} */
remoting.wcsLoader = null;

/**
 * @constructor
 */
remoting.WcsLoader = function() {
  /**
   * The WCS client that will be downloaded. This variable is initialized (via
   * remoting.wcsLoader) by the downloaded Javascript.
   * @type {remoting.WcsIqClient}
   */
  this.wcsIqClient = null;
};

/**
 * The id of the script node.
 * @type {string}
 * @private
 */
remoting.WcsLoader.prototype.SCRIPT_NODE_ID_ = 'wcs-script-node';

/**
 * Starts loading the WCS IQ client.
 *
 * When it's loaded, construct remoting.wcs as a wrapper for it.
 * When the WCS connection is ready, or on error, call |onReady| or |onError|,
 * respectively.
 *
 * @param {string} token An OAuth2 access token.
 * @param {function(string): void} onReady The callback function, called with
 *     a client JID when WCS has been loaded.
 * @param {function(remoting.Error):void} onError Function to invoke with an
 *     error code on failure.
 * @return {void} Nothing.
 */
remoting.WcsLoader.prototype.start = function(token, onReady, onError) {
  var node = document.getElementById(this.SCRIPT_NODE_ID_);
  if (node) {
    console.error('Multiple calls to WcsLoader.start are not allowed.');
    onError(remoting.Error.UNEXPECTED);
    return;
  }

  // Create a script node to load the WCS driver.
  node = document.createElement('script');
  node.id = this.SCRIPT_NODE_ID_;
  node.src = remoting.settings.TALK_GADGET_URL + 'iq?access_token=' + token;
  node.type = 'text/javascript';
  document.body.insertBefore(node, document.body.firstChild);

  /** @type {remoting.WcsLoader} */
  var that = this;
  var onLoad = function() {
    that.constructWcs_(token, onReady);
  };
  var onLoadError = function(event) {
    // The DOM Event object has no detail on the nature of the error, so try to
    // validate the token to get a better idea.
    /** @param {remoting.Error} error Error code. */
    var onValidateError = function(error) {
      var typedNode = /** @type {Element} */ (node);
      typedNode.parentNode.removeChild(node);
      onError(error);
    };
    var onValidateOk = function() {
      // We can reach the authentication server and validate the token. Either
      // there's something wrong with the talkgadget service, or there is a
      // cookie problem. Only the cookie problem can be fixed by the user, so
      // suggest that fix.
      onValidateError(remoting.Error.AUTHENTICATION_FAILED);
    }
    that.validateToken(token, onValidateOk, onValidateError);
  }
  node.addEventListener('load', onLoad, false);
  node.addEventListener('error', onLoadError, false);
};

/**
 * Constructs the remoting.wcs object.
 *
 * @param {string} token An OAuth2 access token.
 * @param {function(string): void} onReady The callback function, called with
 *     an OAuth2 access token when WCS has been loaded.
 * @return {void} Nothing.
 * @private
 */
remoting.WcsLoader.prototype.constructWcs_ = function(token, onReady) {
  remoting.wcs = new remoting.Wcs(
      remoting.wcsLoader.wcsIqClient, token, onReady);
};

/**
 * Validates an OAuth2 access token.
 *
 * @param {string} token The access token.
 * @param {function():void} onOk Callback to invoke if the token is valid.
 * @param {function(remoting.Error):void} onError Function to invoke with an
 *     error code on failure.
 * @return {void} Nothing.
 */
remoting.WcsLoader.prototype.validateToken = function(token, onOk, onError) {
  /** @type {XMLHttpRequest} */
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (xhr.readyState != 4) {
      return;
    }
    if (xhr.status == 200) {
      onOk();
    } else {
      var error = remoting.Error.AUTHENTICATION_FAILED;
      switch (xhr.status) {
        case 0:
          error = remoting.Error.NETWORK_FAILURE;
          break;
        case 502: // No break
        case 503:
          error = remoting.Error.SERVICE_UNAVAILABLE;
          break;
      }
      onError(error);
    }
  };
  var parameters = '?access_token=' + encodeURIComponent(token);
  xhr.open('GET',
           remoting.settings.OAUTH2_API_BASE_URL + '/v1/tokeninfo' + parameters,
           true);
  xhr.send(null);
};