extension_bridge.js revision cedac228d2dd51db4b79ea1e72c7f249408ee061
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @fileoverview Bridge to aid in communication between a Chrome 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * background page and content script. 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * It automatically figures out where it's being run and initializes itself 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * appropriately. Then just call send() to send a message from the background 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * to the page or vice versa, and addMessageListener() to provide a message 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * listener. Messages can be any object that can be serialized using JSON. 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)goog.provide('cvox.ExtensionBridge'); 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)goog.require('cvox.ChromeVoxJSON'); 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @constructor 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cvox.ExtensionBridge = function() {}; 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Initialize the extension bridge. Dynamically figure out whether we're in 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the background page, content script, or in a page, and call the 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * corresponding function for more specific initialization. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cvox.ExtensionBridge.init = function() { 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var self = cvox.ExtensionBridge; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.messageListeners = []; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.disconnectListeners = []; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (/^chrome-extension:\/\/.*background\.html$/.test(window.location.href)) { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This depends on the fact that the background page has a specific url. We 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // should never be loaded into another extension's background page, so this 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is a safe check. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.context = self.BACKGROUND; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.initBackground(); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (chrome && chrome.extension) { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.context = self.CONTENT_SCRIPT; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.initContentScript(); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Constant indicating we're in a background page. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @type {number} 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @const 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cvox.ExtensionBridge.BACKGROUND = 0; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Constant indicating we're in a content script. 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @type {number} 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @const 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cvox.ExtensionBridge.CONTENT_SCRIPT = 1; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The name of the port between the content script and background page. 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @type {string} 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @const 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cvox.ExtensionBridge.PORT_NAME = 'cvox.ExtensionBridge.Port'; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The name of the message between the content script and background to 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * see if they're connected. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @type {string} 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @const 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cvox.ExtensionBridge.PING_MSG = 'cvox.ExtensionBridge.Ping'; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The name of the message between the background and content script to 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * confirm that they're connected. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @type {string} 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @const 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cvox.ExtensionBridge.PONG_MSG = 'cvox.ExtensionBridge.Pong'; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Send a message. If the context is a page, sends a message to the 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * extension background page. If the context is a background page, sends 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * a message to the current active tab (not all tabs). 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object} message The message to be sent. 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cvox.ExtensionBridge.send = function(message) { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var self = cvox.ExtensionBridge; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (self.context) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case self.BACKGROUND: 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.sendBackgroundToContentScript(message); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case self.CONTENT_SCRIPT: 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.sendContentScriptToBackground(message); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Provide a function to listen to messages. In page context, this 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * listens to messages from the background. In background context, 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * this listens to messages from all pages. 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The function gets called with two parameters: the message, and a 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * port that can be used to send replies. 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function(Object, Port)} listener The message listener. 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cvox.ExtensionBridge.addMessageListener = function(listener) { 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cvox.ExtensionBridge.messageListeners.push(listener); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Provide a function to be called when the connection is 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * disconnected. 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function()} listener The listener. 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cvox.ExtensionBridge.addDisconnectListener = function(listener) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cvox.ExtensionBridge.disconnectListeners.push(listener); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Removes all message listeners from the extension bridge. 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cvox.ExtensionBridge.removeMessageListeners = function() { 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cvox.ExtensionBridge.messageListeners.length = 0; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Returns a unique id for this instance of the script. 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {number} 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cvox.ExtensionBridge.uniqueId = function() { 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return cvox.ExtensionBridge.id_; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Initialize the extension bridge in a background page context by registering 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * a listener for connections from the content script. 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cvox.ExtensionBridge.initBackground = function() { 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var self = cvox.ExtensionBridge; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** @type {!Array.<Port>} @private */ 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.portCache_ = []; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** @type {number} */ 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.nextPongId_ = 1; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** @type {number} */ 1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.id_ = 0; 1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var onConnectHandler = function(port) { 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (port.name != self.PORT_NAME) { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.portCache_.push(port); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port.onMessage.addListener( 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function(message) { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (message[cvox.ExtensionBridge.PING_MSG]) { 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var pongMessage = {}; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pongMessage[cvox.ExtensionBridge.PONG_MSG] = self.nextPongId_++; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port.postMessage(pongMessage); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var i = 0; i < self.messageListeners.length; i++) { 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.messageListeners[i](message, port); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port.onDisconnect.addListener(function(message) { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var i = 0; i < self.portCache_.length; i++) { 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (self.portCache_[i] == port) { 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.portCache_.splice(i, 1); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome.extension.onConnect.addListener(onConnectHandler); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Initialize the extension bridge in a content script context, listening 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * for messages from the background page. 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cvox.ExtensionBridge.initContentScript = function() { 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var self = cvox.ExtensionBridge; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.connected = false; 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.pingAttempts = 0; 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.queuedMessages = []; 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** @type {number} */ 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.id_ = -1; 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var onMessageHandler = function(request, sender, sendResponse) { 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (request && request['srcFile']) { 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO (clchen, deboer): Investigate this further and come up with a 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // cleaner solution. The root issue is that this should never be run on 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the background page, but it is in the Chrome OS case. 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (request[cvox.ExtensionBridge.PONG_MSG]) { 2135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.gotPongFromBackgroundPage(request[cvox.ExtensionBridge.PONG_MSG]); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var i = 0; i < self.messageListeners.length; i++) { 2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.messageListeners[i](request, cvox.ExtensionBridge.backgroundPort); 2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) sendResponse({}); 2205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) }; 2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Listen to requests from the background that don't come from 2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // our connection port. 2245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) chrome.extension.onMessage.addListener(onMessageHandler); 2255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.setupBackgroundPort(); 2275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.tryToPingBackgroundPage(); 2295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}; 2305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/** 2325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Set up the connection to the background page. 2335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) */ 2345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cvox.ExtensionBridge.setupBackgroundPort = function() { 2355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Set up the connection to the background page. 2365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) var self = cvox.ExtensionBridge; 2375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.backgroundPort = chrome.extension.connect({name: self.PORT_NAME}); 2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.backgroundPort.onMessage.addListener( 2395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) function(message) { 2405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (message[cvox.ExtensionBridge.PONG_MSG]) { 2415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.gotPongFromBackgroundPage( 2425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) message[cvox.ExtensionBridge.PONG_MSG]); 2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } else { 2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (var i = 0; i < self.messageListeners.length; i++) { 2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.messageListeners[i](message, self.backgroundPort); 2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) }); 2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.backgroundPort.onDisconnect.addListener( 2505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) function(event) { 2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // If we're not connected yet, don't give up - try again. 2525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!self.connected) { 2535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.backgroundPort = null; 2545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 2555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (var i = 0; i < self.disconnectListeners.length; i++) { 2585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.disconnectListeners[i](); 2595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) }); 2615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}; 2625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/** 2645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Try to ping the background page. 2655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) */ 2665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cvox.ExtensionBridge.tryToPingBackgroundPage = function() { 2675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) var self = cvox.ExtensionBridge; 2685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // If we already got a pong, great - we're done. 2705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (self.connected) { 2715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 2725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.pingAttempts++; 2755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (self.pingAttempts > 5) { 2765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Could not connect after 5 ping attempts. Call the disconnect 2775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // handlers, which will disable ChromeVox. 2785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (var i = 0; i < self.disconnectListeners.length; i++) { 2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.disconnectListeners[i](); 2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 2825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Send the ping. 2855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) var msg = {}; 2865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) msg[cvox.ExtensionBridge.PING_MSG] = 1; 2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!self.backgroundPort) { 2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.setupBackgroundPort(); 2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.backgroundPort.postMessage(msg); 2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Check again in 500 ms in case we get no response. 2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) window.setTimeout(cvox.ExtensionBridge.tryToPingBackgroundPage, 500); 2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}; 2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/** 2975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Got pong from the background page, now we know the connection was 2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * successful. 2995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @param {number} pongId unique id assigned to us by the background page 3005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) */ 3015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cvox.ExtensionBridge.gotPongFromBackgroundPage = function(pongId) { 3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) var self = cvox.ExtensionBridge; 3035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.connected = true; 3045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.id_ = pongId; 3055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) while (self.queuedMessages.length > 0) { 3075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.sendContentScriptToBackground(self.queuedMessages.shift()); 3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}; 3105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/** 3125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Send a message from the content script to the background page. 3135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * 3145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @param {Object} message The message to send. 3155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) */ 3165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cvox.ExtensionBridge.sendContentScriptToBackground = function(message) { 3175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) var self = cvox.ExtensionBridge; 3185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!self.connected) { 3195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // We're not connected to the background page, so queue this message 3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // until we're connected. 3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.queuedMessages.push(message); 3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (cvox.ExtensionBridge.backgroundPort) { 3265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cvox.ExtensionBridge.backgroundPort.postMessage(message); 3275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } else { 3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) chrome.extension.sendMessage(message); 3295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}; 3315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/** 3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Send a message from the background page to the content script of the 3345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * current selected tab. 3355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * 3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @param {Object} message The message to send. 3375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) */ 3385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cvox.ExtensionBridge.sendBackgroundToContentScript = function(message) { 3395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) chrome.tabs.query( 3405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) {'active': true, 'lastFocusedWindow': true}, 3415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) function(tabs) { 3425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (tabs && tabs.length > 0) { 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome.tabs.sendMessage(tabs[0].id, message); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cvox.ExtensionBridge.portCache_.forEach(function(port) { 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port.postMessage(message); 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }); 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }); 3505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}; 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cvox.ExtensionBridge.init(); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)