Throttle chat backups (#2865) * Throttle chat backups * Throttle chat backups and apply backup interval throttling - Added a new configuration option `chatBackupThrottleInterval` to the `config.yaml` file to specify the interval in milliseconds to throttle chat backups per user. - Updated the `getBackupFunction` function in `chats.js` to use the `chatBackupThrottleInterval` value from the configuration file when creating a throttled backup function.

1366c2741d35aaaa4680425b8c8775c381edfba4

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
2 files changed, +26 -2Ignore whitespace
default/config.yaml+2 -0
@@ -83,6 +83,8 @@ skipContentCheck: false
8383disableChatBackup: false
8484# Number of backups to keep for each chat and settings file
8585numberOfBackups: 50
86+# Interval in milliseconds to throttle chat backups per user
87+chatBackupThrottleInterval: 10000
8688# Allowed hosts for card downloads
8789whitelistImportDomains:
8890 - localhost
src/endpoints/chats.js+24 -2
@@ -4,6 +4,7 @@ const readline = require('readline');
44const express = require('express');
55const sanitize = require('sanitize-filename');
66const writeFileAtomicSync = require('write-file-atomic').sync;
7+const _ = require('lodash');
78
89const { jsonParser, urlencodedParser } = require('../express-common');
910const { getConfigValue, humanizedISO8601DateTime, tryParse, generateTimestamp, removeOldBackups } = require('../util');
@@ -34,6 +35,27 @@ function backupChat(directory, name, chat) {
3435 }
3536}
3637
38+const backupFunctions = new Map();
39+
40+/**
41+ * Gets a backup function for a user.
42+ * @param {string} handle User handle
43+ * @returns {function(string, string, string): void} Backup function
44+ */
45+function getBackupFunction(handle) {
46+ const throttleInterval = getConfigValue('chatBackupThrottleInterval', 10_000);
47+ if (!backupFunctions.has(handle)) {
48+ backupFunctions.set(handle, _.throttle(backupChat, throttleInterval, { leading: true, trailing: true }));
49+ }
50+ return backupFunctions.get(handle);
51+}
52+
53+process.on('exit', () => {
54+ for (const func of backupFunctions.values()) {
55+ func.flush();
56+ }
57+});
58+
3759/**
3860 * Imports a chat from Ooba's format.
3961 * @param {string} userName User name
@@ -147,7 +169,7 @@ router.post('/save', jsonParser, function (request, response) {
147169 const fileName = `${String(request.body.file_name)}.jsonl`;
148170 const filePath = path.join(request.user.directories.chats, directoryName, sanitize(fileName));
149171 writeFileAtomicSync(filePath, jsonlData, 'utf8');
150172 backupChatgetBackupFunction(request.user.profile.handle)(request.user.directories.backups, directoryName, jsonlData);
151173 return response.send({ result: 'ok' });
152174 } catch (error) {
153175 response.send(error);
@@ -446,7 +468,7 @@ router.post('/group/save', jsonParser, (request, response) => {
446468 let chat_data = request.body.chat;
447469 let jsonlData = chat_data.map(JSON.stringify).join('\n');
448470 writeFileAtomicSync(pathToFile, jsonlData, 'utf8');
449471 backupChatgetBackupFunction(request.user.profile.handle)(request.user.directories.backups, String(id), jsonlData);
450472 return response.send({ ok: true });
451473});
452474