16e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 26e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 36e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// found in the LICENSE file. 46e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 56e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/** 66e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @fileoverview 76e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * It2MeService listens to incoming connections requests from Hangouts 86e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * and the webapp and creates a It2MeHelperChannel between them. 96e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * It supports multiple helper sessions, but only a single helpee. 106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */ 116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)'use strict'; 136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/** @suppress {duplicate} */ 156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)var remoting = remoting || {}; 166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/** 186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {remoting.AppLauncher} appLauncher 196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @constructor 206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */ 216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)remoting.It2MeService = function(appLauncher) { 226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) /** 236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @type {remoting.AppLauncher} 246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @private 256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */ 266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.appLauncher_ = appLauncher; 276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) /** 296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @type {Array.<remoting.It2MeHelperChannel>} 306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @private 316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */ 326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.helpers_ = []; 336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) /** @private */ 356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.helpee_ = null; 366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.onWebappConnectRef_ = this.onWebappConnect_.bind(this); 386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.onConnectExternalRef_ = this.onConnectExternal_.bind(this); 396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}; 406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/** @enum {string} */ 426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)remoting.It2MeService.ConnectionTypes = { 436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) HELPER_HANGOUT: 'it2me.helper.hangout', 446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) HELPEE_HANGOUT: 'it2me.helpee.hangout', 456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) HELPER_WEBAPP: 'it2me.helper.webapp' 466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}; 476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/** 496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * Starts listening to external connection from Hangouts and the webapp. 506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */ 516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)remoting.It2MeService.prototype.init = function() { 526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) chrome.runtime.onConnect.addListener(this.onWebappConnectRef_); 536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) chrome.runtime.onConnectExternal.addListener(this.onConnectExternalRef_); 546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}; 556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)remoting.It2MeService.prototype.dispose = function() { 576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) chrome.runtime.onConnect.removeListener(this.onWebappConnectRef_); 586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) chrome.runtime.onConnectExternal.removeListener( 596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.onConnectExternalRef_); 606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}; 616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/** 636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * This function is called when Hangouts connects via chrome.runtime.connect. 646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * Only web pages that are white-listed in the manifest are allowed to connect. 656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * 666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {chrome.runtime.Port} port 676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @private 686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */ 696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)remoting.It2MeService.prototype.onConnectExternal_ = function(port) { 706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var ConnectionTypes = remoting.It2MeService.ConnectionTypes; 716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) try { 726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) switch (port.name) { 736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) case ConnectionTypes.HELPER_HANGOUT: 746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.handleExternalHelperConnection_(port); 756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return true; 7603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) case ConnectionTypes.HELPEE_HANGOUT: 7703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) this.handleExternalHelpeeConnection_(port); 7803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return true; 796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) default: 806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) throw new Error('Unsupported port - ' + port.name); 816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } catch (e) { 836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var error = /**@type {Error} */ e; 846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) console.error(error); 856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) port.disconnect(); 866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return false; 886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}; 896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/** 916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {chrome.runtime.Port} port 926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @private 936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */ 946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)remoting.It2MeService.prototype.onWebappConnect_ = function(port) { 956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) try { 966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) console.log('Incoming helper connection from webapp.'); 976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // The senderId (tabId or windowId) of the webapp is embedded in the port 996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // name with the format port_name@senderId. 1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var parts = port.name.split('@'); 1016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var portName = parts[0]; 1026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var senderId = parts[1]; 1036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var ConnectionTypes = remoting.It2MeService.ConnectionTypes; 1046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (portName === ConnectionTypes.HELPER_WEBAPP && senderId !== undefined) { 1056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) for (var i = 0; i < this.helpers_.length; i++) { 1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var helper = this.helpers_[i]; 1076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (helper.instanceId() === senderId) { 1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) helper.onWebappConnect(port, senderId); 1096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return; 1106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) throw new Error('No matching hangout connection found for ' + port.name); 1146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } catch (e) { 1156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var error = /** @type {Error} */ e; 1166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) console.error(error); 1176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) port.disconnect(); 1186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}; 1206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/** 1226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {remoting.It2MeHelperChannel} helper 1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */ 1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)remoting.It2MeService.prototype.onHelperChannelDisconnected = function(helper) { 1256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) for (var i = 0; i < this.helpers_.length; i++) { 1266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (helper === this.helpers_[i]) { 1276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.helpers_.splice(i, 1); 1286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}; 1316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 13203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)remoting.It2MeService.prototype.onHelpeeChannelDisconnected = function() { 13303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) base.debug.assert(this.helpee_ !== null); 13403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) this.helpee_ = null; 13503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}; 13603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/** 1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {chrome.runtime.Port} port 1396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @private 1406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */ 1416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)remoting.It2MeService.prototype.handleExternalHelperConnection_ = 1426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) function(port) { 1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (this.helpee_) { 1446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) console.error( 1456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 'Cannot start a helper session while a helpee session is in process.'); 1466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) port.disconnect(); 14703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return; 1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) console.log('Incoming helper connection from Hangouts'); 1516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var helper = new remoting.It2MeHelperChannel( 1526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.appLauncher_, port, this.onHelperChannelDisconnected.bind(this)); 1536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) helper.init(); 1546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.helpers_.push(helper); 1556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}; 15603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 15703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)/** 15803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * @param {chrome.runtime.Port} hangoutPort Represents a connection to Hangouts. 15903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * @private 16003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) */ 16103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)remoting.It2MeService.prototype.handleExternalHelpeeConnection_ = 16203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) function(hangoutPort) { 16303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (this.helpee_) { 16403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) console.error('An existing helpee session is in process.'); 16503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hangoutPort.disconnect(); 16603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return; 16703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 16803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 16903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) console.log('Incoming helpee connection from Hangouts'); 17003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) this.helpee_ = new remoting.It2MeHelpeeChannel( 17103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) hangoutPort, 17203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) new remoting.It2MeHostFacade(), 17303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) new remoting.HostInstaller(), 17403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) this.onHelpeeChannelDisconnected.bind(this)); 17503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) this.helpee_.init(); 17603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)};