diff options
Diffstat (limited to 'toolkit/components/webextensions/ext-alarms.js')
-rw-r--r-- | toolkit/components/webextensions/ext-alarms.js | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/toolkit/components/webextensions/ext-alarms.js b/toolkit/components/webextensions/ext-alarms.js new file mode 100644 index 000000000..2171e7dba --- /dev/null +++ b/toolkit/components/webextensions/ext-alarms.js @@ -0,0 +1,155 @@ +"use strict"; + +var {classes: Cc, interfaces: Ci, utils: Cu} = Components; + +Cu.import("resource://gre/modules/ExtensionUtils.jsm"); +var { + EventManager, +} = ExtensionUtils; + +// WeakMap[Extension -> Map[name -> Alarm]] +var alarmsMap = new WeakMap(); + +// WeakMap[Extension -> Set[callback]] +var alarmCallbacksMap = new WeakMap(); + +// Manages an alarm created by the extension (alarms API). +function Alarm(extension, name, alarmInfo) { + this.extension = extension; + this.name = name; + this.when = alarmInfo.when; + this.delayInMinutes = alarmInfo.delayInMinutes; + this.periodInMinutes = alarmInfo.periodInMinutes; + this.canceled = false; + + let delay, scheduledTime; + if (this.when) { + scheduledTime = this.when; + delay = this.when - Date.now(); + } else { + if (!this.delayInMinutes) { + this.delayInMinutes = this.periodInMinutes; + } + delay = this.delayInMinutes * 60 * 1000; + scheduledTime = Date.now() + delay; + } + + this.scheduledTime = scheduledTime; + + let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + timer.init(this, delay, Ci.nsITimer.TYPE_ONE_SHOT); + this.timer = timer; +} + +Alarm.prototype = { + clear() { + this.timer.cancel(); + alarmsMap.get(this.extension).delete(this.name); + this.canceled = true; + }, + + observe(subject, topic, data) { + if (this.canceled) { + return; + } + + for (let callback of alarmCallbacksMap.get(this.extension)) { + callback(this); + } + + if (!this.periodInMinutes) { + this.clear(); + return; + } + + let delay = this.periodInMinutes * 60 * 1000; + this.scheduledTime = Date.now() + delay; + this.timer.init(this, delay, Ci.nsITimer.TYPE_ONE_SHOT); + }, + + get data() { + return { + name: this.name, + scheduledTime: this.scheduledTime, + periodInMinutes: this.periodInMinutes, + }; + }, +}; + +/* eslint-disable mozilla/balanced-listeners */ +extensions.on("startup", (type, extension) => { + alarmsMap.set(extension, new Map()); + alarmCallbacksMap.set(extension, new Set()); +}); + +extensions.on("shutdown", (type, extension) => { + if (alarmsMap.has(extension)) { + for (let alarm of alarmsMap.get(extension).values()) { + alarm.clear(); + } + alarmsMap.delete(extension); + alarmCallbacksMap.delete(extension); + } +}); +/* eslint-enable mozilla/balanced-listeners */ + +extensions.registerSchemaAPI("alarms", "addon_parent", context => { + let {extension} = context; + return { + alarms: { + create: function(name, alarmInfo) { + name = name || ""; + let alarms = alarmsMap.get(extension); + if (alarms.has(name)) { + alarms.get(name).clear(); + } + let alarm = new Alarm(extension, name, alarmInfo); + alarms.set(alarm.name, alarm); + }, + + get: function(name) { + name = name || ""; + let alarms = alarmsMap.get(extension); + if (alarms.has(name)) { + return Promise.resolve(alarms.get(name).data); + } + return Promise.resolve(); + }, + + getAll: function() { + let result = Array.from(alarmsMap.get(extension).values(), alarm => alarm.data); + return Promise.resolve(result); + }, + + clear: function(name) { + name = name || ""; + let alarms = alarmsMap.get(extension); + if (alarms.has(name)) { + alarms.get(name).clear(); + return Promise.resolve(true); + } + return Promise.resolve(false); + }, + + clearAll: function() { + let cleared = false; + for (let alarm of alarmsMap.get(extension).values()) { + alarm.clear(); + cleared = true; + } + return Promise.resolve(cleared); + }, + + onAlarm: new EventManager(context, "alarms.onAlarm", fire => { + let callback = alarm => { + fire(alarm.data); + }; + + alarmCallbacksMap.get(extension).add(callback); + return () => { + alarmCallbacksMap.get(extension).delete(callback); + }; + }).api(), + }, + }; +}); |