diff options
Diffstat (limited to 'toolkit/jetpack/sdk/output/system.js')
-rw-r--r-- | toolkit/jetpack/sdk/output/system.js | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/toolkit/jetpack/sdk/output/system.js b/toolkit/jetpack/sdk/output/system.js new file mode 100644 index 000000000..4fb16dcd5 --- /dev/null +++ b/toolkit/jetpack/sdk/output/system.js @@ -0,0 +1,71 @@ +/* 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; |