|
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 // Note: this is never instantiated in chrome - the source is sent across |
|
6 // to the worker and it is evaluated there and created in response to a |
|
7 // port-create message we send. |
|
8 function WorkerPort(portid) { |
|
9 AbstractPort.call(this, portid); |
|
10 } |
|
11 |
|
12 WorkerPort.prototype = { |
|
13 __proto__: AbstractPort.prototype, |
|
14 _portType: "worker", |
|
15 |
|
16 _dopost: function fw_WorkerPort_dopost(data) { |
|
17 // postMessage is injected into the sandbox. |
|
18 _postMessage(data, "*"); |
|
19 }, |
|
20 |
|
21 _onerror: function fw_WorkerPort_onerror(err) { |
|
22 // We throw an object that "derives" from the exception, but with |
|
23 // a more detailed message. |
|
24 throw {message: "Port " + this + " handler failed: " + err.message, __proto__: err}; |
|
25 } |
|
26 } |
|
27 |
|
28 function importScripts() { |
|
29 for (var i=0; i < arguments.length; i++) { |
|
30 // load the url *synchronously* |
|
31 var scriptURL = arguments[i]; |
|
32 var xhr = new XMLHttpRequest(); |
|
33 xhr.open('GET', scriptURL, false); |
|
34 xhr.onreadystatechange = function(aEvt) { |
|
35 if (xhr.readyState == 4) { |
|
36 if (xhr.status == 200 || xhr.status == 0) { |
|
37 _evalInSandbox(xhr.responseText, scriptURL); |
|
38 } |
|
39 else { |
|
40 throw new Error("Unable to importScripts ["+scriptURL+"], status " + xhr.status) |
|
41 } |
|
42 } |
|
43 }; |
|
44 xhr.send(null); |
|
45 } |
|
46 } |
|
47 |
|
48 // This function is magically injected into the sandbox and used there. |
|
49 // Thus, it is only ever dealing with "worker" ports. |
|
50 function __initWorkerMessageHandler() { |
|
51 |
|
52 let ports = {}; // all "worker" ports currently alive, keyed by ID. |
|
53 |
|
54 function messageHandler(event) { |
|
55 // We will ignore all messages destined for otherType. |
|
56 let data = event.data; |
|
57 let portid = data.portId; |
|
58 let port; |
|
59 if (!data.portFromType || data.portFromType === "worker") { |
|
60 // this is a message posted by ourself so ignore it. |
|
61 return; |
|
62 } |
|
63 switch (data.portTopic) { |
|
64 case "port-create": |
|
65 // a new port was created on the "client" side - create a new worker |
|
66 // port and store it in the map |
|
67 port = new WorkerPort(portid); |
|
68 ports[portid] = port; |
|
69 // and call the "onconnect" handler. |
|
70 try { |
|
71 onconnect({ports: [port]}); |
|
72 } catch(e) { |
|
73 // we have a bad worker and cannot continue, we need to signal |
|
74 // an error |
|
75 port._postControlMessage("port-connection-error", JSON.stringify(e.toString())); |
|
76 throw e; |
|
77 } |
|
78 break; |
|
79 |
|
80 case "port-close": |
|
81 // the client side of the port was closed, so close this side too. |
|
82 port = ports[portid]; |
|
83 if (!port) { |
|
84 // port already closed (which will happen when we call port.close() |
|
85 // below - the client side will send us this message but we've |
|
86 // already closed it.) |
|
87 return; |
|
88 } |
|
89 delete ports[portid]; |
|
90 port.close(); |
|
91 break; |
|
92 |
|
93 case "port-message": |
|
94 // the client posted a message to this worker port. |
|
95 port = ports[portid]; |
|
96 if (!port) { |
|
97 // port must be closed - this shouldn't happen! |
|
98 return; |
|
99 } |
|
100 port._onmessage(data.data); |
|
101 break; |
|
102 |
|
103 default: |
|
104 break; |
|
105 } |
|
106 } |
|
107 // addEventListener is injected into the sandbox. |
|
108 _addEventListener('message', messageHandler); |
|
109 } |
|
110 __initWorkerMessageHandler(); |