1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/lib/sdk/output/system.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,71 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +"use strict"; 1.8 + 1.9 +const { Cc, Ci, Cr } = require("chrome"); 1.10 +const { Input, start, stop, receive, outputs } = require("../event/utils"); 1.11 +const { id: addonID } = require("../self"); 1.12 +const { setImmediate } = require("../timers"); 1.13 +const { notifyObservers } = Cc['@mozilla.org/observer-service;1']. 1.14 + getService(Ci.nsIObserverService); 1.15 + 1.16 +const NOT_AN_INPUT = "OutputPort can be used only for sending messages"; 1.17 + 1.18 +// `OutputPort` creates a port to which messages can be send. Those 1.19 +// messages are actually disptached as `subject`'s of the observer 1.20 +// notifications. This is handy for communicating between different 1.21 +// components of the SDK. By default messages are dispatched 1.22 +// asynchronously, although `options.sync` can be used to make them 1.23 +// synchronous. If `options.id` is given `topic` for observer 1.24 +// notifications is generated by namespacing it, to avoid spamming 1.25 +// other SDK add-ons. It's also possible to provide `options.topic` 1.26 +// to use excat `topic` without namespacing it. 1.27 +// 1.28 +// Note: Symmetric `new InputPort({ id: "x" })` instances can be used to 1.29 +// receive messages send to the instances of `new OutputPort({ id: "x" })`. 1.30 +const OutputPort = function({id, topic, sync}) { 1.31 + this.id = id || topic; 1.32 + this.sync = !!sync; 1.33 + this.topic = topic || "sdk:" + addonID + ":" + id; 1.34 +}; 1.35 +// OutputPort extends base signal type to implement same message 1.36 +// receiving interface. 1.37 +OutputPort.prototype = new Input(); 1.38 +OutputPort.constructor = OutputPort; 1.39 + 1.40 +// OutputPort can not be consumed there for starting or stopping it 1.41 +// is not supported. 1.42 +OutputPort.prototype[start] = _ => { throw TypeError(NOT_AN_INPUT); }; 1.43 +OutputPort.prototype[stop] = _ => { throw TypeError(NOT_AN_INPUT); }; 1.44 + 1.45 +// Port reecives message send to it, which will be dispatched via 1.46 +// observer notification service. 1.47 +OutputPort.receive = ({topic, sync}, message) => { 1.48 + const type = typeof(message); 1.49 + const supported = message === null || 1.50 + type === "object" || 1.51 + type === "function"; 1.52 + 1.53 + // There is no sensible way to wrap JS primitives that would make sense 1.54 + // for general observer notification users. It's also probably not very 1.55 + // useful to dispatch JS primitives as subject of observer service, there 1.56 + // for we do not support those use cases. 1.57 + if (!supported) 1.58 + throw new TypeError("Unsupproted message type: `" + type + "`"); 1.59 + 1.60 + // Normalize `message` to create a valid observer notification `subject`. 1.61 + // If `message` is `null`, implements `nsISupports` interface or already 1.62 + // represents wrapped JS object use it as is. Otherwise create a wrapped 1.63 + // object so that observers could receive it. 1.64 + const subject = message === null ? null : 1.65 + message instanceof Ci.nsISupports ? message : 1.66 + message.wrappedJSObject ? message : 1.67 + {wrappedJSObject: message}; 1.68 + if (sync) 1.69 + notifyObservers(subject, topic, null); 1.70 + else 1.71 + setImmediate(notifyObservers, subject, topic, null); 1.72 +}; 1.73 +OutputPort.prototype[receive] = OutputPort.receive; 1.74 +exports.OutputPort = OutputPort;