1 // Copyright 2013 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 * Channel to the background script. 7 */ 8 function Channel() { 9 } 10 11 /** @const */ 12 Channel.INTERNAL_REQUEST_MESSAGE = 'internal-request-message'; 13 14 /** @const */ 15 Channel.INTERNAL_REPLY_MESSAGE = 'internal-reply-message'; 16 17 Channel.prototype = { 18 // Message port to use to communicate with background script. 19 port_: null, 20 21 // Registered message callbacks. 22 messageCallbacks_: {}, 23 24 // Internal request id to track pending requests. 25 nextInternalRequestId_: 0, 26 27 // Pending internal request callbacks. 28 internalRequestCallbacks_: {}, 29 30 /** 31 * Initialize the channel with given port for the background script. 32 */ 33 init: function(port) { 34 this.port_ = port; 35 this.port_.onMessage.addListener(this.onMessage_.bind(this)); 36 }, 37 38 /** 39 * Connects to the background script with the given name. 40 */ 41 connect: function(name) { 42 this.port_ = chrome.runtime.connect({name: name}); 43 this.port_.onMessage.addListener(this.onMessage_.bind(this)); 44 }, 45 46 /** 47 * Associates a message name with a callback. When a message with the name 48 * is received, the callback will be invoked with the message as its arg. 49 * Note only the last registered callback will be invoked. 50 */ 51 registerMessage: function(name, callback) { 52 this.messageCallbacks_[name] = callback; 53 }, 54 55 /** 56 * Sends a message to the other side of the channel. 57 */ 58 send: function(msg) { 59 this.port_.postMessage(msg); 60 }, 61 62 /** 63 * Sends a message to the other side and invokes the callback with 64 * the replied object. Useful for message that expects a returned result. 65 */ 66 sendWithCallback: function(msg, callback) { 67 var requestId = this.nextInternalRequestId_++; 68 this.internalRequestCallbacks_[requestId] = callback; 69 this.send({ 70 name: Channel.INTERNAL_REQUEST_MESSAGE, 71 requestId: requestId, 72 payload: msg 73 }); 74 }, 75 76 /** 77 * Invokes message callback using given message. 78 * @return {*} The return value of the message callback or null. 79 */ 80 invokeMessageCallbacks_: function(msg) { 81 var name = msg.name; 82 if (this.messageCallbacks_[name]) 83 return this.messageCallbacks_[name](msg); 84 85 console.error('Error: Unexpected message, name=' + name); 86 return null; 87 }, 88 89 /** 90 * Invoked when a message is received. 91 */ 92 onMessage_: function(msg) { 93 var name = msg.name; 94 if (name == Channel.INTERNAL_REQUEST_MESSAGE) { 95 var payload = msg.payload; 96 var result = this.invokeMessageCallbacks_(payload); 97 this.send({ 98 name: Channel.INTERNAL_REPLY_MESSAGE, 99 requestId: msg.requestId, 100 result: result 101 }); 102 } else if (name == Channel.INTERNAL_REPLY_MESSAGE) { 103 var callback = this.internalRequestCallbacks_[msg.requestId]; 104 delete this.internalRequestCallbacks_[msg.requestId]; 105 if (callback) 106 callback(msg.result); 107 } else { 108 this.invokeMessageCallbacks_(msg); 109 } 110 } 111 }; 112