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: // Code that is shared between clients and workers. michael@0: this.EXPORTED_SYMBOLS = ["AbstractPort"]; michael@0: michael@0: this.AbstractPort = function AbstractPort(portid) { michael@0: this._portid = portid; michael@0: this._handler = undefined; michael@0: this._closed = false; michael@0: // pending messages sent to this port before it has a message handler. michael@0: this._pendingMessagesIncoming = []; michael@0: }; michael@0: michael@0: AbstractPort.prototype = { michael@0: _portType: null, // set by a subclass. michael@0: // abstract methods to be overridden. michael@0: _dopost: function fw_AbstractPort_dopost(data) { michael@0: throw new Error("not implemented"); michael@0: }, michael@0: _onerror: function fw_AbstractPort_onerror(err) { michael@0: throw new Error("not implemented"); michael@0: }, michael@0: michael@0: // and concrete methods shared by client and workers. michael@0: toString: function fw_AbstractPort_toString() { michael@0: return "MessagePort(portType='" + this._portType + "', portId=" michael@0: + this._portid + (this._closed ? ", closed=true" : "") + ")"; michael@0: }, michael@0: _JSONParse: function fw_AbstractPort_JSONParse(data) JSON.parse(data), michael@0: michael@0: _postControlMessage: function fw_AbstractPort_postControlMessage(topic, data) { michael@0: let postData = { michael@0: portTopic: topic, michael@0: portId: this._portid, michael@0: portFromType: this._portType, michael@0: data: data michael@0: }; michael@0: this._dopost(postData); michael@0: }, michael@0: michael@0: _onmessage: function fw_AbstractPort_onmessage(data) { michael@0: // See comments in postMessage below - we work around a cloning michael@0: // issue by using JSON for these messages. michael@0: // Further, we allow the workers to override exactly how the JSON parsing michael@0: // is done - we try and do such parsing in the client window so things michael@0: // like prototype overrides on Array work as expected. michael@0: if (!this._handler) { michael@0: this._pendingMessagesIncoming.push(data); michael@0: } else { michael@0: data = this._JSONParse(data); michael@0: try { michael@0: this._handler({ michael@0: data: data, michael@0: __exposedProps__: { michael@0: data: 'r' michael@0: } michael@0: }); michael@0: } catch (ex) { michael@0: this._onerror(ex); michael@0: } michael@0: } michael@0: }, michael@0: michael@0: set onmessage(handler) { // property setter for onmessage michael@0: this._handler = handler; michael@0: while (this._pendingMessagesIncoming.length) { michael@0: this._onmessage(this._pendingMessagesIncoming.shift()); michael@0: } michael@0: }, michael@0: get onmessage() { michael@0: return this._handler; michael@0: }, michael@0: michael@0: /** michael@0: * postMessage michael@0: * michael@0: * Send data to the onmessage handler on the other end of the port. The michael@0: * data object should have a topic property. michael@0: * michael@0: * @param {jsobj} data michael@0: */ michael@0: postMessage: function fw_AbstractPort_postMessage(data) { michael@0: if (this._closed) { michael@0: throw new Error("port is closed"); michael@0: } michael@0: // There seems to be an issue with passing objects directly and letting michael@0: // the structured clone thing work - we sometimes get: michael@0: // [Exception... "The object could not be cloned." code: "25" nsresult: "0x80530019 (DataCloneError)"] michael@0: // The best guess is that this happens when funky things have been added to the prototypes. michael@0: // It doesn't happen for our "control" messages, only in messages from michael@0: // content - so we explicitly use JSON on these messages as that avoids michael@0: // the problem. michael@0: this._postControlMessage("port-message", JSON.stringify(data)); michael@0: }, michael@0: michael@0: close: function fw_AbstractPort_close() { michael@0: if (this._closed) { michael@0: return; // already closed. michael@0: } michael@0: this._postControlMessage("port-close"); michael@0: // and clean myself up. michael@0: this._handler = null; michael@0: this._pendingMessagesIncoming = []; michael@0: this._closed = true; michael@0: } michael@0: };