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