more pm28 fixes
[guerillascript.git] / main / modules / signals.jsm
blobc3b70f8ce3f4c0550cf6c3c441b8d1680ca0e406
1 /* coded by Ketmar // Invisible Vector (psyc://ketmar.no-ip.org/~Ketmar)
2  * Understanding is not required. Only obedience.
3  *
4  * This program is free software. It comes without any warranty, to
5  * the extent permitted by applicable law. You can redistribute it
6  * and/or modify it under the terms of the Do What The Fuck You Want
7  * To Public License, Version 2, as published by Sam Hocevar. See
8  * http://www.wtfpl.net/txt/copying/ for more details.
9  */
10 ////////////////////////////////////////////////////////////////////////////////
11 this.EXPORTED_SYMBOLS = [
12   "addSignalListener",
13   "removeSignalListener",
14   "emitSignal",
15   "signalNamePrefix"
18 ////////////////////////////////////////////////////////////////////////////////
19 const {utils:Cu, classes:Cc, interfaces:Ci, results:Cr} = Components;
22 function genUUID () {
23   let uuidgen = Cc["@mozilla.org/uuid-generator;1"].createInstance(Ci.nsIUUIDGenerator);
24   if (!uuidgen) throw new Error("no UUID generator available!");
25   return uuidgen.generateUUID().toString().replace(/[^-a-z0-9]/ig, "");
29 ////////////////////////////////////////////////////////////////////////////////
30 const signalNamePrefix = "signal-"+genUUID()+"-";
31 const obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
34 ////////////////////////////////////////////////////////////////////////////////
35 // string key: name
36 // object value:
37 //   object observer
38 //   array[] callbacks
39 let observers = {};
41 function addSignalListener (name, cback) {
42   if (typeof(name) !== "string" || !name) throw new Error("invalid signal name");
43   if (typeof(cback) !== "function") throw new Error("callback function expected");
44   // check if already here
45   let nfo = observers[name];
46   if (nfo !== undefined) {
47     for (let cb of nfo.callbacks) if (cb === cback) return; // nothing to do
48   } else {
49     // no observer, create one
50     nfo = {callbacks:[]};
51     nfo.observer = {
52       observe: function (subject, topic, data) {
53         topic = topic.substr(signalNamePrefix.length); // remove prefix
54         if (data && data.length) {
55           try { data = JSON.parse(data); } catch (e) { Cu.reportError(e); return; }
56         } else {
57           data = null;
58         }
59         for (let cb of nfo.callbacks) {
60           try { cb(topic, data); } catch (e) { Cu.reportError(e); }
61         }
62       },
63     };
64     obs.addObserver(nfo.observer, signalNamePrefix+name, false);
65     observers[name] = nfo;
66   }
67   nfo.callbacks.push(cback);
71 function removeSignalListener (name, cback) {
72   if (typeof(name) !== "string" || !name) throw new Error("invalid signal name");
73   if (typeof(cback) !== "function") throw new Error("callback function expected");
74   // find observer
75   let nfo = observers[name];
76   if (nfo !== undefined) {
77     for (let [idx, cb] of Iterator(nfo.callbacks)) {
78       if (cb === cback) {
79         // remove callback
80         nfo.callbacks.splice(idx, 1);
81         // if there's no more callbacks, remove observer
82         if (nfo.callbacks.length === 0) {
83           obs.removeObserver(nfo.observer, signalNamePrefix+name);
84           delete observers[name];
85         }
86         return;
87       }
88     }
89   }
93 function emitSignal (name, data) {
94   if (typeof(name) !== "string" || !name) throw new Error("invalid signal name");
95   if (!(name in observers)) return; // no listeners -- no need to send anything
96   data = (typeof(data) === "undefined" ? null : (data !== null ? JSON.stringify(data) : null));
97   obs.notifyObservers(null, signalNamePrefix+name, data);