Bug 1799524 [wpt PR 36848] - FSA: Reject overwriting moves with InvalidModificationEr...
[gecko.git] / dom / notification / NotificationStorage.jsm
blobfb282447abddca9fd5fbee6738ced6e33e5cfe8b
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 "use strict";
7 const DEBUG = false;
8 function debug(s) {
9   dump("-*- NotificationStorage.js: " + s + "\n");
12 const kMessageNotificationGetAllOk = "Notification:GetAll:Return:OK";
13 const kMessageNotificationGetAllKo = "Notification:GetAll:Return:KO";
14 const kMessageNotificationSaveKo = "Notification:Save:Return:KO";
15 const kMessageNotificationDeleteKo = "Notification:Delete:Return:KO";
17 const kMessages = [
18   kMessageNotificationGetAllOk,
19   kMessageNotificationGetAllKo,
20   kMessageNotificationSaveKo,
21   kMessageNotificationDeleteKo,
24 function NotificationStorage() {
25   this._requests = {};
26   this._requestCount = 0;
28   Services.obs.addObserver(this, "xpcom-shutdown");
30   // Register for message listeners.
31   this.registerListeners();
34 NotificationStorage.prototype = {
35   registerListeners() {
36     for (let message of kMessages) {
37       Services.cpmm.addMessageListener(message, this);
38     }
39   },
41   unregisterListeners() {
42     for (let message of kMessages) {
43       Services.cpmm.removeMessageListener(message, this);
44     }
45   },
47   observe(aSubject, aTopic, aData) {
48     if (DEBUG) {
49       debug("Topic: " + aTopic);
50     }
51     if (aTopic === "xpcom-shutdown") {
52       Services.obs.removeObserver(this, "xpcom-shutdown");
53       this.unregisterListeners();
54     }
55   },
57   put(
58     origin,
59     id,
60     title,
61     dir,
62     lang,
63     body,
64     tag,
65     icon,
66     alertName,
67     data,
68     behavior,
69     serviceWorkerRegistrationScope
70   ) {
71     if (DEBUG) {
72       debug("PUT: " + origin + " " + id + ": " + title);
73     }
74     var notification = {
75       id,
76       title,
77       dir,
78       lang,
79       body,
80       tag,
81       icon,
82       alertName,
83       timestamp: new Date().getTime(),
84       origin,
85       data,
86       mozbehavior: behavior,
87       serviceWorkerRegistrationScope,
88     };
90     Services.cpmm.sendAsyncMessage("Notification:Save", {
91       origin,
92       notification,
93     });
94   },
96   get(origin, tag, callback) {
97     if (DEBUG) {
98       debug("GET: " + origin + " " + tag);
99     }
100     this._fetchFromDB(origin, tag, callback);
101   },
103   getByID(origin, id, callback) {
104     if (DEBUG) {
105       debug("GETBYID: " + origin + " " + id);
106     }
107     var GetByIDProxyCallback = function(id, originalCallback) {
108       this.searchID = id;
109       this.originalCallback = originalCallback;
110       var self = this;
111       this.handle = function(
112         id,
113         title,
114         dir,
115         lang,
116         body,
117         tag,
118         icon,
119         data,
120         behavior,
121         serviceWorkerRegistrationScope
122       ) {
123         if (id == this.searchID) {
124           self.originalCallback.handle(
125             id,
126             title,
127             dir,
128             lang,
129             body,
130             tag,
131             icon,
132             data,
133             behavior,
134             serviceWorkerRegistrationScope
135           );
136         }
137       };
138       this.done = function() {
139         self.originalCallback.done();
140       };
141     };
143     return this.get(origin, "", new GetByIDProxyCallback(id, callback));
144   },
146   delete(origin, id) {
147     if (DEBUG) {
148       debug("DELETE: " + id);
149     }
150     Services.cpmm.sendAsyncMessage("Notification:Delete", {
151       origin,
152       id,
153     });
154   },
156   receiveMessage(message) {
157     var request = this._requests[message.data.requestID];
159     switch (message.name) {
160       case kMessageNotificationGetAllOk:
161         delete this._requests[message.data.requestID];
162         this._returnNotifications(
163           message.data.notifications,
164           request.origin,
165           request.tag,
166           request.callback
167         );
168         break;
170       case kMessageNotificationGetAllKo:
171         delete this._requests[message.data.requestID];
172         try {
173           request.callback.done();
174         } catch (e) {
175           debug("Error calling callback done: " + e);
176         }
177         break;
178       case kMessageNotificationSaveKo:
179       case kMessageNotificationDeleteKo:
180         if (DEBUG) {
181           debug(
182             "Error received when treating: '" +
183               message.name +
184               "': " +
185               message.data.errorMsg
186           );
187         }
188         break;
190       default:
191         if (DEBUG) {
192           debug("Unrecognized message: " + message.name);
193         }
194         break;
195     }
196   },
198   _fetchFromDB(origin, tag, callback) {
199     var request = {
200       origin,
201       tag,
202       callback,
203     };
204     var requestID = this._requestCount++;
205     this._requests[requestID] = request;
206     Services.cpmm.sendAsyncMessage("Notification:GetAll", {
207       origin,
208       tag,
209       requestID,
210     });
211   },
213   _returnNotifications(notifications, origin, tag, callback) {
214     // Pass each notification back separately.
215     // The callback is called asynchronously to match the behaviour when
216     // fetching from the database.
217     notifications.forEach(function(notification) {
218       try {
219         Services.tm.dispatchToMainThread(
220           callback.handle.bind(
221             callback,
222             notification.id,
223             notification.title,
224             notification.dir,
225             notification.lang,
226             notification.body,
227             notification.tag,
228             notification.icon,
229             notification.data,
230             notification.mozbehavior,
231             notification.serviceWorkerRegistrationScope
232           )
233         );
234       } catch (e) {
235         if (DEBUG) {
236           debug("Error calling callback handle: " + e);
237         }
238       }
239     });
240     try {
241       Services.tm.dispatchToMainThread(callback.done);
242     } catch (e) {
243       if (DEBUG) {
244         debug("Error calling callback done: " + e);
245       }
246     }
247   },
249   QueryInterface: ChromeUtils.generateQI(["nsINotificationStorage"]),
252 var EXPORTED_SYMBOLS = ["NotificationStorage"];