summaryrefslogtreecommitdiffstats
path: root/toolkit/components/webextensions/ext-alarms.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/webextensions/ext-alarms.js')
-rw-r--r--toolkit/components/webextensions/ext-alarms.js155
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(),
+ },
+ };
+});