michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // Note: this is never instantiated in chrome - the source is sent across michael@0: // to the worker and it is evaluated there and created in response to a michael@0: // port-create message we send. michael@0: function WorkerPort(portid) { michael@0: AbstractPort.call(this, portid); michael@0: } michael@0: michael@0: WorkerPort.prototype = { michael@0: __proto__: AbstractPort.prototype, michael@0: _portType: "worker", michael@0: michael@0: _dopost: function fw_WorkerPort_dopost(data) { michael@0: // postMessage is injected into the sandbox. michael@0: _postMessage(data, "*"); michael@0: }, michael@0: michael@0: _onerror: function fw_WorkerPort_onerror(err) { michael@0: // We throw an object that "derives" from the exception, but with michael@0: // a more detailed message. michael@0: throw {message: "Port " + this + " handler failed: " + err.message, __proto__: err}; michael@0: } michael@0: } michael@0: michael@0: function importScripts() { michael@0: for (var i=0; i < arguments.length; i++) { michael@0: // load the url *synchronously* michael@0: var scriptURL = arguments[i]; michael@0: var xhr = new XMLHttpRequest(); michael@0: xhr.open('GET', scriptURL, false); michael@0: xhr.onreadystatechange = function(aEvt) { michael@0: if (xhr.readyState == 4) { michael@0: if (xhr.status == 200 || xhr.status == 0) { michael@0: _evalInSandbox(xhr.responseText, scriptURL); michael@0: } michael@0: else { michael@0: throw new Error("Unable to importScripts ["+scriptURL+"], status " + xhr.status) michael@0: } michael@0: } michael@0: }; michael@0: xhr.send(null); michael@0: } michael@0: } michael@0: michael@0: // This function is magically injected into the sandbox and used there. michael@0: // Thus, it is only ever dealing with "worker" ports. michael@0: function __initWorkerMessageHandler() { michael@0: michael@0: let ports = {}; // all "worker" ports currently alive, keyed by ID. michael@0: michael@0: function messageHandler(event) { michael@0: // We will ignore all messages destined for otherType. michael@0: let data = event.data; michael@0: let portid = data.portId; michael@0: let port; michael@0: if (!data.portFromType || data.portFromType === "worker") { michael@0: // this is a message posted by ourself so ignore it. michael@0: return; michael@0: } michael@0: switch (data.portTopic) { michael@0: case "port-create": michael@0: // a new port was created on the "client" side - create a new worker michael@0: // port and store it in the map michael@0: port = new WorkerPort(portid); michael@0: ports[portid] = port; michael@0: // and call the "onconnect" handler. michael@0: try { michael@0: onconnect({ports: [port]}); michael@0: } catch(e) { michael@0: // we have a bad worker and cannot continue, we need to signal michael@0: // an error michael@0: port._postControlMessage("port-connection-error", JSON.stringify(e.toString())); michael@0: throw e; michael@0: } michael@0: break; michael@0: michael@0: case "port-close": michael@0: // the client side of the port was closed, so close this side too. michael@0: port = ports[portid]; michael@0: if (!port) { michael@0: // port already closed (which will happen when we call port.close() michael@0: // below - the client side will send us this message but we've michael@0: // already closed it.) michael@0: return; michael@0: } michael@0: delete ports[portid]; michael@0: port.close(); michael@0: break; michael@0: michael@0: case "port-message": michael@0: // the client posted a message to this worker port. michael@0: port = ports[portid]; michael@0: if (!port) { michael@0: // port must be closed - this shouldn't happen! michael@0: return; michael@0: } michael@0: port._onmessage(data.data); michael@0: break; michael@0: michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: // addEventListener is injected into the sandbox. michael@0: _addEventListener('message', messageHandler); michael@0: } michael@0: __initWorkerMessageHandler();