Home | History | Annotate | Download | only in webapp
      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
      3  * found in the LICENSE file.
      4  */
      5 
      6 /**
      7  * @fileoverview
      8  * A class that loads a WCS IQ client and constructs remoting.wcs as a
      9  * wrapper for it.
     10  */
     11 
     12 'use strict';
     13 
     14 /** @suppress {duplicate} */
     15 var remoting = remoting || {};
     16 
     17 /** @type {remoting.WcsLoader} */
     18 remoting.wcsLoader = null;
     19 
     20 /**
     21  * @constructor
     22  */
     23 remoting.WcsLoader = function() {
     24   /**
     25    * The WCS client that will be downloaded. This variable is initialized (via
     26    * remoting.wcsLoader) by the downloaded Javascript.
     27    * @type {remoting.WcsIqClient}
     28    */
     29   this.wcsIqClient = null;
     30 };
     31 
     32 /**
     33  * The id of the script node.
     34  * @type {string}
     35  * @private
     36  */
     37 remoting.WcsLoader.prototype.SCRIPT_NODE_ID_ = 'wcs-script-node';
     38 
     39 /**
     40  * Starts loading the WCS IQ client.
     41  *
     42  * When it's loaded, construct remoting.wcs as a wrapper for it.
     43  * When the WCS connection is ready, or on error, call |onReady| or |onError|,
     44  * respectively.
     45  *
     46  * @param {string} token An OAuth2 access token.
     47  * @param {function(string): void} onReady The callback function, called with
     48  *     a client JID when WCS has been loaded.
     49  * @param {function(remoting.Error):void} onError Function to invoke with an
     50  *     error code on failure.
     51  * @return {void} Nothing.
     52  */
     53 remoting.WcsLoader.prototype.start = function(token, onReady, onError) {
     54   var node = document.getElementById(this.SCRIPT_NODE_ID_);
     55   if (node) {
     56     console.error('Multiple calls to WcsLoader.start are not allowed.');
     57     onError(remoting.Error.UNEXPECTED);
     58     return;
     59   }
     60 
     61   // Create a script node to load the WCS driver.
     62   node = document.createElement('script');
     63   node.id = this.SCRIPT_NODE_ID_;
     64   node.src = remoting.settings.TALK_GADGET_URL + 'iq?access_token=' + token;
     65   node.type = 'text/javascript';
     66   document.body.insertBefore(node, document.body.firstChild);
     67 
     68   /** @type {remoting.WcsLoader} */
     69   var that = this;
     70   var onLoad = function() {
     71     that.constructWcs_(token, onReady);
     72   };
     73   var onLoadError = function(event) {
     74     // The DOM Event object has no detail on the nature of the error, so try to
     75     // validate the token to get a better idea.
     76     /** @param {remoting.Error} error Error code. */
     77     var onValidateError = function(error) {
     78       var typedNode = /** @type {Element} */ (node);
     79       typedNode.parentNode.removeChild(node);
     80       onError(error);
     81     };
     82     var onValidateOk = function() {
     83       // We can reach the authentication server and validate the token. Either
     84       // there's something wrong with the talkgadget service, or there is a
     85       // cookie problem. Only the cookie problem can be fixed by the user, so
     86       // suggest that fix.
     87       onValidateError(remoting.Error.AUTHENTICATION_FAILED);
     88     }
     89     that.validateToken(token, onValidateOk, onValidateError);
     90   }
     91   node.addEventListener('load', onLoad, false);
     92   node.addEventListener('error', onLoadError, false);
     93 };
     94 
     95 /**
     96  * Constructs the remoting.wcs object.
     97  *
     98  * @param {string} token An OAuth2 access token.
     99  * @param {function(string): void} onReady The callback function, called with
    100  *     an OAuth2 access token when WCS has been loaded.
    101  * @return {void} Nothing.
    102  * @private
    103  */
    104 remoting.WcsLoader.prototype.constructWcs_ = function(token, onReady) {
    105   remoting.wcs = new remoting.Wcs(
    106       remoting.wcsLoader.wcsIqClient, token, onReady);
    107 };
    108 
    109 /**
    110  * Validates an OAuth2 access token.
    111  *
    112  * @param {string} token The access token.
    113  * @param {function():void} onOk Callback to invoke if the token is valid.
    114  * @param {function(remoting.Error):void} onError Function to invoke with an
    115  *     error code on failure.
    116  * @return {void} Nothing.
    117  */
    118 remoting.WcsLoader.prototype.validateToken = function(token, onOk, onError) {
    119   /** @type {XMLHttpRequest} */
    120   var xhr = new XMLHttpRequest();
    121   xhr.onreadystatechange = function() {
    122     if (xhr.readyState != 4) {
    123       return;
    124     }
    125     if (xhr.status == 200) {
    126       onOk();
    127     } else {
    128       var error = remoting.Error.AUTHENTICATION_FAILED;
    129       switch (xhr.status) {
    130         case 0:
    131           error = remoting.Error.NETWORK_FAILURE;
    132           break;
    133         case 502: // No break
    134         case 503:
    135           error = remoting.Error.SERVICE_UNAVAILABLE;
    136           break;
    137       }
    138       onError(error);
    139     }
    140   };
    141   var parameters = '?access_token=' + encodeURIComponent(token);
    142   xhr.open('GET',
    143            remoting.settings.OAUTH2_API_BASE_URL + '/v1/tokeninfo' + parameters,
    144            true);
    145   xhr.send(null);
    146 };
    147