|
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 |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 // Code that is shared between clients and workers. |
|
6 this.EXPORTED_SYMBOLS = ["AbstractPort"]; |
|
7 |
|
8 this.AbstractPort = function AbstractPort(portid) { |
|
9 this._portid = portid; |
|
10 this._handler = undefined; |
|
11 this._closed = false; |
|
12 // pending messages sent to this port before it has a message handler. |
|
13 this._pendingMessagesIncoming = []; |
|
14 }; |
|
15 |
|
16 AbstractPort.prototype = { |
|
17 _portType: null, // set by a subclass. |
|
18 // abstract methods to be overridden. |
|
19 _dopost: function fw_AbstractPort_dopost(data) { |
|
20 throw new Error("not implemented"); |
|
21 }, |
|
22 _onerror: function fw_AbstractPort_onerror(err) { |
|
23 throw new Error("not implemented"); |
|
24 }, |
|
25 |
|
26 // and concrete methods shared by client and workers. |
|
27 toString: function fw_AbstractPort_toString() { |
|
28 return "MessagePort(portType='" + this._portType + "', portId=" |
|
29 + this._portid + (this._closed ? ", closed=true" : "") + ")"; |
|
30 }, |
|
31 _JSONParse: function fw_AbstractPort_JSONParse(data) JSON.parse(data), |
|
32 |
|
33 _postControlMessage: function fw_AbstractPort_postControlMessage(topic, data) { |
|
34 let postData = { |
|
35 portTopic: topic, |
|
36 portId: this._portid, |
|
37 portFromType: this._portType, |
|
38 data: data |
|
39 }; |
|
40 this._dopost(postData); |
|
41 }, |
|
42 |
|
43 _onmessage: function fw_AbstractPort_onmessage(data) { |
|
44 // See comments in postMessage below - we work around a cloning |
|
45 // issue by using JSON for these messages. |
|
46 // Further, we allow the workers to override exactly how the JSON parsing |
|
47 // is done - we try and do such parsing in the client window so things |
|
48 // like prototype overrides on Array work as expected. |
|
49 if (!this._handler) { |
|
50 this._pendingMessagesIncoming.push(data); |
|
51 } else { |
|
52 data = this._JSONParse(data); |
|
53 try { |
|
54 this._handler({ |
|
55 data: data, |
|
56 __exposedProps__: { |
|
57 data: 'r' |
|
58 } |
|
59 }); |
|
60 } catch (ex) { |
|
61 this._onerror(ex); |
|
62 } |
|
63 } |
|
64 }, |
|
65 |
|
66 set onmessage(handler) { // property setter for onmessage |
|
67 this._handler = handler; |
|
68 while (this._pendingMessagesIncoming.length) { |
|
69 this._onmessage(this._pendingMessagesIncoming.shift()); |
|
70 } |
|
71 }, |
|
72 get onmessage() { |
|
73 return this._handler; |
|
74 }, |
|
75 |
|
76 /** |
|
77 * postMessage |
|
78 * |
|
79 * Send data to the onmessage handler on the other end of the port. The |
|
80 * data object should have a topic property. |
|
81 * |
|
82 * @param {jsobj} data |
|
83 */ |
|
84 postMessage: function fw_AbstractPort_postMessage(data) { |
|
85 if (this._closed) { |
|
86 throw new Error("port is closed"); |
|
87 } |
|
88 // There seems to be an issue with passing objects directly and letting |
|
89 // the structured clone thing work - we sometimes get: |
|
90 // [Exception... "The object could not be cloned." code: "25" nsresult: "0x80530019 (DataCloneError)"] |
|
91 // The best guess is that this happens when funky things have been added to the prototypes. |
|
92 // It doesn't happen for our "control" messages, only in messages from |
|
93 // content - so we explicitly use JSON on these messages as that avoids |
|
94 // the problem. |
|
95 this._postControlMessage("port-message", JSON.stringify(data)); |
|
96 }, |
|
97 |
|
98 close: function fw_AbstractPort_close() { |
|
99 if (this._closed) { |
|
100 return; // already closed. |
|
101 } |
|
102 this._postControlMessage("port-close"); |
|
103 // and clean myself up. |
|
104 this._handler = null; |
|
105 this._pendingMessagesIncoming = []; |
|
106 this._closed = true; |
|
107 } |
|
108 }; |