More cache eviction tools

This commit is contained in:
yflory 2021-01-18 18:05:01 +01:00
parent a0df168ff4
commit 5ca7247304
9 changed files with 178 additions and 6 deletions

View File

@ -985,6 +985,24 @@ define([
}, {timeout: -1});
};
common.disableCache = function (disabled, cb) {
postMessage("CACHE_DISABLE", disabled, cb);
};
window.addEventListener('storage', function (e) {
if (e.key !== 'CRYPTPAD_STORE|disableCache') { return; }
var o = e.oldValue;
var n = e.newValue;
if (n) {
Cache.disable();
common.disableCache(true, function () {});
} else {
Cache.enable();
common.disableCache(false, function () {});
}
});
if (localStorage['CRYPTPAD_STORE|disableCache']) {
Cache.disable();
}
// Admin
common.adminRpc = function (data, cb) {
@ -2226,6 +2244,7 @@ define([
localToken: tryParsing(localStorage.getItem(Constants.tokenKey)), // TODO move this to LocalStore ?
language: common.getLanguage(),
cache: rdyCfg.cache,
disableCache: localStorage['CRYPTPAD_STORE|disableCache'],
driveEvents: true //rdyCfg.driveEvents // Boolean
};
common.userHash = userHash;

View File

@ -37,6 +37,9 @@ define([
var onReadyEvt = Util.mkEvent(true);
var onCacheReadyEvt = Util.mkEvent(true);
// XXX Number of days before deleting the cache for a channel or blob
var CACHE_MAX_AGE = 90; // DAYS
// Default settings for new users
var NEW_USER_SETTINGS = {
drive: {
@ -334,7 +337,6 @@ define([
if (!s.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
s.rpc.removeOwnedChannel(channel, function (err) {
if (!err) { Cache.clearChannel(channel); }
cb({error:err});
});
};
@ -2861,6 +2863,15 @@ define([
}, PING_INTERVAL);
};
Store.disableCache = function (clientId, disabled, cb) {
if (disabled) {
Cache.disable();
} else {
Cache.enable();
}
cb();
};
/**
* Data:
* - userHash or anonHash
@ -2901,6 +2912,11 @@ define([
});
});
}
if (data.disableCache) {
Cache.disable();
}
initialized = true;
postMessage = function (clientId, cmd, d, cb) {
data.query(clientId, cmd, d, cb);
@ -2920,6 +2936,27 @@ define([
callback(ret);
});
// Clear inactive channels from cache
onReadyEvt.reg(function () {
var inactiveTime = (+new Date()) - CACHE_MAX_AGE * (24 * 3600 * 1000);
Cache.getKeys(function (err, keys) {
if (err) { return void console.error(err); }
var next = function (cb) {
if (!keys.length) { return; }
var key = keys.pop();
var value = Cache.getTime(key, function (err, atime) {
if (err) { return void next(); }
if (!atime || atime < inactiveTime) {
Cache.clearChannel(key, next());
return;
}
next();
});
};
next();
});
});
};
Store.disconnect = function () {

View File

@ -7,10 +7,14 @@ define([
// 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 () {
allowed = true;
supported = true;
allowed = supported && !disabled;
onReady.fire();
};
request.onerror = function () {
@ -20,6 +24,15 @@ define([
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"
@ -141,6 +154,30 @@ define([
});
};
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;

View File

@ -14,6 +14,7 @@ define([
CREATE_README: Store.createReadme,
MIGRATE_ANON_DRIVE: Store.migrateAnonDrive,
PING: function (cId, data, cb) { cb(); },
CACHE_DISABLE: Store.disableCache,
// RPC
UPDATE_PIN_LIMIT: Store.updatePinLimit,
GET_PIN_LIMIT: Store.getPinLimit,

View File

@ -76,9 +76,15 @@ define([
};
// Fire an event. channel.event('EV_SOMETHING', { args: "whatever" });
var event = chan.event = function (e, content) {
var event = chan.event = function (e, content, opts) {
opts = opts || {};
evReady.reg(function () {
postMsg(JSON.stringify({ content: content, q: e }));
var toSend = {
content: content,
q: e,
raw: opts.raw
};
postMsg(opts.raw ? toSend : JSON.stringify(toSend));
});
};

View File

@ -1,6 +1,6 @@
(function () {
var factory = function (Util, Rpc) {
var create = function (network, proxy, _cb) {
var create = function (network, proxy, _cb, Cache) {
if (typeof(_cb) !== 'function') { throw new Error("Expected callback"); }
var cb = Util.once(Util.mkAsync(_cb));
@ -155,6 +155,9 @@ var factory = function (Util, Rpc) {
if (e) { return void cb(e); }
if (response && response.length && response[0] === "OK") {
cb();
if (Cache && Cache.clearChannel) {
Cache.clearChannel(channel);
}
} else {
cb('INVALID_RESPONSE');
}

View File

@ -1476,6 +1476,21 @@ define([
});
});
sframeChan.on('Q_CACHE_DISABLE', function (data, cb) {
if (data.disabled) {
Utils.Cache.clear(function () {
Utils.Cache.disable();
});
Cryptpad.disableCache(true, cb);
return;
}
Utils.Cache.enable();
Cryptpad.disableCache(false, cb);
});
sframeChan.on('Q_CLEAR_CACHE', function (data, cb) {
Utils.Cache.clear(cb);
});
sframeChan.on('Q_PIN_GET_USAGE', function (teamId, cb) {
Cryptpad.isOverPinLimit(teamId, function (err, overLimit, data) {
cb({

View File

@ -758,7 +758,7 @@ define([
window.cryptpadStore._put(k, v, cb);
var x = {};
x[k] = v;
ctx.sframeChan.event('EV_LOCALSTORE_PUT', x);
ctx.sframeChan.event('EV_LOCALSTORE_PUT', x, {raw:true});
};
});

View File

@ -60,6 +60,7 @@ define([
'cp-settings-autostore',
'cp-settings-safe-links',
'cp-settings-userfeedback',
'cp-settings-cache',
],
'drive': [
'cp-settings-resettips',
@ -359,6 +360,59 @@ define([
return $div;
};
// XXX
Messages.settings_cacheTitle = "Cache";
Messages.settings_cacheHint = "CryptPad stores parts of your documents in your browser's memory in order to save network usage and improve loading times. The documents stored in cache can then be loaded faster the next time you visit them. You can disable the cache if your device doesn't have a lot of free storage space. For security reasons, the cache is always cleared when you log out, but you can clear it manually if you want to reclaim storage space on your machine.";
Messages.settings_cacheCheckbox = "Enable cache on this device";
Messages.settings_cacheButton = "Clear existing cache";
makeBlock('cache', function (cb, $div) {
var store = window.cryptpadStore;
var $cbox = $(UI.createCheckbox('cp-settings-cache',
Messages.settings_cacheCheckbox,
false, { label: { class: 'noTitle' } }));
var spinner = UI.makeSpinner($cbox);
// Checkbox: "Enable safe links"
var $checkbox = $cbox.find('input').on('change', function() {
spinner.spin();
var val = !$checkbox.is(':checked') ? '1' : undefined;
store.put('disableCache', val, function () {
sframeChan.query('Q_CACHE_DISABLE', {
disabled: Boolean(val)
}, function () {
spinner.done();
});
});
});
store.get('disableCache', function (val) {
if (!val) {
$checkbox.attr('checked', 'checked');
}
});
var button = h('button.btn.btn-danger', [
h('i.fa.fa-trash-o'),
h('span', Messages.settings_cacheButton)
]);
var buttonContainer = h('div.cp-settings-clear-cache', button);
var spinner2 = UI.makeSpinner($(buttonContainer));
UI.confirmButton(button, {
classes: 'btn-danger'
}, function () {
spinner.spin();
sframeChan.query('Q_CLEAR_CACHE', null, function() {
spinner.done();
});
});
cb([
$cbox[0],
buttonContainer
]);
}, true);
create['delete'] = function() {
if (!common.isLoggedIn()) { return; }
var $div = $('<div>', { 'class': 'cp-settings-delete cp-sidebarlayout-element' });