|
@ -85,7 +85,7 @@ vAPI.cacheStorage = (function() { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function genericErrorHandler(error) { |
|
|
function genericErrorHandler(error) { |
|
|
console.error('[uMatrix cacheStorage]', error); |
|
|
|
|
|
|
|
|
console.error('[%s]', STORAGE_NAME, error); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function noopfn() { |
|
|
function noopfn() { |
|
@ -110,20 +110,44 @@ vAPI.cacheStorage = (function() { |
|
|
} |
|
|
} |
|
|
pending.push(callback); |
|
|
pending.push(callback); |
|
|
if ( pending.length !== 1 ) { return; } |
|
|
if ( pending.length !== 1 ) { return; } |
|
|
// This will fail in private browsing mode.
|
|
|
|
|
|
var req = indexedDB.open(STORAGE_NAME, 1); |
|
|
|
|
|
|
|
|
// https://github.com/gorhill/uBlock/issues/3156
|
|
|
|
|
|
// I have observed that no event was fired in Tor Browser 7.0.7 +
|
|
|
|
|
|
// medium security level after the request to open the database was
|
|
|
|
|
|
// created. When this occurs, I have also observed that the `error`
|
|
|
|
|
|
// property was already set, so this means uBO can detect here whether
|
|
|
|
|
|
// the database can be opened successfully. A try-catch block is
|
|
|
|
|
|
// necessary when reading the `error` property because we are not
|
|
|
|
|
|
// allowed to read this propery outside of event handlers in newer
|
|
|
|
|
|
// implementation of IDBRequest (my understanding).
|
|
|
|
|
|
var req; |
|
|
|
|
|
try { |
|
|
|
|
|
req = indexedDB.open(STORAGE_NAME, 1); |
|
|
|
|
|
if ( req.error ) { |
|
|
|
|
|
console.log(req.error); |
|
|
|
|
|
req = undefined; |
|
|
|
|
|
} |
|
|
|
|
|
} catch(ex) { |
|
|
|
|
|
} |
|
|
|
|
|
if ( req === undefined ) { |
|
|
|
|
|
processPendings(); |
|
|
|
|
|
pending = undefined; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
req.onupgradeneeded = function(ev) { |
|
|
req.onupgradeneeded = function(ev) { |
|
|
|
|
|
req = undefined; |
|
|
db = ev.target.result; |
|
|
db = ev.target.result; |
|
|
db.onerror = genericErrorHandler; |
|
|
|
|
|
|
|
|
db.onerror = db.onabort = genericErrorHandler; |
|
|
var table = db.createObjectStore(STORAGE_NAME, { keyPath: 'key' }); |
|
|
var table = db.createObjectStore(STORAGE_NAME, { keyPath: 'key' }); |
|
|
table.createIndex('value', 'value', { unique: false }); |
|
|
table.createIndex('value', 'value', { unique: false }); |
|
|
}; |
|
|
}; |
|
|
req.onsuccess = function(ev) { |
|
|
req.onsuccess = function(ev) { |
|
|
|
|
|
req = undefined; |
|
|
db = ev.target.result; |
|
|
db = ev.target.result; |
|
|
db.onerror = genericErrorHandler; |
|
|
|
|
|
|
|
|
db.onerror = db.onabort = genericErrorHandler; |
|
|
processPendings(); |
|
|
processPendings(); |
|
|
}; |
|
|
}; |
|
|
req.onerror = function() { |
|
|
|
|
|
|
|
|
req.onerror = req.onblocked = function() { |
|
|
|
|
|
req = undefined; |
|
|
console.log(this.error); |
|
|
console.log(this.error); |
|
|
processPendings(); |
|
|
processPendings(); |
|
|
pending = undefined; |
|
|
pending = undefined; |
|
@ -133,64 +157,29 @@ vAPI.cacheStorage = (function() { |
|
|
function getFromDb(keys, store, callback) { |
|
|
function getFromDb(keys, store, callback) { |
|
|
if ( typeof callback !== 'function' ) { return; } |
|
|
if ( typeof callback !== 'function' ) { return; } |
|
|
if ( keys.length === 0 ) { return callback(store); } |
|
|
if ( keys.length === 0 ) { return callback(store); } |
|
|
var notfoundKeys = new Set(keys); |
|
|
|
|
|
var gotOne = function() { |
|
|
var gotOne = function() { |
|
|
if ( typeof this.result === 'object' ) { |
|
|
if ( typeof this.result === 'object' ) { |
|
|
store[this.result.key] = this.result.value; |
|
|
store[this.result.key] = this.result.value; |
|
|
notfoundKeys.delete(this.result.key); |
|
|
|
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
getDb(function(db) { |
|
|
getDb(function(db) { |
|
|
if ( !db ) { return callback(); } |
|
|
if ( !db ) { return callback(); } |
|
|
var transaction = db.transaction(STORAGE_NAME); |
|
|
var transaction = db.transaction(STORAGE_NAME); |
|
|
transaction.oncomplete = transaction.onerror = function() { |
|
|
|
|
|
if ( notfoundKeys.size === 0 ) { |
|
|
|
|
|
|
|
|
transaction.oncomplete = |
|
|
|
|
|
transaction.onerror = |
|
|
|
|
|
transaction.onabort = function() { |
|
|
return callback(store); |
|
|
return callback(store); |
|
|
} |
|
|
|
|
|
maybeMigrate(Array.from(notfoundKeys), store, callback); |
|
|
|
|
|
}; |
|
|
}; |
|
|
var table = transaction.objectStore(STORAGE_NAME); |
|
|
var table = transaction.objectStore(STORAGE_NAME); |
|
|
for ( var key of keys ) { |
|
|
for ( var key of keys ) { |
|
|
var req = table.get(key); |
|
|
var req = table.get(key); |
|
|
req.onsuccess = gotOne; |
|
|
req.onsuccess = gotOne; |
|
|
req.onerror = noopfn; |
|
|
req.onerror = noopfn; |
|
|
|
|
|
req = undefined; |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Migrate from storage API
|
|
|
|
|
|
// TODO: removes once all users are migrated to the new cacheStorage.
|
|
|
|
|
|
function maybeMigrate(keys, store, callback) { |
|
|
|
|
|
var toMigrate = new Set(), |
|
|
|
|
|
i = keys.length; |
|
|
|
|
|
while ( i-- ) { |
|
|
|
|
|
var key = keys[i]; |
|
|
|
|
|
toMigrate.add(key); |
|
|
|
|
|
// If migrating a compiled list, also migrate the non-compiled
|
|
|
|
|
|
// counterpart.
|
|
|
|
|
|
if ( /^cache\/compiled\//.test(key) ) { |
|
|
|
|
|
toMigrate.add(key.replace('/compiled', '')); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
vAPI.storage.get(Array.from(toMigrate), function(bin) { |
|
|
|
|
|
if ( bin instanceof Object === false ) { |
|
|
|
|
|
return callback(store); |
|
|
|
|
|
} |
|
|
|
|
|
var migratedKeys = Object.keys(bin); |
|
|
|
|
|
if ( migratedKeys.length === 0 ) { |
|
|
|
|
|
return callback(store); |
|
|
|
|
|
} |
|
|
|
|
|
var i = migratedKeys.length; |
|
|
|
|
|
while ( i-- ) { |
|
|
|
|
|
var key = migratedKeys[i]; |
|
|
|
|
|
store[key] = bin[key]; |
|
|
|
|
|
} |
|
|
|
|
|
vAPI.storage.remove(migratedKeys); |
|
|
|
|
|
vAPI.cacheStorage.set(bin); |
|
|
|
|
|
callback(store); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function getAllFromDb(callback) { |
|
|
function getAllFromDb(callback) { |
|
|
if ( typeof callback !== 'function' ) { |
|
|
if ( typeof callback !== 'function' ) { |
|
|
callback = noopfn; |
|
|
callback = noopfn; |
|
@ -199,7 +188,9 @@ vAPI.cacheStorage = (function() { |
|
|
if ( !db ) { return callback(); } |
|
|
if ( !db ) { return callback(); } |
|
|
var output = {}; |
|
|
var output = {}; |
|
|
var transaction = db.transaction(STORAGE_NAME); |
|
|
var transaction = db.transaction(STORAGE_NAME); |
|
|
transaction.oncomplete = transaction.onerror = function() { |
|
|
|
|
|
|
|
|
transaction.oncomplete = |
|
|
|
|
|
transaction.onerror = |
|
|
|
|
|
transaction.onabort = function() { |
|
|
callback(output); |
|
|
callback(output); |
|
|
}; |
|
|
}; |
|
|
var table = transaction.objectStore(STORAGE_NAME), |
|
|
var table = transaction.objectStore(STORAGE_NAME), |
|
@ -222,13 +213,16 @@ vAPI.cacheStorage = (function() { |
|
|
getDb(function(db) { |
|
|
getDb(function(db) { |
|
|
if ( !db ) { return callback(); } |
|
|
if ( !db ) { return callback(); } |
|
|
var transaction = db.transaction(STORAGE_NAME, 'readwrite'); |
|
|
var transaction = db.transaction(STORAGE_NAME, 'readwrite'); |
|
|
transaction.oncomplete = transaction.onerror = callback; |
|
|
|
|
|
var table = transaction.objectStore(STORAGE_NAME), |
|
|
|
|
|
entry = {}; |
|
|
|
|
|
|
|
|
transaction.oncomplete = |
|
|
|
|
|
transaction.onerror = |
|
|
|
|
|
transaction.onabort = callback; |
|
|
|
|
|
var table = transaction.objectStore(STORAGE_NAME); |
|
|
for ( var key of keys ) { |
|
|
for ( var key of keys ) { |
|
|
|
|
|
var entry = {}; |
|
|
entry.key = key; |
|
|
entry.key = key; |
|
|
entry.value = input[key]; |
|
|
entry.value = input[key]; |
|
|
table.put(entry); |
|
|
table.put(entry); |
|
|
|
|
|
entry = undefined; |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
@ -242,14 +236,14 @@ vAPI.cacheStorage = (function() { |
|
|
getDb(function(db) { |
|
|
getDb(function(db) { |
|
|
if ( !db ) { return callback(); } |
|
|
if ( !db ) { return callback(); } |
|
|
var transaction = db.transaction(STORAGE_NAME, 'readwrite'); |
|
|
var transaction = db.transaction(STORAGE_NAME, 'readwrite'); |
|
|
transaction.oncomplete = transaction.onerror = callback; |
|
|
|
|
|
|
|
|
transaction.oncomplete = |
|
|
|
|
|
transaction.onerror = |
|
|
|
|
|
transaction.onabort = callback; |
|
|
var table = transaction.objectStore(STORAGE_NAME); |
|
|
var table = transaction.objectStore(STORAGE_NAME); |
|
|
for ( var key of keys ) { |
|
|
for ( var key of keys ) { |
|
|
table.delete(key); |
|
|
table.delete(key); |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
// TODO: removes once all users are migrated to the new cacheStorage.
|
|
|
|
|
|
vAPI.storage.remove(keys); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function clearDb(callback) { |
|
|
function clearDb(callback) { |
|
|