/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; const { Cc, Ci, Cr } = require("chrome"); const { Input, start, stop, receive, outputs } = require("../event/utils"); const { id: addonID } = require("../self"); const { setImmediate } = require("../timers"); const { notifyObservers } = Cc['@mozilla.org/observer-service;1']. getService(Ci.nsIObserverService); const NOT_AN_INPUT = "OutputPort can be used only for sending messages"; // `OutputPort` creates a port to which messages can be send. Those // messages are actually disptached as `subject`'s of the observer // notifications. This is handy for communicating between different // components of the SDK. By default messages are dispatched // asynchronously, although `options.sync` can be used to make them // synchronous. If `options.id` is given `topic` for observer // notifications is generated by namespacing it, to avoid spamming // other SDK add-ons. It's also possible to provide `options.topic` // to use excat `topic` without namespacing it. // // Note: Symmetric `new InputPort({ id: "x" })` instances can be used to // receive messages send to the instances of `new OutputPort({ id: "x" })`. const OutputPort = function({id, topic, sync}) { this.id = id || topic; this.sync = !!sync; this.topic = topic || "sdk:" + addonID + ":" + id; }; // OutputPort extends base signal type to implement same message // receiving interface. OutputPort.prototype = new Input(); OutputPort.constructor = OutputPort; // OutputPort can not be consumed there for starting or stopping it // is not supported. OutputPort.prototype[start] = _ => { throw TypeError(NOT_AN_INPUT); }; OutputPort.prototype[stop] = _ => { throw TypeError(NOT_AN_INPUT); }; // Port reecives message send to it, which will be dispatched via // observer notification service. OutputPort.receive = ({topic, sync}, message) => { const type = typeof(message); const supported = message === null || type === "object" || type === "function"; // There is no sensible way to wrap JS primitives that would make sense // for general observer notification users. It's also probably not very // useful to dispatch JS primitives as subject of observer service, there // for we do not support those use cases. if (!supported) throw new TypeError("Unsupproted message type: `" + type + "`"); // Normalize `message` to create a valid observer notification `subject`. // If `message` is `null`, implements `nsISupports` interface or already // represents wrapped JS object use it as is. Otherwise create a wrapped // object so that observers could receive it. const subject = message === null ? null : message instanceof Ci.nsISupports ? message : message.wrappedJSObject ? message : {wrappedJSObject: message}; if (sync) notifyObservers(subject, topic, null); else setImmediate(notifyObservers, subject, topic, null); }; OutputPort.prototype[receive] = OutputPort.receive; exports.OutputPort = OutputPort;