thelounge
Version:
The self-hosted Web IRC client
132 lines (131 loc) • 4.2 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.StorageCleaner = void 0;
const msg_1 = require("./models/msg");
const config_1 = __importDefault(require("./config"));
const log_1 = __importDefault(require("./log"));
const status_types = [
msg_1.MessageType.AWAY,
msg_1.MessageType.BACK,
msg_1.MessageType.INVITE,
msg_1.MessageType.JOIN,
msg_1.MessageType.KICK,
msg_1.MessageType.MODE,
msg_1.MessageType.MODE_CHANNEL,
msg_1.MessageType.MODE_USER,
msg_1.MessageType.NICK,
msg_1.MessageType.PART,
msg_1.MessageType.QUIT,
msg_1.MessageType.CTCP,
msg_1.MessageType.CTCP_REQUEST,
msg_1.MessageType.CHGHOST,
msg_1.MessageType.TOPIC,
msg_1.MessageType.TOPIC_SET_BY,
];
class StorageCleaner {
db;
olderThanDays;
messageTypes;
limit;
ticker;
errCount;
isStopped;
constructor(db) {
this.errCount = 0;
this.isStopped = true;
this.db = db;
this.limit = 200;
const policy = config_1.default.values.storagePolicy;
this.olderThanDays = policy.maxAgeDays;
switch (policy.deletionPolicy) {
case "statusOnly":
this.messageTypes = status_types;
break;
case "everything":
this.messageTypes = null;
break;
default:
// exhaustive switch guard, blows up when user specifies a invalid policy enum
this.messageTypes = assertNoBadPolicy(policy.deletionPolicy);
}
}
genDeletionRequest() {
return {
limit: this.limit,
messageTypes: this.messageTypes,
olderThanDays: this.olderThanDays,
};
}
async runDeletesNoLimit() {
if (!config_1.default.values.storagePolicy.enabled) {
// this is meant to be used by cli tools, so we guard against this
throw new Error("storage policy is disabled");
}
const req = this.genDeletionRequest();
req.limit = -1; // unlimited
const num_deleted = await this.db.deleteMessages(req);
return num_deleted;
}
async runDeletes() {
if (this.isStopped) {
return;
}
if (!this.db.isEnabled) {
// TODO: remove this once the server is intelligent enough to wait for init
this.schedule(30 * 1000);
return;
}
const req = this.genDeletionRequest();
let num_deleted = 0;
try {
num_deleted = await this.db.deleteMessages(req);
this.errCount = 0; // reset when it works
}
catch (err) {
this.errCount++;
log_1.default.error("can't clean messages", err.message);
if (this.errCount === 2) {
log_1.default.error("Cleaning failed too many times, will not retry");
this.stop();
return;
}
}
// need to recheck here as the field may have changed since the await
if (this.isStopped) {
return;
}
if (num_deleted < req.limit) {
this.schedule(5 * 60 * 1000);
}
else {
this.schedule(5000); // give others a chance to execute queries
}
}
schedule(ms) {
const self = this;
this.ticker = setTimeout(() => {
self.runDeletes().catch((err) => {
log_1.default.error("storageCleaner: unexpected failure");
throw err;
});
}, ms);
}
start() {
this.isStopped = false;
this.schedule(0);
}
stop() {
this.isStopped = true;
if (!this.ticker) {
return;
}
clearTimeout(this.ticker);
}
}
exports.StorageCleaner = StorageCleaner;
function assertNoBadPolicy(_) {
throw new Error(`Invalid deletion policy "${config_1.default.values.storagePolicy.deletionPolicy}" in the \`storagePolicy\` object, fix your config.`);
}