cryptpad/www/common/outer/cache-store.js

191 lines
6 KiB
JavaScript
Raw Normal View History

2020-11-03 09:49:13 +00:00
define([
2020-11-05 15:19:05 +00:00
'/common/common-util.js',
2020-11-03 09:49:13 +00:00
'/bower_components/localforage/dist/localforage.min.js',
2020-11-05 15:19:05 +00:00
], function (Util, localForage) {
var S = window.CryptPad_Cache = {};
var onReady = Util.mkEvent(true);
// Check if indexedDB is allowed
var allowed = false;
2021-01-18 17:05:01 +00:00
var disabled = false;
var supported = false;
try {
2020-12-10 12:03:22 +00:00
var request = window.indexedDB.open('test_db', 1);
request.onsuccess = function () {
2021-01-18 17:05:01 +00:00
supported = true;
allowed = supported && !disabled;
onReady.fire();
};
request.onerror = function () {
onReady.fire();
};
} catch (e) {
onReady.fire();
}
2020-11-03 09:49:13 +00:00
2021-01-18 17:05:01 +00:00
S.enable = function () {
disabled = false;
allowed = supported && !disabled;
};
S.disable = function () {
disabled = true;
allowed = supported && !disabled;
};
2020-11-03 09:49:13 +00:00
var cache = localForage.createInstance({
driver: localForage.INDEXEDDB,
2020-11-03 09:49:13 +00:00
name: "cp_cache"
});
2020-11-06 14:30:56 +00:00
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);
});
});
2020-11-06 14:30:56 +00:00
});
};
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));
});
2020-11-06 14:30:56 +00:00
});
};
2020-11-03 09:49:13 +00:00
// id: channel ID or blob ID
// returns array of messages
S.getChannelCache = function (id, cb) {
2020-11-05 15:19:05 +00:00
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);
});
});
2020-11-03 09:49:13 +00:00
});
};
2020-11-05 15:19:05 +00:00
// 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
2020-11-03 09:49:13 +00:00
var checkCheckpoints = function (array) {
if (!Array.isArray(array)) { return; }
2020-11-05 15:19:05 +00:00
// Keep the last 100 messages
2021-08-18 09:37:19 +00:00
if (array.length > 100) { // FIXME this behaviour is only valid for chainpad-style documents
2020-11-05 15:19:05 +00:00
array.splice(0, array.length - 100);
2020-11-03 09:49:13 +00:00
}
2020-11-05 15:19:05 +00:00
// 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);
2020-11-03 09:49:13 +00:00
};
2020-12-14 10:52:24 +00:00
var t = {};
S.storeCache = function (id, validateKey, val, onError) {
onError = Util.once(Util.mkAsync(onError || function () {}));
2020-12-14 10:05:39 +00:00
onReady.reg(function () {
2020-12-14 10:52:24 +00:00
// 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)); }
2020-12-14 10:52:24 +00:00
});
}, 50);
t[id](validateKey, val, onError);
2020-11-03 09:49:13 +00:00
});
};
2020-12-14 11:06:18 +00:00
S.leaveChannel = function (id) {
delete t[id];
};
2020-11-24 15:49:12 +00:00
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();
});
});
2020-11-03 09:49:13 +00:00
};
2020-11-27 16:19:03 +00:00
S.clear = function (cb) {
cb = Util.once(Util.mkAsync(cb || function () {}));
onReady.reg(function () {
if (!allowed) { return void cb('NOCACHE'); }
cache.clear(cb);
});
2020-11-03 09:49:13 +00:00
};
2021-01-18 17:05:01 +00:00
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);
});
});
};
2020-12-01 17:18:16 +00:00
self.CryptPad_clearIndexedDB = S.clear;
2020-11-03 09:49:13 +00:00
return S;
});