2013-10-02 10:27:07 -07:00
|
|
|
/* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
|
|
|
|
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
|
|
|
/* 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 */
|
|
|
|
|
2013-10-02 10:27:09 -07:00
|
|
|
function debug(s) {
|
|
|
|
// dump('DEBUG DataStoreService: ' + s + '\n');
|
|
|
|
}
|
2013-10-02 10:27:07 -07:00
|
|
|
|
|
|
|
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
|
|
|
|
|
|
|
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
|
|
|
Cu.import('resource://gre/modules/Services.jsm');
|
|
|
|
Cu.import('resource://gre/modules/DataStore.jsm');
|
|
|
|
|
|
|
|
/* DataStoreService */
|
|
|
|
|
|
|
|
const DATASTORESERVICE_CID = Components.ID('{d193d0e2-c677-4a7b-bb0a-19155b470f2e}');
|
|
|
|
|
|
|
|
function DataStoreService() {
|
|
|
|
debug('DataStoreService Constructor');
|
|
|
|
|
|
|
|
let obs = Services.obs;
|
|
|
|
if (!obs) {
|
|
|
|
debug("DataStore Error: observer-service is null!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
obs.addObserver(this, 'webapps-clear-data', false);
|
|
|
|
}
|
|
|
|
|
|
|
|
DataStoreService.prototype = {
|
|
|
|
// Hash of DataStores
|
|
|
|
stores: {},
|
2013-10-02 10:27:14 -07:00
|
|
|
accessStores: {},
|
2013-10-02 10:27:07 -07:00
|
|
|
|
|
|
|
installDataStore: function(aAppId, aName, aOwner, aReadOnly) {
|
2013-10-02 10:27:09 -07:00
|
|
|
debug('installDataStore - appId: ' + aAppId + ', aName: ' +
|
|
|
|
aName + ', aOwner:' + aOwner + ', aReadOnly: ' +
|
|
|
|
aReadOnly);
|
2013-10-02 10:27:07 -07:00
|
|
|
|
|
|
|
if (aName in this.stores && aAppId in this.stores[aName]) {
|
|
|
|
debug('This should not happen');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let store = new DataStore(aAppId, aName, aOwner, aReadOnly);
|
|
|
|
|
|
|
|
if (!(aName in this.stores)) {
|
|
|
|
this.stores[aName] = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
this.stores[aName][aAppId] = store;
|
|
|
|
},
|
|
|
|
|
2013-10-02 10:27:14 -07:00
|
|
|
installAccessDataStore: function(aAppId, aName, aOwner, aReadOnly) {
|
|
|
|
debug('installDataStore - appId: ' + aAppId + ', aName: ' +
|
|
|
|
aName + ', aOwner:' + aOwner + ', aReadOnly: ' +
|
|
|
|
aReadOnly);
|
|
|
|
|
|
|
|
if (aName in this.accessStores && aAppId in this.accessStores[aName]) {
|
|
|
|
debug('This should not happen');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let accessStore = new DataStoreAccess(aAppId, aName, aOwner, aReadOnly);
|
|
|
|
|
|
|
|
if (!(aName in this.accessStores)) {
|
|
|
|
this.accessStores[aName] = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
this.accessStores[aName][aAppId] = accessStore;
|
|
|
|
},
|
|
|
|
|
2013-10-02 10:27:07 -07:00
|
|
|
getDataStores: function(aWindow, aName) {
|
|
|
|
debug('getDataStores - aName: ' + aName);
|
2013-10-02 10:27:14 -07:00
|
|
|
let appId = aWindow.document.nodePrincipal.appId;
|
|
|
|
|
2013-10-02 10:27:07 -07:00
|
|
|
let self = this;
|
|
|
|
return new aWindow.Promise(function(resolve, reject) {
|
2013-10-02 10:27:11 -07:00
|
|
|
let matchingStores = [];
|
2013-10-02 10:27:07 -07:00
|
|
|
|
|
|
|
if (aName in self.stores) {
|
2013-10-02 10:27:14 -07:00
|
|
|
if (appId in self.stores[aName]) {
|
|
|
|
matchingStores.push({ store: self.stores[aName][appId],
|
|
|
|
readonly: false });
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var i in self.stores[aName]) {
|
|
|
|
if (i == appId) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
let access = self.getDataStoreAccess(self.stores[aName][i], appId);
|
|
|
|
if (!access) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
let readOnly = self.stores[aName][i].readOnly || access.readOnly;
|
|
|
|
matchingStores.push({ store: self.stores[aName][i],
|
|
|
|
readonly: readOnly });
|
2013-10-02 10:27:07 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-02 10:27:11 -07:00
|
|
|
let callbackPending = matchingStores.length;
|
|
|
|
let results = [];
|
|
|
|
|
|
|
|
if (!callbackPending) {
|
|
|
|
resolve(results);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let i = 0; i < matchingStores.length; ++i) {
|
2013-10-02 10:27:14 -07:00
|
|
|
let obj = matchingStores[i].store.exposeObject(aWindow,
|
|
|
|
matchingStores[i].readonly);
|
2013-10-02 10:27:11 -07:00
|
|
|
results.push(obj);
|
|
|
|
|
2013-10-02 10:27:14 -07:00
|
|
|
matchingStores[i].store.retrieveRevisionId(
|
2013-10-02 10:27:11 -07:00
|
|
|
function() {
|
|
|
|
--callbackPending;
|
|
|
|
if (!callbackPending) {
|
|
|
|
resolve(results);
|
|
|
|
}
|
|
|
|
},
|
2013-10-02 10:27:15 -07:00
|
|
|
// if the revision is already known, we don't need to retrieve it
|
|
|
|
// again.
|
|
|
|
false
|
2013-10-02 10:27:11 -07:00
|
|
|
);
|
|
|
|
}
|
2013-10-02 10:27:07 -07:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2013-10-02 10:27:14 -07:00
|
|
|
getDataStoreAccess: function(aStore, aAppId) {
|
|
|
|
if (!(aStore.name in this.accessStores) ||
|
|
|
|
!(aAppId in this.accessStores[aStore.name])) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.accessStores[aStore.name][aAppId];
|
|
|
|
},
|
|
|
|
|
2013-10-02 10:27:07 -07:00
|
|
|
observe: function observe(aSubject, aTopic, aData) {
|
|
|
|
debug('getDataStores - aTopic: ' + aTopic);
|
|
|
|
if (aTopic != 'webapps-clear-data') {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let params =
|
|
|
|
aSubject.QueryInterface(Ci.mozIApplicationClearPrivateDataParams);
|
|
|
|
|
|
|
|
// DataStore is explosed to apps, not browser content.
|
|
|
|
if (params.browserOnly) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let key in this.stores) {
|
|
|
|
if (params.appId in this.stores[key]) {
|
2013-10-02 10:27:09 -07:00
|
|
|
this.stores[key][params.appId].delete();
|
2013-10-02 10:27:07 -07:00
|
|
|
delete this.stores[key][params.appId];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.stores[key].length) {
|
|
|
|
delete this.stores[key];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
classID : DATASTORESERVICE_CID,
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataStoreService,
|
|
|
|
Ci.nsIObserver]),
|
|
|
|
classInfo: XPCOMUtils.generateCI({
|
|
|
|
classID: DATASTORESERVICE_CID,
|
|
|
|
contractID: '@mozilla.org/datastore-service;1',
|
|
|
|
interfaces: [Ci.nsIDataStoreService, Ci.nsIObserver],
|
|
|
|
flags: Ci.nsIClassInfo.SINGLETON
|
|
|
|
})
|
|
|
|
};
|
|
|
|
|
|
|
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DataStoreService]);
|