1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/src/notification/NotificationStorage.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,186 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +const DEBUG = false; 1.11 +function debug(s) { dump("-*- NotificationStorage.js: " + s + "\n"); } 1.12 + 1.13 +const Cc = Components.classes; 1.14 +const Ci = Components.interfaces; 1.15 +const Cu = Components.utils; 1.16 + 1.17 +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 1.18 + 1.19 +const NOTIFICATIONSTORAGE_CID = "{37f819b0-0b5c-11e3-8ffd-0800200c9a66}"; 1.20 +const NOTIFICATIONSTORAGE_CONTRACTID = "@mozilla.org/notificationStorage;1"; 1.21 + 1.22 +XPCOMUtils.defineLazyServiceGetter(this, "cpmm", 1.23 + "@mozilla.org/childprocessmessagemanager;1", 1.24 + "nsIMessageSender"); 1.25 + 1.26 + 1.27 +function NotificationStorage() { 1.28 + // cache objects 1.29 + this._notifications = {}; 1.30 + this._byTag = {}; 1.31 + this._cached = false; 1.32 + 1.33 + this._requests = {}; 1.34 + this._requestCount = 0; 1.35 + 1.36 + // Register for message listeners. 1.37 + cpmm.addMessageListener("Notification:GetAll:Return:OK", this); 1.38 +} 1.39 + 1.40 +NotificationStorage.prototype = { 1.41 + 1.42 + put: function(origin, id, title, dir, lang, body, tag, icon) { 1.43 + if (DEBUG) { debug("PUT: " + id + ": " + title); } 1.44 + var notification = { 1.45 + id: id, 1.46 + title: title, 1.47 + dir: dir, 1.48 + lang: lang, 1.49 + body: body, 1.50 + tag: tag, 1.51 + icon: icon, 1.52 + origin: origin 1.53 + }; 1.54 + 1.55 + this._notifications[id] = notification; 1.56 + if (tag) { 1.57 + if (!this._byTag[origin]) { 1.58 + this._byTag[origin] = {}; 1.59 + } 1.60 + 1.61 + // We might have existing notification with this tag, 1.62 + // if so we need to remove it from our cache. 1.63 + if (this._byTag[origin][tag]) { 1.64 + var oldNotification = this._byTag[origin][tag]; 1.65 + delete this._notifications[oldNotification.id]; 1.66 + } 1.67 + 1.68 + this._byTag[origin][tag] = notification; 1.69 + }; 1.70 + 1.71 + cpmm.sendAsyncMessage("Notification:Save", { 1.72 + origin: origin, 1.73 + notification: notification 1.74 + }); 1.75 + }, 1.76 + 1.77 + get: function(origin, tag, callback) { 1.78 + if (DEBUG) { debug("GET: " + origin + " " + tag); } 1.79 + if (this._cached) { 1.80 + this._fetchFromCache(origin, tag, callback); 1.81 + } else { 1.82 + this._fetchFromDB(origin, tag, callback); 1.83 + } 1.84 + }, 1.85 + 1.86 + delete: function(origin, id) { 1.87 + if (DEBUG) { debug("DELETE: " + id); } 1.88 + var notification = this._notifications[id]; 1.89 + if (notification) { 1.90 + if (notification.tag) { 1.91 + delete this._byTag[origin][notification.tag]; 1.92 + } 1.93 + delete this._notifications[id]; 1.94 + } 1.95 + 1.96 + cpmm.sendAsyncMessage("Notification:Delete", { 1.97 + origin: origin, 1.98 + id: id 1.99 + }); 1.100 + }, 1.101 + 1.102 + receiveMessage: function(message) { 1.103 + switch (message.name) { 1.104 + case "Notification:GetAll:Return:OK": 1.105 + var request = this._requests[message.data.requestID]; 1.106 + delete this._requests[message.data.requestID]; 1.107 + this._populateCache(message.data.notifications); 1.108 + this._fetchFromCache(request.origin, request.tag, request.callback); 1.109 + break; 1.110 + 1.111 + default: 1.112 + if (DEBUG) debug("Unrecognized message: " + message.name); 1.113 + break; 1.114 + } 1.115 + }, 1.116 + 1.117 + _fetchFromDB: function(origin, tag, callback) { 1.118 + var request = { 1.119 + origin: origin, 1.120 + tag: tag, 1.121 + callback: callback 1.122 + }; 1.123 + var requestID = this._requestCount++; 1.124 + this._requests[requestID] = request; 1.125 + cpmm.sendAsyncMessage("Notification:GetAll", { 1.126 + origin: origin, 1.127 + requestID: requestID 1.128 + }); 1.129 + }, 1.130 + 1.131 + _fetchFromCache: function(origin, tag, callback) { 1.132 + var notifications = []; 1.133 + // If a tag was specified and we have a notification 1.134 + // with this tag, return that. If no tag was specified 1.135 + // simple return all stored notifications. 1.136 + if (tag && this._byTag[origin] && this._byTag[origin][tag]) { 1.137 + notifications.push(this._byTag[origin][tag]); 1.138 + } else if (!tag) { 1.139 + for (var id in this._notifications) { 1.140 + if (this._notifications[id].origin === origin) { 1.141 + notifications.push(this._notifications[id]); 1.142 + } 1.143 + } 1.144 + } 1.145 + 1.146 + // Pass each notification back separately. 1.147 + notifications.forEach(function(notification) { 1.148 + try { 1.149 + callback.handle(notification.id, 1.150 + notification.title, 1.151 + notification.dir, 1.152 + notification.lang, 1.153 + notification.body, 1.154 + notification.tag, 1.155 + notification.icon); 1.156 + } catch (e) { 1.157 + if (DEBUG) { debug("Error calling callback handle: " + e); } 1.158 + } 1.159 + }); 1.160 + try { 1.161 + callback.done(); 1.162 + } catch (e) { 1.163 + if (DEBUG) { debug("Error calling callback done: " + e); } 1.164 + } 1.165 + }, 1.166 + 1.167 + _populateCache: function(notifications) { 1.168 + notifications.forEach(function(notification) { 1.169 + this._notifications[notification.id] = notification; 1.170 + if (notification.tag && notification.origin) { 1.171 + let tag = notification.tag; 1.172 + let origin = notification.origin; 1.173 + if (!this._byTag[origin]) { 1.174 + this._byTag[origin] = {}; 1.175 + } 1.176 + this._byTag[origin][tag] = notification; 1.177 + } 1.178 + }.bind(this)); 1.179 + this._cached = true; 1.180 + }, 1.181 + 1.182 + classID : Components.ID(NOTIFICATIONSTORAGE_CID), 1.183 + contractID : NOTIFICATIONSTORAGE_CONTRACTID, 1.184 + QueryInterface: XPCOMUtils.generateQI([Ci.nsINotificationStorage, 1.185 + Ci.nsIMessageListener]), 1.186 +}; 1.187 + 1.188 + 1.189 +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NotificationStorage]);