1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 // TODO Bug 907060 Per off-line discussion, after the MessagePort is done
6 // at Bug 643325, we will start to refactorize the common logic of both
7 // Inter-App Communication and Shared Worker. For now, we hope to design an
8 // MozInterAppMessagePort to meet the timeline, which still follows exactly
9 // the same interface and semantic as the MessagePort is. In the future,
10 // we can then align it back to MessagePort with backward compatibility.
14 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
16 Cu.import("resource://gre/modules/Services.jsm");
17 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
18 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
21 function debug(aMsg) {
22 dump("-- InterAppMessagePort: " + Date.now() + ": " + aMsg + "\n");
25 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
26 "@mozilla.org/childprocessmessagemanager;1",
29 XPCOMUtils.defineLazyServiceGetter(this, "appsService",
30 "@mozilla.org/AppsService;1",
33 const kMessages = ["InterAppMessagePort:OnMessage",
34 "InterAppMessagePort:Shutdown"];
36 function InterAppMessagePort() {
37 if (DEBUG) debug("InterAppMessagePort()");
40 InterAppMessagePort.prototype = {
41 __proto__: DOMRequestIpcHelper.prototype,
43 classDescription: "MozInterAppMessagePort",
45 classID: Components.ID("{c66e0f8c-e3cb-11e2-9e85-43ef6244b884}"),
47 contractID: "@mozilla.org/dom/inter-app-message-port;1",
49 QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
50 Ci.nsISupportsWeakReference,
53 // Ci.nsIDOMGlobalPropertyInitializer implementation.
54 init: function(aWindow) {
55 if (DEBUG) debug("Calling init().");
57 this.initDOMRequestHelper(aWindow, kMessages);
59 let principal = aWindow.document.nodePrincipal;
60 this._manifestURL = appsService.getManifestURLByLocalId(principal.appId);
61 this._pageURL = principal.URI.specIgnoringRef;
63 // Remove query string.
64 this._pageURL = this._pageURL.split("?")[0];
66 this._started = false;
68 this._messageQueue = [];
71 // WebIDL implementation for constructor.
72 __init: function(aMessagePortID) {
74 debug("Calling __init(): aMessagePortID: " + aMessagePortID);
77 this._messagePortID = aMessagePortID;
79 cpmm.sendAsyncMessage("InterAppMessagePort:Register",
80 { messagePortID: this._messagePortID,
81 manifestURL: this._manifestURL,
82 pageURL: this._pageURL });
85 // DOMRequestIpcHelper implementation.
87 if (DEBUG) debug("Calling uninit().");
89 // When the message port is uninitialized, we need to disentangle the
90 // coupling ports, as if the close() method had been called.
92 if (DEBUG) debug("close() has been called. Don't need to close again.");
99 postMessage: function(aMessage) {
100 if (DEBUG) debug("Calling postMessage().");
103 if (DEBUG) debug("close() has been called. Cannot post message.");
107 cpmm.sendAsyncMessage("InterAppMessagePort:PostMessage",
108 { messagePortID: this._messagePortID,
109 manifestURL: this._manifestURL,
110 message: aMessage });
114 // Begin dispatching messages received on the port.
115 if (DEBUG) debug("Calling start().");
118 if (DEBUG) debug("close() has been called. Cannot call start().");
123 if (DEBUG) debug("start() has been called. Don't need to start again.");
127 // When a port's port message queue is enabled, the event loop must use it
128 // as one of its task sources.
129 this._started = true;
130 while (this._messageQueue.length) {
131 let message = this._messageQueue.shift();
132 this._dispatchMessage(message);
137 // Disconnecting the port, so that it is no longer active.
138 if (DEBUG) debug("Calling close().");
141 if (DEBUG) debug("close() has been called. Don't need to close again.");
146 this._messageQueue.length = 0;
148 // When this method called on a local port that is entangled with another
149 // port, must cause the user agent to disentangle the coupling ports.
150 cpmm.sendAsyncMessage("InterAppMessagePort:Unregister",
151 { messagePortID: this._messagePortID,
152 manifestURL: this._manifestURL });
154 this.removeMessageListeners(kMessages);
158 if (DEBUG) debug("Getting onmessage handler.");
160 return this.__DOM_IMPL__.getEventHandler("onmessage");
163 set onmessage(aHandler) {
164 if (DEBUG) debug("Setting onmessage handler.");
166 this.__DOM_IMPL__.setEventHandler("onmessage", aHandler);
168 // The first time a MessagePort object's onmessage IDL attribute is set,
169 // the port's message queue must be enabled, as if the start() method had
172 if (DEBUG) debug("start() has been called. Don't need to start again.");
179 _dispatchMessage: function _dispatchMessage(aMessage) {
180 let wrappedMessage = Cu.cloneInto(aMessage, this._window);
182 debug("_dispatchMessage: wrappedMessage: " +
183 JSON.stringify(wrappedMessage));
186 let event = new this._window
187 .MozInterAppMessageEvent("message",
188 { data: wrappedMessage });
189 this.__DOM_IMPL__.dispatchEvent(event);
192 receiveMessage: function(aMessage) {
193 if (DEBUG) debug("receiveMessage: name: " + aMessage.name);
195 let message = aMessage.json;
196 if (message.manifestURL != this._manifestURL ||
197 message.pageURL != this._pageURL ||
198 message.messagePortID != this._messagePortID) {
199 if (DEBUG) debug("The message doesn't belong to this page. Returning. " +
204 switch (aMessage.name) {
205 case "InterAppMessagePort:OnMessage":
207 if (DEBUG) debug("close() has been called. Drop the message.");
211 if (!this._started) {
212 if (DEBUG) debug("Not yet called start(). Queue up the message.");
213 this._messageQueue.push(message.message);
217 this._dispatchMessage(message.message);
220 case "InterAppMessagePort:Shutdown":
224 if (DEBUG) debug("Error! Shouldn't fall into this case.");
230 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([InterAppMessagePort]);