Merge pull request #3158 from SillyTavern/max-total-chat-backups Add maxTotalChatBackups config.yaml value
Signed| @@ -98,6 +98,8 @@ skipContentCheck: false | ||
| 98 | 98 | disableChatBackup: false |
| 99 | 99 | # Number of backups to keep for each chat and settings file |
| 100 | 100 | numberOfBackups: 50 |
| 101 | +# Maximum number of chat backups to keep per user (starting from the most recent). Set to -1 to keep all backups. | |
| 102 | +maxTotalChatBackups: -1 | |
| 101 | 103 | # Interval in milliseconds to throttle chat backups per user |
| 102 | 104 | chatBackupThrottleInterval: 10000 |
| 103 | 105 | # Allowed hosts for card downloads |
| @@ -11,6 +11,10 @@ import _ from 'lodash'; | ||
| 11 | 11 | import { jsonParser, urlencodedParser } from '../express-common.js'; |
| 12 | 12 | import { getConfigValue, humanizedISO8601DateTime, tryParse, generateTimestamp, removeOldBackups } from '../util.js'; |
| 13 | 13 | |
| 14 | +const isBackupDisabled = getConfigValue('disableChatBackup', false); | |
| 15 | +const maxTotalChatBackups = Number(getConfigValue('maxTotalChatBackups', -1)); | |
| 16 | +const throttleInterval = getConfigValue('chatBackupThrottleInterval', 10_000); | |
| 17 | + | |
| 14 | 18 | /** |
| 15 | 19 | * Saves a chat to the backups directory. |
| 16 | 20 | * @param {string} directory The user's backups directory. |
| @@ -19,7 +23,6 @@ import { getConfigValue, humanizedISO8601DateTime, tryParse, generateTimestamp, | ||
| 19 | 23 | */ |
| 20 | 24 | function backupChat(directory, name, chat) { |
| 21 | 25 | try { |
| 22 | - const isBackupDisabled = getConfigValue('disableChatBackup', false); | |
| 23 | 26 | |
| 24 | 27 | if (isBackupDisabled) { |
| 25 | 28 | return; |
| @@ -32,6 +35,12 @@ function backupChat(directory, name, chat) { | ||
| 32 | 35 | writeFileAtomicSync(backupFile, chat, 'utf-8'); |
| 33 | 36 | |
| 34 | 37 | removeOldBackups(directory, `chat_${name}_`); |
| 38 | + | |
| 39 | + if (isNaN(maxTotalChatBackups) || maxTotalChatBackups < 0) { | |
| 40 | + return; | |
| 41 | + } | |
| 42 | + | |
| 43 | + removeOldBackups(directory, 'chat_', maxTotalChatBackups); | |
| 35 | 44 | } catch (err) { |
| 36 | 45 | console.log(`Could not backup chat for ${name}`, err); |
| 37 | 46 | } |
| @@ -45,7 +54,6 @@ const backupFunctions = new Map(); | ||
| 45 | 54 | * @returns {function(string, string, string): void} Backup function |
| 46 | 55 | */ |
| 47 | 56 | function getBackupFunction(handle) { |
| 48 | - const throttleInterval = getConfigValue('chatBackupThrottleInterval', 10_000); | |
| 49 | 57 | if (!backupFunctions.has(handle)) { |
| 50 | 58 | backupFunctions.set(handle, _.throttle(backupChat, throttleInterval, { leading: true, trailing: true })); |
| 51 | 59 | } |
| @@ -376,16 +376,24 @@ export function generateTimestamp() { | ||
| 376 | 376 | * Remove old backups with the given prefix from a specified directory. |
| 377 | 377 | * @param {string} directory The root directory to remove backups from. |
| 378 | 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 | */ |
| 380 | 381 | export function removeOldBackups(directory, prefix, limit = null) { |
| 381 | 382 | const MAX_BACKUPS = limit ?? Number(getConfigValue('numberOfBackups', 50)); |
| 382 | 383 | |
| 383 | 384 | let files = fs.readdirSync(directory).filter(f => f.startsWith(prefix)); |
| 384 | 385 | if (files.length > MAX_BACKUPS) { |
| 385 | 386 | files = files.map(f => path.join(directory, f)); |
| 386 | 387 | files.sort((a, b) => fs.statSync(a).mtimeMs - fs.statSync(b).mtimeMs); |
| 387 | 388 | |
| 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 | } |
| 391 | 399 | |