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