dom/settings/SettingsService.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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])

mercurial