Skip to content

Commit

Permalink
Change backups to be user data scoped
Browse files Browse the repository at this point in the history
  • Loading branch information
Cohee1207 committed May 28, 2024
1 parent 0024f96 commit e66b270
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 26 deletions.
9 changes: 9 additions & 0 deletions backups/!README.md
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const USER_DIRECTORY_TEMPLATE = Object.freeze({
comfyWorkflows: 'user/workflows',
files: 'user/files',
vectors: 'vectors',
backups: 'backups',
});

/**
Expand Down
17 changes: 7 additions & 10 deletions src/endpoints/chats.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,30 @@ 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);

if (isBackupDisabled) {
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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 });
});

Expand Down
16 changes: 6 additions & 10 deletions src/endpoints/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -131,15 +127,15 @@ 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)) {
return;
}

fs.copyFileSync(sourceFile, backupFile);
removeOldBackups(`settings_${handle}`);
removeOldBackups(userDirectories.backups, `settings_${handle}`);
}

const router = express.Router();
Expand Down Expand Up @@ -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 };
});

Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/

/**
Expand Down
12 changes: 6 additions & 6 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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]);
Expand Down

0 comments on commit e66b270

Please sign in to comment.