Move settings endpoints to their own module
This commit is contained in:
parent
769cc0a78f
commit
d935b2a132
158
server.js
158
server.js
|
@ -43,7 +43,6 @@ util.inspect.defaultOptions.maxStringLength = null;
|
||||||
const basicAuthMiddleware = require('./src/middleware/basicAuthMiddleware');
|
const basicAuthMiddleware = require('./src/middleware/basicAuthMiddleware');
|
||||||
const { jsonParser, urlencodedParser } = require('./src/express-common.js');
|
const { jsonParser, urlencodedParser } = require('./src/express-common.js');
|
||||||
const contentManager = require('./src/endpoints/content-manager');
|
const contentManager = require('./src/endpoints/content-manager');
|
||||||
const { migrateSecrets } = require('./src/endpoints/secrets');
|
|
||||||
const {
|
const {
|
||||||
getVersion,
|
getVersion,
|
||||||
getConfigValue,
|
getConfigValue,
|
||||||
|
@ -51,8 +50,6 @@ const {
|
||||||
tryParse,
|
tryParse,
|
||||||
clientRelativePath,
|
clientRelativePath,
|
||||||
removeFileExtension,
|
removeFileExtension,
|
||||||
generateTimestamp,
|
|
||||||
removeOldBackups,
|
|
||||||
getImages,
|
getImages,
|
||||||
forwardFetchResponse,
|
forwardFetchResponse,
|
||||||
} = require('./src/util');
|
} = require('./src/util');
|
||||||
|
@ -122,10 +119,8 @@ if (fs.existsSync(whitelistPath)) {
|
||||||
|
|
||||||
const whitelistMode = getConfigValue('whitelistMode', true);
|
const whitelistMode = getConfigValue('whitelistMode', true);
|
||||||
const autorun = (getConfigValue('autorun', false) || cliArguments.autorun) && !cliArguments.ssl;
|
const autorun = (getConfigValue('autorun', false) || cliArguments.autorun) && !cliArguments.ssl;
|
||||||
const enableExtensions = getConfigValue('enableExtensions', true);
|
|
||||||
const listen = getConfigValue('listen', false);
|
const listen = getConfigValue('listen', false);
|
||||||
|
|
||||||
const SETTINGS_FILE = './public/settings.json';
|
|
||||||
const { DIRECTORIES, UPLOADS_PATH, AVATAR_WIDTH, AVATAR_HEIGHT } = require('./src/constants');
|
const { DIRECTORIES, UPLOADS_PATH, AVATAR_WIDTH, AVATAR_HEIGHT } = require('./src/constants');
|
||||||
|
|
||||||
// CORS Settings //
|
// CORS Settings //
|
||||||
|
@ -331,135 +326,6 @@ app.post('/deleteuseravatar', jsonParser, function (request, response) {
|
||||||
return response.sendStatus(404);
|
return response.sendStatus(404);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
app.post('/api/settings/save', jsonParser, function (request, response) {
|
|
||||||
try {
|
|
||||||
writeFileAtomicSync('public/settings.json', JSON.stringify(request.body, null, 4), 'utf8');
|
|
||||||
response.send({ result: 'ok' });
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
response.send(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function readAndParseFromDirectory(directoryPath, fileExtension = '.json') {
|
|
||||||
const files = fs
|
|
||||||
.readdirSync(directoryPath)
|
|
||||||
.filter(x => path.parse(x).ext == fileExtension)
|
|
||||||
.sort();
|
|
||||||
|
|
||||||
const parsedFiles = [];
|
|
||||||
|
|
||||||
files.forEach(item => {
|
|
||||||
try {
|
|
||||||
const file = fs.readFileSync(path.join(directoryPath, item), 'utf-8');
|
|
||||||
parsedFiles.push(fileExtension == '.json' ? JSON.parse(file) : file);
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
// skip
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return parsedFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sortByName(_) {
|
|
||||||
return (a, b) => a.localeCompare(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
function readPresetsFromDirectory(directoryPath, options = {}) {
|
|
||||||
const {
|
|
||||||
sortFunction,
|
|
||||||
removeFileExtension = false,
|
|
||||||
fileExtension = '.json',
|
|
||||||
} = options;
|
|
||||||
|
|
||||||
const files = fs.readdirSync(directoryPath).sort(sortFunction).filter(x => path.parse(x).ext == fileExtension);
|
|
||||||
const fileContents = [];
|
|
||||||
const fileNames = [];
|
|
||||||
|
|
||||||
files.forEach(item => {
|
|
||||||
try {
|
|
||||||
const file = fs.readFileSync(path.join(directoryPath, item), 'utf8');
|
|
||||||
JSON.parse(file);
|
|
||||||
fileContents.push(file);
|
|
||||||
fileNames.push(removeFileExtension ? item.replace(/\.[^/.]+$/, '') : item);
|
|
||||||
} catch {
|
|
||||||
// skip
|
|
||||||
console.log(`${item} is not a valid JSON`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return { fileContents, fileNames };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wintermute's code
|
|
||||||
app.post('/api/settings/get', jsonParser, (request, response) => {
|
|
||||||
let settings;
|
|
||||||
try {
|
|
||||||
settings = fs.readFileSync('public/settings.json', 'utf8');
|
|
||||||
} catch (e) {
|
|
||||||
return response.sendStatus(500);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NovelAI Settings
|
|
||||||
const { fileContents: novelai_settings, fileNames: novelai_setting_names }
|
|
||||||
= readPresetsFromDirectory(DIRECTORIES.novelAI_Settings, {
|
|
||||||
sortFunction: sortByName(DIRECTORIES.novelAI_Settings),
|
|
||||||
removeFileExtension: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
// OpenAI Settings
|
|
||||||
const { fileContents: openai_settings, fileNames: openai_setting_names }
|
|
||||||
= readPresetsFromDirectory(DIRECTORIES.openAI_Settings, {
|
|
||||||
sortFunction: sortByName(DIRECTORIES.openAI_Settings), removeFileExtension: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
// TextGenerationWebUI Settings
|
|
||||||
const { fileContents: textgenerationwebui_presets, fileNames: textgenerationwebui_preset_names }
|
|
||||||
= readPresetsFromDirectory(DIRECTORIES.textGen_Settings, {
|
|
||||||
sortFunction: sortByName(DIRECTORIES.textGen_Settings), removeFileExtension: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
//Kobold
|
|
||||||
const { fileContents: koboldai_settings, fileNames: koboldai_setting_names }
|
|
||||||
= readPresetsFromDirectory(DIRECTORIES.koboldAI_Settings, {
|
|
||||||
sortFunction: sortByName(DIRECTORIES.koboldAI_Settings), removeFileExtension: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const worldFiles = fs
|
|
||||||
.readdirSync(DIRECTORIES.worlds)
|
|
||||||
.filter(file => path.extname(file).toLowerCase() === '.json')
|
|
||||||
.sort((a, b) => a.localeCompare(b));
|
|
||||||
const world_names = worldFiles.map(item => path.parse(item).name);
|
|
||||||
|
|
||||||
const themes = readAndParseFromDirectory(DIRECTORIES.themes);
|
|
||||||
const movingUIPresets = readAndParseFromDirectory(DIRECTORIES.movingUI);
|
|
||||||
const quickReplyPresets = readAndParseFromDirectory(DIRECTORIES.quickreplies);
|
|
||||||
|
|
||||||
const instruct = readAndParseFromDirectory(DIRECTORIES.instruct);
|
|
||||||
const context = readAndParseFromDirectory(DIRECTORIES.context);
|
|
||||||
|
|
||||||
response.send({
|
|
||||||
settings,
|
|
||||||
koboldai_settings,
|
|
||||||
koboldai_setting_names,
|
|
||||||
world_names,
|
|
||||||
novelai_settings,
|
|
||||||
novelai_setting_names,
|
|
||||||
openai_settings,
|
|
||||||
openai_setting_names,
|
|
||||||
textgenerationwebui_presets,
|
|
||||||
textgenerationwebui_preset_names,
|
|
||||||
themes,
|
|
||||||
movingUIPresets,
|
|
||||||
quickReplyPresets,
|
|
||||||
instruct,
|
|
||||||
context,
|
|
||||||
enable_extensions: enableExtensions,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/savetheme', jsonParser, (request, response) => {
|
app.post('/savetheme', jsonParser, (request, response) => {
|
||||||
if (!request.body || !request.body.name) {
|
if (!request.body || !request.body.name) {
|
||||||
return response.sendStatus(400);
|
return response.sendStatus(400);
|
||||||
|
@ -741,6 +607,10 @@ app.use('/api/sprites', require('./src/endpoints/sprites').router);
|
||||||
// Custom content management
|
// Custom content management
|
||||||
app.use('/api/content', require('./src/endpoints/content-manager').router);
|
app.use('/api/content', require('./src/endpoints/content-manager').router);
|
||||||
|
|
||||||
|
// Settings load/store
|
||||||
|
const settingsEndpoint = require('./src/endpoints/settings');
|
||||||
|
app.use('/api/settings', settingsEndpoint.router);
|
||||||
|
|
||||||
// Stable Diffusion generation
|
// Stable Diffusion generation
|
||||||
app.use('/api/sd', require('./src/endpoints/stable-diffusion').router);
|
app.use('/api/sd', require('./src/endpoints/stable-diffusion').router);
|
||||||
|
|
||||||
|
@ -793,8 +663,9 @@ const setupTasks = async function () {
|
||||||
|
|
||||||
console.log(`SillyTavern ${version.pkgVersion}` + (version.gitBranch ? ` '${version.gitBranch}' (${version.gitRevision})` : ''));
|
console.log(`SillyTavern ${version.pkgVersion}` + (version.gitBranch ? ` '${version.gitBranch}' (${version.gitRevision})` : ''));
|
||||||
|
|
||||||
backupSettings();
|
// TODO: do endpoint init functions depend on certain directories existing or not existing? They should be callable
|
||||||
migrateSecrets(SETTINGS_FILE);
|
// in any order for encapsulation reasons, but right now it's unknown if that would break anything.
|
||||||
|
await settingsEndpoint.init();
|
||||||
ensurePublicDirectoriesExist();
|
ensurePublicDirectoriesExist();
|
||||||
await ensureThumbnailCache();
|
await ensureThumbnailCache();
|
||||||
contentManager.checkForNewContent();
|
contentManager.checkForNewContent();
|
||||||
|
@ -856,21 +727,6 @@ if (cliArguments.ssl) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function backupSettings() {
|
|
||||||
try {
|
|
||||||
if (!fs.existsSync(DIRECTORIES.backups)) {
|
|
||||||
fs.mkdirSync(DIRECTORIES.backups);
|
|
||||||
}
|
|
||||||
|
|
||||||
const backupFile = path.join(DIRECTORIES.backups, `settings_${generateTimestamp()}.json`);
|
|
||||||
fs.copyFileSync(SETTINGS_FILE, backupFile);
|
|
||||||
|
|
||||||
removeOldBackups('settings_');
|
|
||||||
} catch (err) {
|
|
||||||
console.log('Could not backup settings file', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function ensurePublicDirectoriesExist() {
|
function ensurePublicDirectoriesExist() {
|
||||||
for (const dir of Object.values(DIRECTORIES)) {
|
for (const dir of Object.values(DIRECTORIES)) {
|
||||||
if (!fs.existsSync(dir)) {
|
if (!fs.existsSync(dir)) {
|
||||||
|
|
|
@ -0,0 +1,164 @@
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const express = require('express');
|
||||||
|
const writeFileAtomicSync = require('write-file-atomic').sync;
|
||||||
|
const { DIRECTORIES } = require('../constants');
|
||||||
|
const { getConfigValue, generateTimestamp, removeOldBackups } = require('../util');
|
||||||
|
const { jsonParser } = require('../express-common');
|
||||||
|
const { migrateSecrets } = require('./secrets');
|
||||||
|
|
||||||
|
const enableExtensions = getConfigValue('enableExtensions', true);
|
||||||
|
const SETTINGS_FILE = './public/settings.json';
|
||||||
|
|
||||||
|
function readAndParseFromDirectory(directoryPath, fileExtension = '.json') {
|
||||||
|
const files = fs
|
||||||
|
.readdirSync(directoryPath)
|
||||||
|
.filter(x => path.parse(x).ext == fileExtension)
|
||||||
|
.sort();
|
||||||
|
|
||||||
|
const parsedFiles = [];
|
||||||
|
|
||||||
|
files.forEach(item => {
|
||||||
|
try {
|
||||||
|
const file = fs.readFileSync(path.join(directoryPath, item), 'utf-8');
|
||||||
|
parsedFiles.push(fileExtension == '.json' ? JSON.parse(file) : file);
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
// skip
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return parsedFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortByName(_) {
|
||||||
|
return (a, b) => a.localeCompare(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
function readPresetsFromDirectory(directoryPath, options = {}) {
|
||||||
|
const {
|
||||||
|
sortFunction,
|
||||||
|
removeFileExtension = false,
|
||||||
|
fileExtension = '.json',
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
const files = fs.readdirSync(directoryPath).sort(sortFunction).filter(x => path.parse(x).ext == fileExtension);
|
||||||
|
const fileContents = [];
|
||||||
|
const fileNames = [];
|
||||||
|
|
||||||
|
files.forEach(item => {
|
||||||
|
try {
|
||||||
|
const file = fs.readFileSync(path.join(directoryPath, item), 'utf8');
|
||||||
|
JSON.parse(file);
|
||||||
|
fileContents.push(file);
|
||||||
|
fileNames.push(removeFileExtension ? item.replace(/\.[^/.]+$/, '') : item);
|
||||||
|
} catch {
|
||||||
|
// skip
|
||||||
|
console.log(`${item} is not a valid JSON`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { fileContents, fileNames };
|
||||||
|
}
|
||||||
|
|
||||||
|
function backupSettings() {
|
||||||
|
try {
|
||||||
|
if (!fs.existsSync(DIRECTORIES.backups)) {
|
||||||
|
fs.mkdirSync(DIRECTORIES.backups);
|
||||||
|
}
|
||||||
|
|
||||||
|
const backupFile = path.join(DIRECTORIES.backups, `settings_${generateTimestamp()}.json`);
|
||||||
|
fs.copyFileSync(SETTINGS_FILE, backupFile);
|
||||||
|
|
||||||
|
removeOldBackups('settings_');
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Could not backup settings file', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.post('/save', jsonParser, function (request, response) {
|
||||||
|
try {
|
||||||
|
writeFileAtomicSync('public/settings.json', JSON.stringify(request.body, null, 4), 'utf8');
|
||||||
|
response.send({ result: 'ok' });
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
response.send(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wintermute's code
|
||||||
|
router.post('/get', jsonParser, (request, response) => {
|
||||||
|
let settings;
|
||||||
|
try {
|
||||||
|
settings = fs.readFileSync('public/settings.json', 'utf8');
|
||||||
|
} catch (e) {
|
||||||
|
return response.sendStatus(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NovelAI Settings
|
||||||
|
const { fileContents: novelai_settings, fileNames: novelai_setting_names }
|
||||||
|
= readPresetsFromDirectory(DIRECTORIES.novelAI_Settings, {
|
||||||
|
sortFunction: sortByName(DIRECTORIES.novelAI_Settings),
|
||||||
|
removeFileExtension: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// OpenAI Settings
|
||||||
|
const { fileContents: openai_settings, fileNames: openai_setting_names }
|
||||||
|
= readPresetsFromDirectory(DIRECTORIES.openAI_Settings, {
|
||||||
|
sortFunction: sortByName(DIRECTORIES.openAI_Settings), removeFileExtension: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// TextGenerationWebUI Settings
|
||||||
|
const { fileContents: textgenerationwebui_presets, fileNames: textgenerationwebui_preset_names }
|
||||||
|
= readPresetsFromDirectory(DIRECTORIES.textGen_Settings, {
|
||||||
|
sortFunction: sortByName(DIRECTORIES.textGen_Settings), removeFileExtension: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
//Kobold
|
||||||
|
const { fileContents: koboldai_settings, fileNames: koboldai_setting_names }
|
||||||
|
= readPresetsFromDirectory(DIRECTORIES.koboldAI_Settings, {
|
||||||
|
sortFunction: sortByName(DIRECTORIES.koboldAI_Settings), removeFileExtension: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const worldFiles = fs
|
||||||
|
.readdirSync(DIRECTORIES.worlds)
|
||||||
|
.filter(file => path.extname(file).toLowerCase() === '.json')
|
||||||
|
.sort((a, b) => a.localeCompare(b));
|
||||||
|
const world_names = worldFiles.map(item => path.parse(item).name);
|
||||||
|
|
||||||
|
const themes = readAndParseFromDirectory(DIRECTORIES.themes);
|
||||||
|
const movingUIPresets = readAndParseFromDirectory(DIRECTORIES.movingUI);
|
||||||
|
const quickReplyPresets = readAndParseFromDirectory(DIRECTORIES.quickreplies);
|
||||||
|
|
||||||
|
const instruct = readAndParseFromDirectory(DIRECTORIES.instruct);
|
||||||
|
const context = readAndParseFromDirectory(DIRECTORIES.context);
|
||||||
|
|
||||||
|
response.send({
|
||||||
|
settings,
|
||||||
|
koboldai_settings,
|
||||||
|
koboldai_setting_names,
|
||||||
|
world_names,
|
||||||
|
novelai_settings,
|
||||||
|
novelai_setting_names,
|
||||||
|
openai_settings,
|
||||||
|
openai_setting_names,
|
||||||
|
textgenerationwebui_presets,
|
||||||
|
textgenerationwebui_preset_names,
|
||||||
|
themes,
|
||||||
|
movingUIPresets,
|
||||||
|
quickReplyPresets,
|
||||||
|
instruct,
|
||||||
|
context,
|
||||||
|
enable_extensions: enableExtensions,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sync for now, but should probably be migrated to async file APIs
|
||||||
|
async function init() {
|
||||||
|
backupSettings();
|
||||||
|
migrateSecrets(SETTINGS_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { router, init };
|
Loading…
Reference in New Issue