// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /** * Channel to the background script. */ function Channel() { } /** @const */ Channel.INTERNAL_REQUEST_MESSAGE = 'internal-request-message'; /** @const */ Channel.INTERNAL_REPLY_MESSAGE = 'internal-reply-message'; Channel.prototype = { // Message port to use to communicate with background script. port_: null, // Registered message callbacks. messageCallbacks_: {}, // Internal request id to track pending requests. nextInternalRequestId_: 0, // Pending internal request callbacks. internalRequestCallbacks_: {}, /** * Initialize the channel with given port for the background script. */ init: function(port) { this.port_ = port; this.port_.onMessage.addListener(this.onMessage_.bind(this)); }, /** * Connects to the background script with the given name. */ connect: function(name) { this.port_ = chrome.runtime.connect({name: name}); this.port_.onMessage.addListener(this.onMessage_.bind(this)); }, /** * Associates a message name with a callback. When a message with the name * is received, the callback will be invoked with the message as its arg. * Note only the last registered callback will be invoked. */ registerMessage: function(name, callback) { this.messageCallbacks_[name] = callback; }, /** * Sends a message to the other side of the channel. */ send: function(msg) { this.port_.postMessage(msg); }, /** * Sends a message to the other side and invokes the callback with * the replied object. Useful for message that expects a returned result. */ sendWithCallback: function(msg, callback) { var requestId = this.nextInternalRequestId_++; this.internalRequestCallbacks_[requestId] = callback; this.send({ name: Channel.INTERNAL_REQUEST_MESSAGE, requestId: requestId, payload: msg }); }, /** * Invokes message callback using given message. * @return {*} The return value of the message callback or null. */ invokeMessageCallbacks_: function(msg) { var name = msg.name; if (this.messageCallbacks_[name]) return this.messageCallbacks_[name](msg); console.error('Error: Unexpected message, name=' + name); return null; }, /** * Invoked when a message is received. */ onMessage_: function(msg) { var name = msg.name; if (name == Channel.INTERNAL_REQUEST_MESSAGE) { var payload = msg.payload; var result = this.invokeMessageCallbacks_(payload); this.send({ name: Channel.INTERNAL_REPLY_MESSAGE, requestId: msg.requestId, result: result }); } else if (name == Channel.INTERNAL_REPLY_MESSAGE) { var callback = this.internalRequestCallbacks_[msg.requestId]; delete this.internalRequestCallbacks_[msg.requestId]; if (callback) callback(msg.result); } else { this.invokeMessageCallbacks_(msg); } } };