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} */
15var remoting = remoting || {};
16
17/** @type {remoting.WcsLoader} */
18remoting.wcsLoader = null;
19
20/**
21 * @constructor
22 */
23remoting.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 */
37remoting.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 */
53remoting.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 */
104remoting.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 */
118remoting.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