system.js 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. "use strict";
  5. const { Cc, Ci, Cr } = require("chrome");
  6. const { Input, start, stop, receive, outputs } = require("../event/utils");
  7. const { id: addonID } = require("../self");
  8. const { setImmediate } = require("../timers");
  9. const { notifyObservers } = Cc['@mozilla.org/observer-service;1'].
  10. getService(Ci.nsIObserverService);
  11. const NOT_AN_INPUT = "OutputPort can be used only for sending messages";
  12. // `OutputPort` creates a port to which messages can be send. Those
  13. // messages are actually disptached as `subject`'s of the observer
  14. // notifications. This is handy for communicating between different
  15. // components of the SDK. By default messages are dispatched
  16. // asynchronously, although `options.sync` can be used to make them
  17. // synchronous. If `options.id` is given `topic` for observer
  18. // notifications is generated by namespacing it, to avoid spamming
  19. // other SDK add-ons. It's also possible to provide `options.topic`
  20. // to use excat `topic` without namespacing it.
  21. //
  22. // Note: Symmetric `new InputPort({ id: "x" })` instances can be used to
  23. // receive messages send to the instances of `new OutputPort({ id: "x" })`.
  24. const OutputPort = function({id, topic, sync}) {
  25. this.id = id || topic;
  26. this.sync = !!sync;
  27. this.topic = topic || "sdk:" + addonID + ":" + id;
  28. };
  29. // OutputPort extends base signal type to implement same message
  30. // receiving interface.
  31. OutputPort.prototype = new Input();
  32. OutputPort.constructor = OutputPort;
  33. // OutputPort can not be consumed there for starting or stopping it
  34. // is not supported.
  35. OutputPort.prototype[start] = _ => { throw TypeError(NOT_AN_INPUT); };
  36. OutputPort.prototype[stop] = _ => { throw TypeError(NOT_AN_INPUT); };
  37. // Port reecives message send to it, which will be dispatched via
  38. // observer notification service.
  39. OutputPort.receive = ({topic, sync}, message) => {
  40. const type = typeof(message);
  41. const supported = message === null ||
  42. type === "object" ||
  43. type === "function";
  44. // There is no sensible way to wrap JS primitives that would make sense
  45. // for general observer notification users. It's also probably not very
  46. // useful to dispatch JS primitives as subject of observer service, there
  47. // for we do not support those use cases.
  48. if (!supported)
  49. throw new TypeError("Unsupproted message type: `" + type + "`");
  50. // Normalize `message` to create a valid observer notification `subject`.
  51. // If `message` is `null`, implements `nsISupports` interface or already
  52. // represents wrapped JS object use it as is. Otherwise create a wrapped
  53. // object so that observers could receive it.
  54. const subject = message === null ? null :
  55. message instanceof Ci.nsISupports ? message :
  56. message.wrappedJSObject ? message :
  57. {wrappedJSObject: message};
  58. if (sync)
  59. notifyObservers(subject, topic, null);
  60. else
  61. setImmediate(notifyObservers, subject, topic, null);
  62. };
  63. OutputPort.prototype[receive] = OutputPort.receive;
  64. exports.OutputPort = OutputPort;