Change backups to be user data scoped
This commit is contained in:
parent
0024f96a99
commit
e66b270811
|
@ -0,0 +1,9 @@
|
|||
# Looking for setting snapshots or chat backups?
|
||||
|
||||
Individual user backups are now located in the data directory.
|
||||
|
||||
Example for the default user under default data root:
|
||||
|
||||
/data/default-user/backups
|
||||
|
||||
This folder remains for historical purposes only.
|
|
@ -41,6 +41,7 @@ const USER_DIRECTORY_TEMPLATE = Object.freeze({
|
|||
comfyWorkflows: 'user/workflows',
|
||||
files: 'user/files',
|
||||
vectors: 'vectors',
|
||||
backups: 'backups',
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,15 +6,16 @@ const sanitize = require('sanitize-filename');
|
|||
const writeFileAtomicSync = require('write-file-atomic').sync;
|
||||
|
||||
const { jsonParser, urlencodedParser } = require('../express-common');
|
||||
const { PUBLIC_DIRECTORIES, UPLOADS_PATH } = require('../constants');
|
||||
const { UPLOADS_PATH } = require('../constants');
|
||||
const { getConfigValue, humanizedISO8601DateTime, tryParse, generateTimestamp, removeOldBackups } = require('../util');
|
||||
|
||||
/**
|
||||
* Saves a chat to the backups directory.
|
||||
* @param {string} directory The user's backups directory.
|
||||
* @param {string} name The name of the chat.
|
||||
* @param {string} chat The serialized chat to save.
|
||||
*/
|
||||
function backupChat(name, chat) {
|
||||
function backupChat(directory, name, chat) {
|
||||
try {
|
||||
const isBackupDisabled = getConfigValue('disableChatBackup', false);
|
||||
|
||||
|
@ -22,17 +23,13 @@ function backupChat(name, chat) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!fs.existsSync(PUBLIC_DIRECTORIES.backups)) {
|
||||
fs.mkdirSync(PUBLIC_DIRECTORIES.backups);
|
||||
}
|
||||
|
||||
// replace non-alphanumeric characters with underscores
|
||||
name = sanitize(name).replace(/[^a-z0-9]/gi, '_').toLowerCase();
|
||||
|
||||
const backupFile = path.join(PUBLIC_DIRECTORIES.backups, `chat_${name}_${generateTimestamp()}.jsonl`);
|
||||
const backupFile = path.join(directory, `chat_${name}_${generateTimestamp()}.jsonl`);
|
||||
writeFileAtomicSync(backupFile, chat, 'utf-8');
|
||||
|
||||
removeOldBackups(`chat_${name}_`);
|
||||
removeOldBackups(directory, `chat_${name}_`);
|
||||
} catch (err) {
|
||||
console.log(`Could not backup chat for ${name}`, err);
|
||||
}
|
||||
|
@ -151,7 +148,7 @@ router.post('/save', jsonParser, function (request, response) {
|
|||
const fileName = `${sanitize(String(request.body.file_name))}.jsonl`;
|
||||
const filePath = path.join(request.user.directories.chats, directoryName, fileName);
|
||||
writeFileAtomicSync(filePath, jsonlData, 'utf8');
|
||||
backupChat(directoryName, jsonlData);
|
||||
backupChat(request.user.directories.backups, directoryName, jsonlData);
|
||||
return response.send({ result: 'ok' });
|
||||
} catch (error) {
|
||||
response.send(error);
|
||||
|
@ -455,7 +452,7 @@ router.post('/group/save', jsonParser, (request, response) => {
|
|||
let chat_data = request.body.chat;
|
||||
let jsonlData = chat_data.map(JSON.stringify).join('\n');
|
||||
writeFileAtomicSync(pathToFile, jsonlData, 'utf8');
|
||||
backupChat(String(id), jsonlData);
|
||||
backupChat(request.user.directories.backups, String(id), jsonlData);
|
||||
return response.send({ ok: true });
|
||||
});
|
||||
|
||||
|
|
|
@ -110,10 +110,6 @@ function readPresetsFromDirectory(directoryPath, options = {}) {
|
|||
|
||||
async function backupSettings() {
|
||||
try {
|
||||
if (!fs.existsSync(PUBLIC_DIRECTORIES.backups)) {
|
||||
fs.mkdirSync(PUBLIC_DIRECTORIES.backups);
|
||||
}
|
||||
|
||||
const userHandles = await getAllUserHandles();
|
||||
|
||||
for (const handle of userHandles) {
|
||||
|
@ -131,7 +127,7 @@ async function backupSettings() {
|
|||
*/
|
||||
function backupUserSettings(handle) {
|
||||
const userDirectories = getUserDirectories(handle);
|
||||
const backupFile = path.join(PUBLIC_DIRECTORIES.backups, `${getFilePrefix(handle)}${generateTimestamp()}.json`);
|
||||
const backupFile = path.join(userDirectories.backups, `${getFilePrefix(handle)}${generateTimestamp()}.json`);
|
||||
const sourceFile = path.join(userDirectories.root, SETTINGS_FILE);
|
||||
|
||||
if (!fs.existsSync(sourceFile)) {
|
||||
|
@ -139,7 +135,7 @@ function backupUserSettings(handle) {
|
|||
}
|
||||
|
||||
fs.copyFileSync(sourceFile, backupFile);
|
||||
removeOldBackups(`settings_${handle}`);
|
||||
removeOldBackups(userDirectories.backups, `settings_${handle}`);
|
||||
}
|
||||
|
||||
const router = express.Router();
|
||||
|
@ -227,12 +223,12 @@ router.post('/get', jsonParser, (request, response) => {
|
|||
|
||||
router.post('/get-snapshots', jsonParser, async (request, response) => {
|
||||
try {
|
||||
const snapshots = fs.readdirSync(PUBLIC_DIRECTORIES.backups);
|
||||
const snapshots = fs.readdirSync(request.user.directories.backups);
|
||||
const userFilesPattern = getFilePrefix(request.user.profile.handle);
|
||||
const userSnapshots = snapshots.filter(x => x.startsWith(userFilesPattern));
|
||||
|
||||
const result = userSnapshots.map(x => {
|
||||
const stat = fs.statSync(path.join(PUBLIC_DIRECTORIES.backups, x));
|
||||
const stat = fs.statSync(path.join(request.user.directories.backups, x));
|
||||
return { date: stat.ctimeMs, name: x, size: stat.size };
|
||||
});
|
||||
|
||||
|
@ -252,7 +248,7 @@ router.post('/load-snapshot', jsonParser, async (request, response) => {
|
|||
}
|
||||
|
||||
const snapshotName = request.body.name;
|
||||
const snapshotPath = path.join(PUBLIC_DIRECTORIES.backups, snapshotName);
|
||||
const snapshotPath = path.join(request.user.directories.backups, snapshotName);
|
||||
|
||||
if (!fs.existsSync(snapshotPath)) {
|
||||
return response.sendStatus(404);
|
||||
|
@ -286,7 +282,7 @@ router.post('/restore-snapshot', jsonParser, async (request, response) => {
|
|||
}
|
||||
|
||||
const snapshotName = request.body.name;
|
||||
const snapshotPath = path.join(PUBLIC_DIRECTORIES.backups, snapshotName);
|
||||
const snapshotPath = path.join(request.user.directories.backups, snapshotName);
|
||||
|
||||
if (!fs.existsSync(snapshotPath)) {
|
||||
return response.sendStatus(404);
|
||||
|
|
|
@ -87,6 +87,7 @@ const STORAGE_KEYS = {
|
|||
* @property {string} comfyWorkflows - The directory where the ComfyUI workflows are stored
|
||||
* @property {string} files - The directory where the uploaded files are stored
|
||||
* @property {string} vectors - The directory where the vectors are stored
|
||||
* @property {string} backups - The directory where the backups are stored
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
12
src/util.js
12
src/util.js
|
@ -9,8 +9,6 @@ const yaml = require('yaml');
|
|||
const { default: simpleGit } = require('simple-git');
|
||||
const { Readable } = require('stream');
|
||||
|
||||
const { PUBLIC_DIRECTORIES } = require('./constants');
|
||||
|
||||
/**
|
||||
* Parsed config object.
|
||||
*/
|
||||
|
@ -360,14 +358,16 @@ function generateTimestamp() {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {string} prefix
|
||||
* Remove old backups with the given prefix from a specified directory.
|
||||
* @param {string} directory The root directory to remove backups from.
|
||||
* @param {string} prefix File prefix to filter backups by.
|
||||
*/
|
||||
function removeOldBackups(prefix) {
|
||||
function removeOldBackups(directory, prefix) {
|
||||
const MAX_BACKUPS = 50;
|
||||
|
||||
let files = fs.readdirSync(PUBLIC_DIRECTORIES.backups).filter(f => f.startsWith(prefix));
|
||||
let files = fs.readdirSync(directory).filter(f => f.startsWith(prefix));
|
||||
if (files.length > MAX_BACKUPS) {
|
||||
files = files.map(f => path.join(PUBLIC_DIRECTORIES.backups, f));
|
||||
files = files.map(f => path.join(directory, f));
|
||||
files.sort((a, b) => fs.statSync(a).mtimeMs - fs.statSync(b).mtimeMs);
|
||||
|
||||
fs.rmSync(files[0]);
|
||||
|
|
Loading…
Reference in New Issue