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