mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Support specifing config.yaml
in cli
This commit is contained in:
77
server.js
77
server.js
@ -20,10 +20,28 @@ import open from 'open';
|
|||||||
|
|
||||||
// local library imports
|
// local library imports
|
||||||
import './src/fetch-patch.js';
|
import './src/fetch-patch.js';
|
||||||
import { serverEvents, EVENT_NAMES } from './src/server-events.js';
|
|
||||||
import { CommandLineParser } from './src/command-line.js';
|
import { CommandLineParser } from './src/command-line.js';
|
||||||
import { loadPlugins } from './src/plugin-loader.js';
|
import { serverDirectory } from './src/server-directory.js';
|
||||||
import {
|
|
||||||
|
console.log(`Node version: ${process.version}. Running in ${process.env.NODE_ENV} environment. Server directory: ${serverDirectory}`);
|
||||||
|
|
||||||
|
// Work around a node v20.0.0, v20.1.0, and v20.2.0 bug. The issue was fixed in v20.3.0.
|
||||||
|
// https://github.com/nodejs/node/issues/47822#issuecomment-1564708870
|
||||||
|
// Safe to remove once support for Node v20 is dropped.
|
||||||
|
if (process.versions && process.versions.node && process.versions.node.match(/20\.[0-2]\.0/)) {
|
||||||
|
// @ts-ignore
|
||||||
|
if (net.setDefaultAutoSelectFamily) net.setDefaultAutoSelectFamily(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// config.yaml will be set when parsing command line arguments
|
||||||
|
const cliArgs = new CommandLineParser().parse(process.argv);
|
||||||
|
globalThis.DATA_ROOT = cliArgs.dataRoot;
|
||||||
|
globalThis.COMMAND_LINE_ARGS = cliArgs;
|
||||||
|
process.chdir(serverDirectory);
|
||||||
|
|
||||||
|
const { serverEvents, EVENT_NAMES } = await import('./src/server-events.js');
|
||||||
|
const { loadPlugins } = await import('./src/plugin-loader.js');
|
||||||
|
const {
|
||||||
initUserStorage,
|
initUserStorage,
|
||||||
getCookieSecret,
|
getCookieSecret,
|
||||||
getCookieSessionName,
|
getCookieSessionName,
|
||||||
@ -38,17 +56,17 @@ import {
|
|||||||
getSessionCookieAge,
|
getSessionCookieAge,
|
||||||
verifySecuritySettings,
|
verifySecuritySettings,
|
||||||
loginPageMiddleware,
|
loginPageMiddleware,
|
||||||
} from './src/users.js';
|
} = await import('./src/users.js');
|
||||||
|
|
||||||
import getWebpackServeMiddleware from './src/middleware/webpack-serve.js';
|
const { default: getWebpackServeMiddleware } = await import('./src/middleware/webpack-serve.js');
|
||||||
import basicAuthMiddleware from './src/middleware/basicAuth.js';
|
const { default: basicAuthMiddleware } = await import('./src/middleware/basicAuth.js');
|
||||||
import getWhitelistMiddleware from './src/middleware/whitelist.js';
|
const { default: getWhitelistMiddleware } = await import('./src/middleware/whitelist.js');
|
||||||
import accessLoggerMiddleware, { getAccessLogPath, migrateAccessLog } from './src/middleware/accessLogWriter.js';
|
const { default: accessLoggerMiddleware, getAccessLogPath, migrateAccessLog } = await import('./src/middleware/accessLogWriter.js');
|
||||||
import multerMonkeyPatch from './src/middleware/multerMonkeyPatch.js';
|
const { default: multerMonkeyPatch } = await import('./src/middleware/multerMonkeyPatch.js');
|
||||||
import initRequestProxy from './src/request-proxy.js';
|
const { default: initRequestProxy } = await import('./src/request-proxy.js');
|
||||||
import getCacheBusterMiddleware from './src/middleware/cacheBuster.js';
|
const { default: getCacheBusterMiddleware } = await import('./src/middleware/cacheBuster.js');
|
||||||
import corsProxyMiddleware from './src/middleware/corsProxy.js';
|
const { default: corsProxyMiddleware } = await import('./src/middleware/corsProxy.js');
|
||||||
import {
|
const {
|
||||||
getVersion,
|
getVersion,
|
||||||
color,
|
color,
|
||||||
removeColorFormatting,
|
removeColorFormatting,
|
||||||
@ -56,38 +74,23 @@ import {
|
|||||||
safeReadFileSync,
|
safeReadFileSync,
|
||||||
setupLogLevel,
|
setupLogLevel,
|
||||||
setWindowTitle,
|
setWindowTitle,
|
||||||
} from './src/util.js';
|
} = await import('./src/util.js');
|
||||||
import { UPLOADS_DIRECTORY } from './src/constants.js';
|
const { UPLOADS_DIRECTORY } = await import('./src/constants.js');
|
||||||
import { ensureThumbnailCache } from './src/endpoints/thumbnails.js';
|
const { ensureThumbnailCache } = await import('./src/endpoints/thumbnails.js');
|
||||||
import { serverDirectory } from './src/server-directory.js';
|
|
||||||
|
|
||||||
// Routers
|
// Routers
|
||||||
import { router as usersPublicRouter } from './src/endpoints/users-public.js';
|
const { router : usersPublicRouter } = await import('./src/endpoints/users-public.js');
|
||||||
import { init as statsInit, onExit as statsOnExit } from './src/endpoints/stats.js';
|
const { init : statsInit, onExit : statsOnExit } = await import('./src/endpoints/stats.js');
|
||||||
import { checkForNewContent } from './src/endpoints/content-manager.js';
|
const { checkForNewContent } = await import('./src/endpoints/content-manager.js');
|
||||||
import { init as settingsInit } from './src/endpoints/settings.js';
|
const { init : settingsInit } = await import('./src/endpoints/settings.js');
|
||||||
import { redirectDeprecatedEndpoints, ServerStartup, setupPrivateEndpoints } from './src/server-startup.js';
|
const { redirectDeprecatedEndpoints, ServerStartup, setupPrivateEndpoints } = await import('./src/server-startup.js');
|
||||||
import { diskCache } from './src/endpoints/characters.js';
|
const { diskCache } = await import('./src/endpoints/characters.js');
|
||||||
|
|
||||||
// Unrestrict console logs display limit
|
// Unrestrict console logs display limit
|
||||||
util.inspect.defaultOptions.maxArrayLength = null;
|
util.inspect.defaultOptions.maxArrayLength = null;
|
||||||
util.inspect.defaultOptions.maxStringLength = null;
|
util.inspect.defaultOptions.maxStringLength = null;
|
||||||
util.inspect.defaultOptions.depth = 4;
|
util.inspect.defaultOptions.depth = 4;
|
||||||
|
|
||||||
console.log(`Node version: ${process.version}. Running in ${process.env.NODE_ENV} environment. Server directory: ${serverDirectory}`);
|
|
||||||
|
|
||||||
// Work around a node v20.0.0, v20.1.0, and v20.2.0 bug. The issue was fixed in v20.3.0.
|
|
||||||
// https://github.com/nodejs/node/issues/47822#issuecomment-1564708870
|
|
||||||
// Safe to remove once support for Node v20 is dropped.
|
|
||||||
if (process.versions && process.versions.node && process.versions.node.match(/20\.[0-2]\.0/)) {
|
|
||||||
// @ts-ignore
|
|
||||||
if (net.setDefaultAutoSelectFamily) net.setDefaultAutoSelectFamily(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
const cliArgs = new CommandLineParser().parse(process.argv);
|
|
||||||
globalThis.DATA_ROOT = cliArgs.dataRoot;
|
|
||||||
globalThis.COMMAND_LINE_ARGS = cliArgs;
|
|
||||||
|
|
||||||
if (!cliArgs.enableIPv6 && !cliArgs.enableIPv4) {
|
if (!cliArgs.enableIPv6 && !cliArgs.enableIPv4) {
|
||||||
console.error('error: You can\'t disable all internet protocols: at least IPv6 or IPv4 must be enabled.');
|
console.error('error: You can\'t disable all internet protocols: at least IPv6 or IPv4 must be enabled.');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import yargs from 'yargs/yargs';
|
import yargs from 'yargs/yargs';
|
||||||
import { hideBin } from 'yargs/helpers';
|
import { hideBin } from 'yargs/helpers';
|
||||||
import ipRegex from 'ip-regex';
|
import ipRegex from 'ip-regex';
|
||||||
import { canResolve, color, getConfigValue, stringToBool } from './util.js';
|
import { canResolve, color, getConfigValue, setConfigFilePath, stringToBool } from './util.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {object} CommandLineArguments Parsed command line arguments
|
* @typedef {object} CommandLineArguments Parsed command line arguments
|
||||||
|
* @property {string} configPath Path to the config file
|
||||||
* @property {string} dataRoot Data root directory
|
* @property {string} dataRoot Data root directory
|
||||||
* @property {number} port Port number
|
* @property {number} port Port number
|
||||||
* @property {boolean} listen If SillyTavern is listening on all network interfaces
|
* @property {boolean} listen If SillyTavern is listening on all network interfaces
|
||||||
@ -40,6 +41,7 @@ export class CommandLineParser {
|
|||||||
constructor() {
|
constructor() {
|
||||||
/** @type {CommandLineArguments} */
|
/** @type {CommandLineArguments} */
|
||||||
this.default = Object.freeze({
|
this.default = Object.freeze({
|
||||||
|
configPath: './config.yaml',
|
||||||
dataRoot: './data',
|
dataRoot: './data',
|
||||||
port: 8000,
|
port: 8000,
|
||||||
listen: false,
|
listen: false,
|
||||||
@ -88,6 +90,11 @@ export class CommandLineParser {
|
|||||||
parse(args) {
|
parse(args) {
|
||||||
const cliArguments = yargs(hideBin(args))
|
const cliArguments = yargs(hideBin(args))
|
||||||
.usage('Usage: <your-start-script> [options]\nOptions that are not provided will be filled with config values.')
|
.usage('Usage: <your-start-script> [options]\nOptions that are not provided will be filled with config values.')
|
||||||
|
.option('configPath', {
|
||||||
|
type: 'string',
|
||||||
|
default: null,
|
||||||
|
describe: 'Path to the config file',
|
||||||
|
})
|
||||||
.option('enableIPv6', {
|
.option('enableIPv6', {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
default: null,
|
default: null,
|
||||||
@ -177,8 +184,11 @@ export class CommandLineParser {
|
|||||||
describe: 'Request proxy bypass list (space separated list of hosts)',
|
describe: 'Request proxy bypass list (space separated list of hosts)',
|
||||||
}).parseSync();
|
}).parseSync();
|
||||||
|
|
||||||
|
const configPath = cliArguments.configPath ?? this.default.configPath;
|
||||||
|
setConfigFilePath(configPath);
|
||||||
/** @type {CommandLineArguments} */
|
/** @type {CommandLineArguments} */
|
||||||
const result = {
|
const result = {
|
||||||
|
configPath: configPath,
|
||||||
dataRoot: cliArguments.dataRoot ?? getConfigValue('dataRoot', this.default.dataRoot),
|
dataRoot: cliArguments.dataRoot ?? getConfigValue('dataRoot', this.default.dataRoot),
|
||||||
port: cliArguments.port ?? getConfigValue('port', this.default.port, 'number'),
|
port: cliArguments.port ?? getConfigValue('port', this.default.port, 'number'),
|
||||||
listen: cliArguments.listen ?? getConfigValue('listen', this.default.listen, 'boolean'),
|
listen: cliArguments.listen ?? getConfigValue('listen', this.default.listen, 'boolean'),
|
||||||
|
22
src/util.js
22
src/util.js
@ -23,6 +23,7 @@ import { serverDirectory } from './server-directory.js';
|
|||||||
* Parsed config object.
|
* Parsed config object.
|
||||||
*/
|
*/
|
||||||
let CACHED_CONFIG = null;
|
let CACHED_CONFIG = null;
|
||||||
|
let CONFIG_FILE = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a configuration key to an environment variable key.
|
* Converts a configuration key to an environment variable key.
|
||||||
@ -32,23 +33,38 @@ let CACHED_CONFIG = null;
|
|||||||
*/
|
*/
|
||||||
export const keyToEnv = (key) => 'SILLYTAVERN_' + String(key).toUpperCase().replace(/\./g, '_');
|
export const keyToEnv = (key) => 'SILLYTAVERN_' + String(key).toUpperCase().replace(/\./g, '_');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the config file path.
|
||||||
|
* @param {string} configFilePath Path to the config file
|
||||||
|
*/
|
||||||
|
export function setConfigFilePath(configFilePath) {
|
||||||
|
if (CONFIG_FILE !== null) {
|
||||||
|
console.error(color.red('Config file path already set. Please restart the server to change the config file path.'));
|
||||||
|
}
|
||||||
|
CONFIG_FILE = path.resolve(configFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the config object from the config.yaml file.
|
* Returns the config object from the config.yaml file.
|
||||||
* @returns {object} Config object
|
* @returns {object} Config object
|
||||||
*/
|
*/
|
||||||
export function getConfig() {
|
export function getConfig() {
|
||||||
|
if (CONFIG_FILE === null) {
|
||||||
|
console.trace();
|
||||||
|
console.error(color.red('No config file path set. Please set the config file path using setConfigFilePath().'));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
if (CACHED_CONFIG) {
|
if (CACHED_CONFIG) {
|
||||||
return CACHED_CONFIG;
|
return CACHED_CONFIG;
|
||||||
}
|
}
|
||||||
|
if (!fs.existsSync(CONFIG_FILE)) {
|
||||||
if (!fs.existsSync('./config.yaml')) {
|
|
||||||
console.error(color.red('No config file found. Please create a config.yaml file. The default config file can be found in the /default folder.'));
|
console.error(color.red('No config file found. Please create a config.yaml file. The default config file can be found in the /default folder.'));
|
||||||
console.error(color.red('The program will now exit.'));
|
console.error(color.red('The program will now exit.'));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const config = yaml.parse(fs.readFileSync(path.join(process.cwd(), './config.yaml'), 'utf8'));
|
const config = yaml.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
||||||
CACHED_CONFIG = config;
|
CACHED_CONFIG = config;
|
||||||
return config;
|
return config;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
Reference in New Issue
Block a user