Merge pull request #3158 from SillyTavern/max-total-chat-backups Add maxTotalChatBackups config.yaml value

c05265d1a1c4a7b777d4a2ccd7b3e6f23426eced

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

Signed
3 files changed, +23 -5Showing whitespace changes
default/config.yaml+2 -0
@@ -98,6 +98,8 @@ skipContentCheck: false
98disableChatBackup: false98disableChatBackup: false
99# Number of backups to keep for each chat and settings file99# Number of backups to keep for each chat and settings file
100numberOfBackups: 50100numberOfBackups: 50
101# Maximum number of chat backups to keep per user (starting from the most recent). Set to -1 to keep all backups.
102maxTotalChatBackups: -1
101# Interval in milliseconds to throttle chat backups per user103# Interval in milliseconds to throttle chat backups per user
102chatBackupThrottleInterval: 10000104chatBackupThrottleInterval: 10000
103# Allowed hosts for card downloads105# Allowed hosts for card downloads
src/endpoints/chats.js+10 -2
@@ -11,6 +11,10 @@ import _ from 'lodash';
11import { jsonParser, urlencodedParser } from '../express-common.js';11import { jsonParser, urlencodedParser } from '../express-common.js';
12import { getConfigValue, humanizedISO8601DateTime, tryParse, generateTimestamp, removeOldBackups } from '../util.js';12import { getConfigValue, humanizedISO8601DateTime, tryParse, generateTimestamp, removeOldBackups } from '../util.js';
1313
14const isBackupDisabled = getConfigValue('disableChatBackup', false);
15const maxTotalChatBackups = Number(getConfigValue('maxTotalChatBackups', -1));
16const throttleInterval = getConfigValue('chatBackupThrottleInterval', 10_000);
17
14/**18/**
15 * Saves a chat to the backups directory.19 * Saves a chat to the backups directory.
16 * @param {string} directory The user's backups directory.20 * @param {string} directory The user's backups directory.
@@ -19,7 +23,6 @@ import { getConfigValue, humanizedISO8601DateTime, tryParse, generateTimestamp,
19 */23 */
20function backupChat(directory, name, chat) {24function backupChat(directory, name, chat) {
21 try {25 try {
22 const isBackupDisabled = getConfigValue('disableChatBackup', false);
2326
24 if (isBackupDisabled) {27 if (isBackupDisabled) {
25 return;28 return;
@@ -32,6 +35,12 @@ function backupChat(directory, name, chat) {
32 writeFileAtomicSync(backupFile, chat, 'utf-8');35 writeFileAtomicSync(backupFile, chat, 'utf-8');
3336
34 removeOldBackups(directory, `chat_${name}_`);37 removeOldBackups(directory, `chat_${name}_`);
38
39 if (isNaN(maxTotalChatBackups) || maxTotalChatBackups < 0) {
40 return;
41 }
42
43 removeOldBackups(directory, 'chat_', maxTotalChatBackups);
35 } catch (err) {44 } catch (err) {
36 console.log(`Could not backup chat for ${name}`, err);45 console.log(`Could not backup chat for ${name}`, err);
37 }46 }
@@ -45,7 +54,6 @@ const backupFunctions = new Map();
45 * @returns {function(string, string, string): void} Backup function54 * @returns {function(string, string, string): void} Backup function
46 */55 */
47function getBackupFunction(handle) {56function getBackupFunction(handle) {
48 const throttleInterval = getConfigValue('chatBackupThrottleInterval', 10_000);
49 if (!backupFunctions.has(handle)) {57 if (!backupFunctions.has(handle)) {
50 backupFunctions.set(handle, _.throttle(backupChat, throttleInterval, { leading: true, trailing: true }));58 backupFunctions.set(handle, _.throttle(backupChat, throttleInterval, { leading: true, trailing: true }));
51 }59 }
src/util.js+11 -3
@@ -376,16 +376,24 @@ export function generateTimestamp() {
376 * Remove old backups with the given prefix from a specified directory.376 * Remove old backups with the given prefix from a specified directory.
377 * @param {string} directory The root directory to remove backups from.377 * @param {string} directory The root directory to remove backups from.
378 * @param {string} prefix File prefix to filter backups by.378 * @param {string} prefix File prefix to filter backups by.
379 * @param {number?} limit Maximum number of backups to keep. If null, the limit is determined by the `numberOfBackups` config value.
379 */380 */
380export function removeOldBackups(directory, prefix) {381export function removeOldBackups(directory, prefix, limit = null) {
381 const MAX_BACKUPS = Number(getConfigValue('numberOfBackups', 50));382 const MAX_BACKUPS = limit ?? Number(getConfigValue('numberOfBackups', 50));
382383
383 let files = fs.readdirSync(directory).filter(f => f.startsWith(prefix));384 let files = fs.readdirSync(directory).filter(f => f.startsWith(prefix));
384 if (files.length > MAX_BACKUPS) {385 if (files.length > MAX_BACKUPS) {
385 files = files.map(f => path.join(directory, f));386 files = files.map(f => path.join(directory, f));
386 files.sort((a, b) => fs.statSync(a).mtimeMs - fs.statSync(b).mtimeMs);387 files.sort((a, b) => fs.statSync(a).mtimeMs - fs.statSync(b).mtimeMs);
387388
388 fs.rmSync(files[0]);389 while (files.length > MAX_BACKUPS) {
390 const oldest = files.shift();
391 if (!oldest) {
392 break;
393 }
394
395 fs.rmSync(oldest);
396 }
389 }397 }
390}398}
391399