Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | "use strict" |
michael@0 | 6 | |
michael@0 | 7 | /* static functions */ |
michael@0 | 8 | let DEBUG = 0; |
michael@0 | 9 | let debug; |
michael@0 | 10 | if (DEBUG) |
michael@0 | 11 | debug = function (s) { dump("-*- SettingsService: " + s + "\n"); } |
michael@0 | 12 | else |
michael@0 | 13 | debug = function (s) {} |
michael@0 | 14 | |
michael@0 | 15 | const Ci = Components.interfaces; |
michael@0 | 16 | const Cu = Components.utils; |
michael@0 | 17 | |
michael@0 | 18 | Cu.import("resource://gre/modules/SettingsQueue.jsm"); |
michael@0 | 19 | Cu.import("resource://gre/modules/SettingsDB.jsm"); |
michael@0 | 20 | Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
michael@0 | 21 | Cu.import("resource://gre/modules/Services.jsm"); |
michael@0 | 22 | |
michael@0 | 23 | const nsIClassInfo = Ci.nsIClassInfo; |
michael@0 | 24 | |
michael@0 | 25 | const SETTINGSSERVICELOCK_CONTRACTID = "@mozilla.org/settingsServiceLock;1"; |
michael@0 | 26 | const SETTINGSSERVICELOCK_CID = Components.ID("{d7a395a0-e292-11e1-834e-1761d57f5f99}"); |
michael@0 | 27 | const nsISettingsServiceLock = Ci.nsISettingsServiceLock; |
michael@0 | 28 | |
michael@0 | 29 | function SettingsServiceLock(aSettingsService) |
michael@0 | 30 | { |
michael@0 | 31 | if (DEBUG) debug("settingsServiceLock constr!"); |
michael@0 | 32 | this._open = true; |
michael@0 | 33 | this._busy = false; |
michael@0 | 34 | this._requests = new Queue(); |
michael@0 | 35 | this._settingsService = aSettingsService; |
michael@0 | 36 | this._transaction = null; |
michael@0 | 37 | } |
michael@0 | 38 | |
michael@0 | 39 | SettingsServiceLock.prototype = { |
michael@0 | 40 | |
michael@0 | 41 | callHandle: function callHandle(aCallback, aName, aValue) { |
michael@0 | 42 | try { |
michael@0 | 43 | aCallback ? aCallback.handle(aName, aValue) : null; |
michael@0 | 44 | } catch (e) { |
michael@0 | 45 | dump("settings 'handle' callback threw an exception, dropping: " + e + "\n"); |
michael@0 | 46 | } |
michael@0 | 47 | }, |
michael@0 | 48 | |
michael@0 | 49 | callAbort: function callAbort(aCallback, aMessage) { |
michael@0 | 50 | try { |
michael@0 | 51 | aCallback ? aCallback.handleAbort(aMessage) : null; |
michael@0 | 52 | } catch (e) { |
michael@0 | 53 | dump("settings 'abort' callback threw an exception, dropping: " + e + "\n"); |
michael@0 | 54 | } |
michael@0 | 55 | }, |
michael@0 | 56 | |
michael@0 | 57 | callError: function callError(aCallback, aMessage) { |
michael@0 | 58 | try { |
michael@0 | 59 | aCallback ? aCallback.handleError(aMessage) : null; |
michael@0 | 60 | } catch (e) { |
michael@0 | 61 | dump("settings 'error' callback threw an exception, dropping: " + e + "\n"); |
michael@0 | 62 | } |
michael@0 | 63 | }, |
michael@0 | 64 | |
michael@0 | 65 | process: function process() { |
michael@0 | 66 | debug("process!"); |
michael@0 | 67 | let lock = this; |
michael@0 | 68 | lock._open = false; |
michael@0 | 69 | let store = lock._transaction.objectStore(SETTINGSSTORE_NAME); |
michael@0 | 70 | |
michael@0 | 71 | while (!lock._requests.isEmpty()) { |
michael@0 | 72 | if (lock._isBusy) { |
michael@0 | 73 | return; |
michael@0 | 74 | } |
michael@0 | 75 | let info = lock._requests.dequeue(); |
michael@0 | 76 | if (DEBUG) debug("info:" + info.intent); |
michael@0 | 77 | let callback = info.callback; |
michael@0 | 78 | let name = info.name; |
michael@0 | 79 | switch (info.intent) { |
michael@0 | 80 | case "set": |
michael@0 | 81 | let value = info.value; |
michael@0 | 82 | let message = info.message; |
michael@0 | 83 | if(DEBUG && typeof(value) == 'object') { |
michael@0 | 84 | debug("object name:" + name + ", val: " + JSON.stringify(value)); |
michael@0 | 85 | } |
michael@0 | 86 | lock._isBusy = true; |
michael@0 | 87 | let checkKeyRequest = store.get(name); |
michael@0 | 88 | |
michael@0 | 89 | checkKeyRequest.onsuccess = function (event) { |
michael@0 | 90 | let defaultValue; |
michael@0 | 91 | if (event.target.result) { |
michael@0 | 92 | defaultValue = event.target.result.defaultValue; |
michael@0 | 93 | } else { |
michael@0 | 94 | defaultValue = null; |
michael@0 | 95 | if (DEBUG) debug("MOZSETTINGS-SET-WARNING: " + name + " is not in the database.\n"); |
michael@0 | 96 | } |
michael@0 | 97 | let setReq = store.put({ settingName: name, defaultValue: defaultValue, userValue: value }); |
michael@0 | 98 | |
michael@0 | 99 | setReq.onsuccess = function() { |
michael@0 | 100 | lock._isBusy = false; |
michael@0 | 101 | lock._open = true; |
michael@0 | 102 | lock.callHandle(callback, name, value); |
michael@0 | 103 | Services.obs.notifyObservers(lock, "mozsettings-changed", JSON.stringify({ |
michael@0 | 104 | key: name, |
michael@0 | 105 | value: value, |
michael@0 | 106 | message: message |
michael@0 | 107 | })); |
michael@0 | 108 | lock._open = false; |
michael@0 | 109 | lock.process(); |
michael@0 | 110 | }; |
michael@0 | 111 | |
michael@0 | 112 | setReq.onerror = function(event) { |
michael@0 | 113 | lock._isBusy = false; |
michael@0 | 114 | lock.callError(callback, event.target.errorMessage); |
michael@0 | 115 | lock.process(); |
michael@0 | 116 | }; |
michael@0 | 117 | } |
michael@0 | 118 | |
michael@0 | 119 | checkKeyRequest.onerror = function(event) { |
michael@0 | 120 | lock._isBusy = false; |
michael@0 | 121 | lock.callError(callback, event.target.errorMessage); |
michael@0 | 122 | lock.process(); |
michael@0 | 123 | }; |
michael@0 | 124 | break; |
michael@0 | 125 | case "get": |
michael@0 | 126 | let getReq = store.mozGetAll(name); |
michael@0 | 127 | getReq.onsuccess = function(event) { |
michael@0 | 128 | if (DEBUG) { |
michael@0 | 129 | debug("Request successful. Record count:" + event.target.result.length); |
michael@0 | 130 | debug("result: " + JSON.stringify(event.target.result)); |
michael@0 | 131 | } |
michael@0 | 132 | this._open = true; |
michael@0 | 133 | if (callback) { |
michael@0 | 134 | if (event.target.result[0]) { |
michael@0 | 135 | if (event.target.result.length > 1) { |
michael@0 | 136 | if (DEBUG) debug("Warning: overloaded setting:" + name); |
michael@0 | 137 | } |
michael@0 | 138 | let result = event.target.result[0]; |
michael@0 | 139 | let value = result.userValue !== undefined |
michael@0 | 140 | ? result.userValue |
michael@0 | 141 | : result.defaultValue; |
michael@0 | 142 | lock.callHandle(callback, name, value); |
michael@0 | 143 | } else { |
michael@0 | 144 | lock.callHandle(callback, name, null); |
michael@0 | 145 | } |
michael@0 | 146 | } else { |
michael@0 | 147 | if (DEBUG) debug("no callback defined!"); |
michael@0 | 148 | } |
michael@0 | 149 | this._open = false; |
michael@0 | 150 | }.bind(lock); |
michael@0 | 151 | getReq.onerror = function error(event) { |
michael@0 | 152 | lock.callError(callback, event.target.errorMessage); |
michael@0 | 153 | }; |
michael@0 | 154 | break; |
michael@0 | 155 | } |
michael@0 | 156 | } |
michael@0 | 157 | lock._open = true; |
michael@0 | 158 | }, |
michael@0 | 159 | |
michael@0 | 160 | createTransactionAndProcess: function(aCallback) { |
michael@0 | 161 | if (this._settingsService._settingsDB._db) { |
michael@0 | 162 | let lock; |
michael@0 | 163 | while (lock = this._settingsService._locks.dequeue()) { |
michael@0 | 164 | if (!lock._transaction) { |
michael@0 | 165 | lock._transaction = lock._settingsService._settingsDB._db.transaction(SETTINGSSTORE_NAME, "readwrite"); |
michael@0 | 166 | if (aCallback) { |
michael@0 | 167 | lock._transaction.oncomplete = aCallback.handle; |
michael@0 | 168 | lock._transaction.onabort = function(event) { |
michael@0 | 169 | let message = ''; |
michael@0 | 170 | if (event.target.error) { |
michael@0 | 171 | message = event.target.error.name + ': ' + event.target.error.message; |
michael@0 | 172 | } |
michael@0 | 173 | this.callAbort(aCallback, message); |
michael@0 | 174 | }; |
michael@0 | 175 | } |
michael@0 | 176 | } |
michael@0 | 177 | if (!lock._isBusy) { |
michael@0 | 178 | lock.process(); |
michael@0 | 179 | } else { |
michael@0 | 180 | this._settingsService._locks.enqueue(lock); |
michael@0 | 181 | return; |
michael@0 | 182 | } |
michael@0 | 183 | } |
michael@0 | 184 | if (!this._requests.isEmpty() && !this._isBusy) { |
michael@0 | 185 | this.process(); |
michael@0 | 186 | } |
michael@0 | 187 | } |
michael@0 | 188 | }, |
michael@0 | 189 | |
michael@0 | 190 | get: function get(aName, aCallback) { |
michael@0 | 191 | if (DEBUG) debug("get: " + aName + ", " + aCallback); |
michael@0 | 192 | this._requests.enqueue({ callback: aCallback, intent:"get", name: aName }); |
michael@0 | 193 | this.createTransactionAndProcess(); |
michael@0 | 194 | }, |
michael@0 | 195 | |
michael@0 | 196 | set: function set(aName, aValue, aCallback, aMessage) { |
michael@0 | 197 | debug("set: " + aName + ": " + JSON.stringify(aValue)); |
michael@0 | 198 | if (aMessage === undefined) |
michael@0 | 199 | aMessage = null; |
michael@0 | 200 | this._requests.enqueue({ callback: aCallback, |
michael@0 | 201 | intent: "set", |
michael@0 | 202 | name: aName, |
michael@0 | 203 | value: this._settingsService._settingsDB.prepareValue(aValue), |
michael@0 | 204 | message: aMessage }); |
michael@0 | 205 | this.createTransactionAndProcess(); |
michael@0 | 206 | }, |
michael@0 | 207 | |
michael@0 | 208 | classID : SETTINGSSERVICELOCK_CID, |
michael@0 | 209 | QueryInterface : XPCOMUtils.generateQI([nsISettingsServiceLock]) |
michael@0 | 210 | }; |
michael@0 | 211 | |
michael@0 | 212 | const SETTINGSSERVICE_CID = Components.ID("{f656f0c0-f776-11e1-a21f-0800200c9a66}"); |
michael@0 | 213 | |
michael@0 | 214 | function SettingsService() |
michael@0 | 215 | { |
michael@0 | 216 | debug("settingsService Constructor"); |
michael@0 | 217 | this._locks = new Queue(); |
michael@0 | 218 | this._settingsDB = new SettingsDB(); |
michael@0 | 219 | this._settingsDB.init(); |
michael@0 | 220 | } |
michael@0 | 221 | |
michael@0 | 222 | SettingsService.prototype = { |
michael@0 | 223 | |
michael@0 | 224 | nextTick: function nextTick(aCallback, thisObj) { |
michael@0 | 225 | if (thisObj) |
michael@0 | 226 | aCallback = aCallback.bind(thisObj); |
michael@0 | 227 | |
michael@0 | 228 | Services.tm.currentThread.dispatch(aCallback, Ci.nsIThread.DISPATCH_NORMAL); |
michael@0 | 229 | }, |
michael@0 | 230 | |
michael@0 | 231 | createLock: function createLock(aCallback) { |
michael@0 | 232 | var lock = new SettingsServiceLock(this); |
michael@0 | 233 | this._locks.enqueue(lock); |
michael@0 | 234 | this._settingsDB.ensureDB( |
michael@0 | 235 | function() { lock.createTransactionAndProcess(aCallback); }, |
michael@0 | 236 | function() { dump("SettingsService failed to open DB!\n"); } |
michael@0 | 237 | ); |
michael@0 | 238 | this.nextTick(function() { this._open = false; }, lock); |
michael@0 | 239 | return lock; |
michael@0 | 240 | }, |
michael@0 | 241 | |
michael@0 | 242 | classID : SETTINGSSERVICE_CID, |
michael@0 | 243 | QueryInterface : XPCOMUtils.generateQI([Ci.nsISettingsService]) |
michael@0 | 244 | } |
michael@0 | 245 | |
michael@0 | 246 | this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsService, SettingsServiceLock]) |