Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
const lazy = {};
ChromeUtils.defineLazyGetter(lazy, "console", () => {
return console.createInstance({
prefix: "NotificationStorage",
maxLogLevelPref: "dom.webnotifications.loglevel",
});
});
const kMessageGetAllOk = "GetAll:Return:OK";
const kMessageGetAllKo = "GetAll:Return:KO";
const kMessageSaveKo = "Save:Return:KO";
const kMessageDeleteKo = "Delete:Return:KO";
export class NotificationStorage {
#requests = {};
#requestCount = 0;
constructor() {
Services.obs.addObserver(this, "xpcom-shutdown");
// Register for message listeners.
this.registerListeners();
}
storageQualifier() {
return "Notification";
}
prefixStorageQualifier(message) {
return `${this.storageQualifier()}:${message}`;
}
formatMessageType(message) {
return this.prefixStorageQualifier(message);
}
supportedMessages() {
return [
this.formatMessageType(kMessageGetAllOk),
this.formatMessageType(kMessageGetAllKo),
this.formatMessageType(kMessageSaveKo),
this.formatMessageType(kMessageDeleteKo),
];
}
registerListeners() {
for (let message of this.supportedMessages()) {
Services.cpmm.addMessageListener(message, this);
}
}
unregisterListeners() {
for (let message of this.supportedMessages()) {
Services.cpmm.removeMessageListener(message, this);
}
}
observe(aSubject, aTopic) {
lazy.console.debug(`Topic: ${aTopic}`);
if (aTopic === "xpcom-shutdown") {
Services.obs.removeObserver(this, "xpcom-shutdown");
this.unregisterListeners();
}
}
put(
origin,
id,
title,
dir,
lang,
body,
tag,
icon,
alertName,
data,
behavior,
serviceWorkerRegistrationScope
) {
lazy.console.debug(`PUT: ${origin} ${id}: ${title}`);
var notification = {
id,
title,
dir,
lang,
body,
tag,
icon,
alertName,
timestamp: new Date().getTime(),
origin,
data,
mozbehavior: behavior,
serviceWorkerRegistrationScope,
};
Services.cpmm.sendAsyncMessage(this.formatMessageType("Save"), {
origin,
notification,
});
}
get(origin, tag, callback) {
lazy.console.debug(`GET: ${origin} ${tag}`);
this.#fetchFromDB(origin, tag, callback);
}
delete(origin, id) {
lazy.console.debug(`DELETE: ${id}`);
Services.cpmm.sendAsyncMessage(this.formatMessageType("Delete"), {
origin,
id,
});
}
receiveMessage(message) {
var request = this.#requests[message.data.requestID];
switch (message.name) {
case this.formatMessageType(kMessageGetAllOk):
delete this.#requests[message.data.requestID];
this.#returnNotifications(message.data.notifications, request.callback);
break;
case this.formatMessageType(kMessageGetAllKo):
delete this.#requests[message.data.requestID];
try {
request.callback.done();
} catch (e) {
lazy.console.debug(`Error calling callback done: ${e}`);
}
break;
case this.formatMessageType(kMessageSaveKo):
case this.formatMessageType(kMessageDeleteKo):
lazy.console.debug(
`Error received when treating: '${message.name}': ${message.data.errorMsg}`
);
break;
default:
lazy.console.debug(`Unrecognized message: ${message.name}`);
break;
}
}
#getUniqueRequestID() {
// This assumes the count will never go above MAX_SAFE_INTEGER, as
// notifications are not supposed to happen that frequently.
this.#requestCount += 1;
return this.#requestCount;
}
#fetchFromDB(origin, tag, callback) {
var request = {
origin,
tag,
callback,
};
var requestID = this.#getUniqueRequestID();
this.#requests[requestID] = request;
Services.cpmm.sendAsyncMessage(this.formatMessageType("GetAll"), {
origin,
tag,
requestID,
});
}
#returnNotifications(notifications, callback) {
// Pass each notification back separately.
// The callback is called asynchronously to match the behaviour when
// fetching from the database.
notifications.forEach(function (notification) {
try {
Services.tm.dispatchToMainThread(
callback.handle.bind(
callback,
notification.id,
notification.title,
notification.dir,
notification.lang,
notification.body,
notification.tag,
notification.icon,
notification.data,
notification.mozbehavior,
notification.serviceWorkerRegistrationScope
)
);
} catch (e) {
lazy.console.debug(`Error calling callback handle: ${e}`);
}
});
try {
Services.tm.dispatchToMainThread(callback.done);
} catch (e) {
lazy.console.debug(`Error calling callback done: ${e}`);
}
}
QueryInterface = ChromeUtils.generateQI(["nsINotificationStorage"]);
}
export class MemoryNotificationStorage extends NotificationStorage {
storageQualifier() {
return "MemoryNotification";
}
}