Bug 1432605: Fix alarms API when multiple contexts use it. r?aswan
MozReview-Commit-ID: E5CIYrlEiSd
--- a/toolkit/components/extensions/ext-alarms.js
+++ b/toolkit/components/extensions/ext-alarms.js
@@ -1,22 +1,16 @@
"use strict";
// The ext-* files are imported into the same scopes.
/* import-globals-from ext-toolkit.js */
-// WeakMap[Extension -> Map[name -> Alarm]]
-let alarmsMap = new WeakMap();
-
-// WeakMap[Extension -> Set[callback]]
-let alarmCallbacksMap = new WeakMap();
-
// Manages an alarm created by the extension (alarms API).
-function Alarm(extension, name, alarmInfo) {
- this.extension = extension;
+function Alarm(api, name, alarmInfo) {
+ this.api = api;
this.name = name;
this.when = alarmInfo.when;
this.delayInMinutes = alarmInfo.delayInMinutes;
this.periodInMinutes = alarmInfo.periodInMinutes;
this.canceled = false;
let delay, scheduledTime;
if (this.when) {
@@ -35,26 +29,26 @@ function Alarm(extension, name, alarmInf
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.api.alarms.delete(this.name);
this.canceled = true;
},
observe(subject, topic, data) {
if (this.canceled) {
return;
}
- for (let callback of alarmCallbacksMap.get(this.extension)) {
+ for (let callback of this.api.callbacks) {
callback(this);
}
if (!this.periodInMinutes) {
this.clear();
return;
}
@@ -68,85 +62,80 @@ Alarm.prototype = {
name: this.name,
scheduledTime: this.scheduledTime,
periodInMinutes: this.periodInMinutes,
};
},
};
this.alarms = class extends ExtensionAPI {
- onShutdown() {
- let {extension} = this;
+ constructor(extension) {
+ super(extension);
- if (alarmsMap.has(extension)) {
- for (let alarm of alarmsMap.get(extension).values()) {
- alarm.clear();
- }
- alarmsMap.delete(extension);
- alarmCallbacksMap.delete(extension);
+ this.alarms = new Map();
+ this.callbacks = new Set();
+ }
+
+ onShutdown() {
+ for (let alarm of this.alarms.values()) {
+ alarm.clear();
}
}
getAPI(context) {
- let {extension} = context;
-
- alarmsMap.set(extension, new Map());
- alarmCallbacksMap.set(extension, new Set());
+ const self = this;
return {
alarms: {
create: function(name, alarmInfo) {
name = name || "";
- let alarms = alarmsMap.get(extension);
- if (alarms.has(name)) {
- alarms.get(name).clear();
+ if (self.alarms.has(name)) {
+ self.alarms.get(name).clear();
}
- let alarm = new Alarm(extension, name, alarmInfo);
- alarms.set(alarm.name, alarm);
+ let alarm = new Alarm(self, name, alarmInfo);
+ self.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);
+ if (self.alarms.has(name)) {
+ return Promise.resolve(self.alarms.get(name).data);
}
return Promise.resolve();
},
getAll: function() {
- let result = Array.from(alarmsMap.get(extension).values(), alarm => alarm.data);
+ let result = Array.from(self.alarms.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();
+ if (self.alarms.has(name)) {
+ self.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()) {
+ for (let alarm of self.alarms.values()) {
alarm.clear();
cleared = true;
}
return Promise.resolve(cleared);
},
onAlarm: new EventManager(context, "alarms.onAlarm", fire => {
let callback = alarm => {
fire.sync(alarm.data);
};
- alarmCallbacksMap.get(extension).add(callback);
+ self.callbacks.add(callback);
return () => {
- alarmCallbacksMap.get(extension).delete(callback);
+ self.callbacks.delete(callback);
};
}).api(),
},
};
}
};