2012-04-27 16:21:31 -07:00
|
|
|
/* 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/. */
|
|
|
|
|
|
|
|
"use strict"
|
|
|
|
|
|
|
|
/* static functions */
|
|
|
|
let DEBUG = 0;
|
2012-10-31 09:13:28 -07:00
|
|
|
let debug;
|
2012-04-27 16:21:31 -07:00
|
|
|
if (DEBUG)
|
|
|
|
debug = function (s) { dump("-*- SettingsService: " + s + "\n"); }
|
|
|
|
else
|
|
|
|
debug = function (s) {}
|
|
|
|
|
|
|
|
const Ci = Components.interfaces;
|
|
|
|
const Cu = Components.utils;
|
|
|
|
|
|
|
|
Cu.import("resource://gre/modules/SettingsQueue.jsm");
|
|
|
|
Cu.import("resource://gre/modules/SettingsDB.jsm");
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
|
|
|
|
|
|
const nsIClassInfo = Ci.nsIClassInfo;
|
|
|
|
|
|
|
|
const SETTINGSSERVICELOCK_CONTRACTID = "@mozilla.org/settingsServiceLock;1";
|
2012-08-31 00:37:43 -07:00
|
|
|
const SETTINGSSERVICELOCK_CID = Components.ID("{d7a395a0-e292-11e1-834e-1761d57f5f99}");
|
2012-04-27 16:21:31 -07:00
|
|
|
const nsISettingsServiceLock = Ci.nsISettingsServiceLock;
|
|
|
|
|
2014-05-20 12:19:18 -07:00
|
|
|
function SettingsServiceLock(aSettingsService, aTransactionCallback)
|
2012-04-27 16:21:31 -07:00
|
|
|
{
|
2013-01-08 03:04:25 -08:00
|
|
|
if (DEBUG) debug("settingsServiceLock constr!");
|
2012-04-27 16:21:31 -07:00
|
|
|
this._open = true;
|
2013-01-08 03:04:25 -08:00
|
|
|
this._busy = false;
|
2012-04-27 16:21:31 -07:00
|
|
|
this._requests = new Queue();
|
|
|
|
this._settingsService = aSettingsService;
|
|
|
|
this._transaction = null;
|
2014-05-20 12:19:18 -07:00
|
|
|
this._transactionCallback = aTransactionCallback;
|
2012-04-27 16:21:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
SettingsServiceLock.prototype = {
|
|
|
|
|
2014-04-23 14:16:24 -07:00
|
|
|
callHandle: function callHandle(aCallback, aName, aValue) {
|
|
|
|
try {
|
|
|
|
aCallback ? aCallback.handle(aName, aValue) : null;
|
|
|
|
} catch (e) {
|
|
|
|
dump("settings 'handle' callback threw an exception, dropping: " + e + "\n");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
callAbort: function callAbort(aCallback, aMessage) {
|
|
|
|
try {
|
|
|
|
aCallback ? aCallback.handleAbort(aMessage) : null;
|
|
|
|
} catch (e) {
|
|
|
|
dump("settings 'abort' callback threw an exception, dropping: " + e + "\n");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
callError: function callError(aCallback, aMessage) {
|
|
|
|
try {
|
|
|
|
aCallback ? aCallback.handleError(aMessage) : null;
|
|
|
|
} catch (e) {
|
|
|
|
dump("settings 'error' callback threw an exception, dropping: " + e + "\n");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-05-20 12:19:18 -07:00
|
|
|
callTransactionHandle: function callTransactionHandle() {
|
|
|
|
try {
|
|
|
|
this._transactionCallback ? this._transactionCallback.handle() : null;
|
|
|
|
} catch (e) {
|
|
|
|
dump("settings 'Transaction handle' callback threw an exception, dropping: " + e + "\n");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2012-04-27 16:21:31 -07:00
|
|
|
process: function process() {
|
|
|
|
debug("process!");
|
|
|
|
let lock = this;
|
|
|
|
lock._open = false;
|
|
|
|
let store = lock._transaction.objectStore(SETTINGSSTORE_NAME);
|
|
|
|
|
|
|
|
while (!lock._requests.isEmpty()) {
|
2013-01-08 03:04:25 -08:00
|
|
|
if (lock._isBusy) {
|
|
|
|
return;
|
|
|
|
}
|
2012-04-27 16:21:31 -07:00
|
|
|
let info = lock._requests.dequeue();
|
2013-01-08 03:04:25 -08:00
|
|
|
if (DEBUG) debug("info:" + info.intent);
|
2012-04-27 16:21:31 -07:00
|
|
|
let callback = info.callback;
|
|
|
|
let name = info.name;
|
|
|
|
switch (info.intent) {
|
|
|
|
case "set":
|
|
|
|
let value = info.value;
|
2012-08-31 00:37:43 -07:00
|
|
|
let message = info.message;
|
2013-01-08 03:04:25 -08:00
|
|
|
if(DEBUG && typeof(value) == 'object') {
|
2012-04-27 16:21:31 -07:00
|
|
|
debug("object name:" + name + ", val: " + JSON.stringify(value));
|
2013-01-08 03:04:25 -08:00
|
|
|
}
|
|
|
|
lock._isBusy = true;
|
2013-01-07 06:03:26 -08:00
|
|
|
let checkKeyRequest = store.get(name);
|
2012-04-27 16:21:31 -07:00
|
|
|
|
2013-01-07 06:03:26 -08:00
|
|
|
checkKeyRequest.onsuccess = function (event) {
|
|
|
|
let defaultValue;
|
|
|
|
if (event.target.result) {
|
|
|
|
defaultValue = event.target.result.defaultValue;
|
|
|
|
} else {
|
|
|
|
defaultValue = null;
|
2013-01-08 03:04:25 -08:00
|
|
|
if (DEBUG) debug("MOZSETTINGS-SET-WARNING: " + name + " is not in the database.\n");
|
2013-01-07 06:03:26 -08:00
|
|
|
}
|
2013-01-08 03:04:25 -08:00
|
|
|
let setReq = store.put({ settingName: name, defaultValue: defaultValue, userValue: value });
|
2013-01-07 06:03:26 -08:00
|
|
|
|
2013-01-08 03:04:25 -08:00
|
|
|
setReq.onsuccess = function() {
|
|
|
|
lock._isBusy = false;
|
2013-01-07 06:03:26 -08:00
|
|
|
lock._open = true;
|
2014-04-23 14:16:24 -07:00
|
|
|
lock.callHandle(callback, name, value);
|
2013-01-07 06:03:26 -08:00
|
|
|
Services.obs.notifyObservers(lock, "mozsettings-changed", JSON.stringify({
|
|
|
|
key: name,
|
|
|
|
value: value,
|
|
|
|
message: message
|
|
|
|
}));
|
|
|
|
lock._open = false;
|
2013-01-08 03:04:25 -08:00
|
|
|
lock.process();
|
2013-01-07 06:03:26 -08:00
|
|
|
};
|
|
|
|
|
2013-01-08 03:04:25 -08:00
|
|
|
setReq.onerror = function(event) {
|
|
|
|
lock._isBusy = false;
|
2014-04-23 14:16:24 -07:00
|
|
|
lock.callError(callback, event.target.errorMessage);
|
2013-01-08 03:04:25 -08:00
|
|
|
lock.process();
|
|
|
|
};
|
2013-01-07 06:03:26 -08:00
|
|
|
}
|
2012-04-27 16:21:31 -07:00
|
|
|
|
2013-01-08 03:04:25 -08:00
|
|
|
checkKeyRequest.onerror = function(event) {
|
|
|
|
lock._isBusy = false;
|
2014-04-23 14:16:24 -07:00
|
|
|
lock.callError(callback, event.target.errorMessage);
|
2013-01-08 03:04:25 -08:00
|
|
|
lock.process();
|
|
|
|
};
|
2012-04-27 16:21:31 -07:00
|
|
|
break;
|
|
|
|
case "get":
|
2013-01-08 03:04:25 -08:00
|
|
|
let getReq = store.mozGetAll(name);
|
|
|
|
getReq.onsuccess = function(event) {
|
|
|
|
if (DEBUG) {
|
|
|
|
debug("Request successful. Record count:" + event.target.result.length);
|
|
|
|
debug("result: " + JSON.stringify(event.target.result));
|
|
|
|
}
|
2012-04-27 16:21:31 -07:00
|
|
|
this._open = true;
|
|
|
|
if (callback) {
|
|
|
|
if (event.target.result[0]) {
|
|
|
|
if (event.target.result.length > 1) {
|
2013-01-08 03:04:25 -08:00
|
|
|
if (DEBUG) debug("Warning: overloaded setting:" + name);
|
2012-04-27 16:21:31 -07:00
|
|
|
}
|
2013-01-07 06:03:26 -08:00
|
|
|
let result = event.target.result[0];
|
|
|
|
let value = result.userValue !== undefined
|
|
|
|
? result.userValue
|
|
|
|
: result.defaultValue;
|
2014-04-23 14:16:24 -07:00
|
|
|
lock.callHandle(callback, name, value);
|
2013-01-08 03:04:25 -08:00
|
|
|
} else {
|
2014-04-23 14:16:24 -07:00
|
|
|
lock.callHandle(callback, name, null);
|
2013-01-08 03:04:25 -08:00
|
|
|
}
|
2012-04-27 16:21:31 -07:00
|
|
|
} else {
|
2013-01-08 03:04:25 -08:00
|
|
|
if (DEBUG) debug("no callback defined!");
|
2012-04-27 16:21:31 -07:00
|
|
|
}
|
|
|
|
this._open = false;
|
|
|
|
}.bind(lock);
|
2014-04-23 14:16:24 -07:00
|
|
|
getReq.onerror = function error(event) {
|
|
|
|
lock.callError(callback, event.target.errorMessage);
|
|
|
|
};
|
2012-04-27 16:21:31 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lock._open = true;
|
|
|
|
},
|
|
|
|
|
2014-05-20 12:19:18 -07:00
|
|
|
createTransactionAndProcess: function() {
|
2012-04-27 16:21:31 -07:00
|
|
|
if (this._settingsService._settingsDB._db) {
|
2013-01-08 03:04:25 -08:00
|
|
|
let lock;
|
2012-04-27 16:21:31 -07:00
|
|
|
while (lock = this._settingsService._locks.dequeue()) {
|
|
|
|
if (!lock._transaction) {
|
|
|
|
lock._transaction = lock._settingsService._settingsDB._db.transaction(SETTINGSSTORE_NAME, "readwrite");
|
2014-05-20 12:19:18 -07:00
|
|
|
if (lock._transactionCallback) {
|
|
|
|
lock._transaction.oncomplete = lock.callTransactionHandle.bind(lock);
|
2014-02-07 03:19:58 -08:00
|
|
|
lock._transaction.onabort = function(event) {
|
|
|
|
let message = '';
|
|
|
|
if (event.target.error) {
|
|
|
|
message = event.target.error.name + ': ' + event.target.error.message;
|
|
|
|
}
|
2014-05-20 12:19:18 -07:00
|
|
|
this.callAbort(lock._transactionCallback.handleAbort, message);
|
2014-02-07 03:19:58 -08:00
|
|
|
};
|
|
|
|
}
|
2012-04-27 16:21:31 -07:00
|
|
|
}
|
2013-01-08 03:04:25 -08:00
|
|
|
if (!lock._isBusy) {
|
|
|
|
lock.process();
|
|
|
|
} else {
|
|
|
|
this._settingsService._locks.enqueue(lock);
|
|
|
|
return;
|
|
|
|
}
|
2012-04-27 16:21:31 -07:00
|
|
|
}
|
2013-01-08 03:04:25 -08:00
|
|
|
if (!this._requests.isEmpty() && !this._isBusy) {
|
2012-04-27 16:21:31 -07:00
|
|
|
this.process();
|
2013-01-08 03:04:25 -08:00
|
|
|
}
|
2012-04-27 16:21:31 -07:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
get: function get(aName, aCallback) {
|
2013-01-08 03:04:25 -08:00
|
|
|
if (DEBUG) debug("get: " + aName + ", " + aCallback);
|
2012-04-27 16:21:31 -07:00
|
|
|
this._requests.enqueue({ callback: aCallback, intent:"get", name: aName });
|
|
|
|
this.createTransactionAndProcess();
|
|
|
|
},
|
|
|
|
|
2012-08-31 00:37:43 -07:00
|
|
|
set: function set(aName, aValue, aCallback, aMessage) {
|
2012-04-27 16:21:31 -07:00
|
|
|
debug("set: " + aName + ": " + JSON.stringify(aValue));
|
2012-08-31 00:37:43 -07:00
|
|
|
if (aMessage === undefined)
|
|
|
|
aMessage = null;
|
|
|
|
this._requests.enqueue({ callback: aCallback,
|
|
|
|
intent: "set",
|
|
|
|
name: aName,
|
2013-08-11 08:41:59 -07:00
|
|
|
value: this._settingsService._settingsDB.prepareValue(aValue),
|
2012-08-31 00:37:43 -07:00
|
|
|
message: aMessage });
|
2012-04-27 16:21:31 -07:00
|
|
|
this.createTransactionAndProcess();
|
|
|
|
},
|
|
|
|
|
|
|
|
classID : SETTINGSSERVICELOCK_CID,
|
2014-03-22 06:56:17 -07:00
|
|
|
QueryInterface : XPCOMUtils.generateQI([nsISettingsServiceLock])
|
2012-04-27 16:21:31 -07:00
|
|
|
};
|
|
|
|
|
2012-09-05 17:33:03 -07:00
|
|
|
const SETTINGSSERVICE_CID = Components.ID("{f656f0c0-f776-11e1-a21f-0800200c9a66}");
|
2012-04-27 16:21:31 -07:00
|
|
|
|
|
|
|
function SettingsService()
|
|
|
|
{
|
|
|
|
debug("settingsService Constructor");
|
|
|
|
this._locks = new Queue();
|
|
|
|
this._settingsDB = new SettingsDB();
|
2013-09-28 04:25:46 -07:00
|
|
|
this._settingsDB.init();
|
2012-04-27 16:21:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
SettingsService.prototype = {
|
|
|
|
|
|
|
|
nextTick: function nextTick(aCallback, thisObj) {
|
|
|
|
if (thisObj)
|
|
|
|
aCallback = aCallback.bind(thisObj);
|
|
|
|
|
|
|
|
Services.tm.currentThread.dispatch(aCallback, Ci.nsIThread.DISPATCH_NORMAL);
|
|
|
|
},
|
|
|
|
|
2014-02-07 03:19:58 -08:00
|
|
|
createLock: function createLock(aCallback) {
|
2014-05-20 12:19:18 -07:00
|
|
|
var lock = new SettingsServiceLock(this, aCallback);
|
2012-04-27 16:21:31 -07:00
|
|
|
this._locks.enqueue(lock);
|
|
|
|
this._settingsDB.ensureDB(
|
2014-05-20 12:19:18 -07:00
|
|
|
function() { lock.createTransactionAndProcess(); },
|
2013-09-28 04:25:46 -07:00
|
|
|
function() { dump("SettingsService failed to open DB!\n"); }
|
|
|
|
);
|
2012-04-27 16:21:31 -07:00
|
|
|
this.nextTick(function() { this._open = false; }, lock);
|
|
|
|
return lock;
|
|
|
|
},
|
|
|
|
|
|
|
|
classID : SETTINGSSERVICE_CID,
|
2014-03-22 06:56:17 -07:00
|
|
|
QueryInterface : XPCOMUtils.generateQI([Ci.nsISettingsService])
|
2012-04-27 16:21:31 -07:00
|
|
|
}
|
|
|
|
|
2012-10-31 09:13:28 -07:00
|
|
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsService, SettingsServiceLock])
|