cryptpad/www/common/outer/cache-store.js
ansuz 3965af1992 handle suspected source of errors
atime update on cache entries blocked calendar event creation for me once
seemingly due to an unhandled DOMException triggered by localForage.
This is the only place I expect it could have come from, but the error message wasn't very helpful
so I could be wrong
2021-06-08 16:25:44 +05:30

190 lines
5.9 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

define([
'/common/common-util.js',
'/bower_components/localforage/dist/localforage.min.js',
], function (Util, localForage) {
var S = window.CryptPad_Cache = {};
var onReady = Util.mkEvent(true);
// Check if indexedDB is allowed
var allowed = false;
var disabled = false;
var supported = false;
try {
var request = window.indexedDB.open('test_db', 1);
request.onsuccess = function () {
supported = true;
allowed = supported && !disabled;
onReady.fire();
};
request.onerror = function () {
onReady.fire();
};
} catch (e) {
onReady.fire();
}
S.enable = function () {
disabled = false;
allowed = supported && !disabled;
};
S.disable = function () {
disabled = true;
allowed = supported && !disabled;
};
var cache = localForage.createInstance({
driver: localForage.INDEXEDDB,
name: "cp_cache"
});
S.getBlobCache = function (id, cb) {
cb = Util.once(Util.mkAsync(cb || function () {}));
onReady.reg(function () {
if (!allowed) { return void cb('NOCACHE'); }
cache.getItem(id, function (err, obj) {
if (err || !obj || !obj.c) {
return void cb(Util.serializeError(err || 'EINVAL'));
}
cb(null, obj.c);
obj.t = +new Date();
cache.setItem(id, obj, function (err) {
if (!err) { return; }
console.error(err);
});
});
});
};
S.setBlobCache = function (id, u8, cb) {
cb = Util.once(Util.mkAsync(cb || function () {}));
onReady.reg(function () {
if (!allowed) { return void cb('NOCACHE'); }
if (!u8) { return void cb('EINVAL'); }
cache.setItem(id, {
c: u8,
t: (+new Date()) // 't' represent the "lastAccess" of this cache (get or set)
}, function (err) {
cb(Util.serializeError(err));
});
});
};
// id: channel ID or blob ID
// returns array of messages
S.getChannelCache = function (id, cb) {
cb = Util.once(Util.mkAsync(cb || function () {}));
onReady.reg(function () {
if (!allowed) { return void cb('NOCACHE'); }
cache.getItem(id, function (err, obj) {
if (err || !obj || !Array.isArray(obj.c)) {
return void cb(Util.serializeError(err || 'EINVAL'));
}
cb(null, obj);
obj.t = +new Date();
cache.setItem(id, obj, function (err) {
if (!err) { return; }
console.error(err);
});
});
});
};
// Keep the last two checkpoint + any checkpoint that may exist in the last 100 messages
// FIXME: duplicate system with sliceCpIndex from lib/hk-util.js
var checkCheckpoints = function (array) {
if (!Array.isArray(array)) { return; }
// Keep the last 100 messages
if (array.length > 100) {
array.splice(0, array.length - 100);
}
// Remove every message before the first checkpoint
var firstCpIdx;
array.some(function (el, i) {
if (!el.isCheckpoint) { return; }
firstCpIdx = i;
return true;
});
array.splice(0, firstCpIdx);
};
var t = {};
S.storeCache = function (id, validateKey, val, onError) {
onError = Util.once(Util.mkAsync(onError || function () {}));
onReady.reg(function () {
// Make a throttle or use the existing one to avoid calling
// storeCache with the same array multiple times
t[id] = t[id] || Util.throttle(function (validateKey, val, onError) {
if (!allowed) { return void onError('NOCACHE'); }
if (!Array.isArray(val) || !validateKey) { return void onError('EINVAL'); }
checkCheckpoints(val);
cache.setItem(id, {
k: validateKey,
c: val,
t: (+new Date()) // 't' represent the "lastAccess" of this cache (get or set)
}, function (err) {
if (err) { onError(Util.serializeError(err)); }
});
}, 50);
t[id](validateKey, val, onError);
});
};
S.leaveChannel = function (id) {
delete t[id];
};
S.clearChannel = function (id, cb) {
cb = Util.once(Util.mkAsync(cb || function () {}));
onReady.reg(function () {
if (!allowed) { return void cb('NOCACHE'); }
cache.removeItem(id, function () {
cb();
});
});
};
S.clear = function (cb) {
cb = Util.once(Util.mkAsync(cb || function () {}));
onReady.reg(function () {
if (!allowed) { return void cb('NOCACHE'); }
cache.clear(cb);
});
};
S.getKeys = function (cb) {
cb = Util.once(Util.mkAsync(cb || function () {}));
onReady.reg(function () {
if (!allowed) { return void cb('NOCACHE'); }
cache.keys().then(function (keys) {
cb(null, keys);
}).catch(function (err) {
cb(err);
});
});
};
S.getTime = function (id, cb) {
cb = Util.once(Util.mkAsync(cb || function () {}));
onReady.reg(function () {
if (!allowed) { return void cb('NOCACHE'); }
cache.getItem(id, function (err, obj) {
if (err || !obj || !obj.c) {
return void cb(Util.serializeError(err || 'EINVAL'));
}
cb(null, obj.t);
});
});
};
self.CryptPad_clearIndexedDB = S.clear;
return S;
});