mirror of
https://git.joinsharkey.org/Sharkey/Sharkey.git
synced 2024-11-22 11:13:08 +02:00
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/476 Closes #465 Approved-by: Marie <marie@kaifa.ch>
This commit is contained in:
commit
5ef39c8644
1 changed files with 122 additions and 0 deletions
|
@ -212,6 +212,8 @@ export function loadConfig(): Config {
|
|||
{} as Source,
|
||||
) as Source;
|
||||
|
||||
applyEnvOverrides(config);
|
||||
|
||||
const url = tryCreateUrl(config.url);
|
||||
const version = meta.version;
|
||||
const host = url.host;
|
||||
|
@ -304,3 +306,123 @@ function convertRedisOptions(options: RedisOptionsSource, host: string): RedisOp
|
|||
db: options.db ?? 0,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
this function allows overriding any string-valued config option with
|
||||
a sensible-named environment variable
|
||||
|
||||
e.g. `MK_CONFIG_MEILISEARCH_APIKEY` sets `config.meilisearch.apikey`
|
||||
|
||||
you can also override a single `dbSlave` value,
|
||||
e.g. `MK_CONFIG_DBSLAVES_1_PASS` sets the password for the 2nd
|
||||
database replica (the first one would be
|
||||
`MK_CONFIG_DBSLAVES_0_PASS`); in this case, `config.dbSlaves` must
|
||||
be set to an array of the right size already in the file
|
||||
|
||||
values can be read from files, too: setting `MK_DB_PASS_FILE` to
|
||||
`/some/file` would set the main database password to the contents of
|
||||
`/some/file` (trimmed of whitespaces)
|
||||
*/
|
||||
function applyEnvOverrides(config: Source) {
|
||||
// these inner functions recurse through the config structure, using
|
||||
// the given steps, building the env variable name
|
||||
|
||||
function _apply_top(steps: (string | number)[]) {
|
||||
_walk('', [], steps);
|
||||
}
|
||||
|
||||
function _walk(name: string, path: (string | number)[], steps: (string | number)[]) {
|
||||
// are there more steps after this one? recurse
|
||||
if (steps.length > 1) {
|
||||
const thisStep = steps.shift();
|
||||
if (thisStep === null || thisStep === undefined) return;
|
||||
|
||||
// if a step is not a simple value, iterate through it
|
||||
if (typeof thisStep === 'object') {
|
||||
for (const thisOneStep of thisStep) {
|
||||
_descend(name, path, thisOneStep, steps);
|
||||
}
|
||||
} else {
|
||||
_descend(name, path, thisStep, steps);
|
||||
}
|
||||
|
||||
// the actual override has happened at the bottom of the
|
||||
// recursion, we're done
|
||||
return;
|
||||
}
|
||||
|
||||
// this is the last step, same thing as above
|
||||
const lastStep = steps[0];
|
||||
|
||||
if (typeof lastStep === 'object') {
|
||||
for (const lastOneStep of lastStep) {
|
||||
_lastBit(name, path, lastOneStep);
|
||||
}
|
||||
} else {
|
||||
_lastBit(name, path, lastStep);
|
||||
}
|
||||
}
|
||||
|
||||
function _step2name(step: string|number): string {
|
||||
return step.toString().replaceAll(/[^a-z0-9]+/gi,'').toUpperCase();
|
||||
}
|
||||
|
||||
// this recurses down, bailing out if there's no config to override
|
||||
function _descend(name: string, path: (string | number)[], thisStep: string | number, steps: (string | number)[]) {
|
||||
name = `${name}${_step2name(thisStep)}_`;
|
||||
path = [ ...path, thisStep ];
|
||||
_walk(name, path, steps);
|
||||
}
|
||||
|
||||
// this is the bottom of the recursion: look at the environment and
|
||||
// set the value
|
||||
function _lastBit(name: string, path: (string | number)[], lastStep: string | number) {
|
||||
name = `MK_CONFIG_${name}${_step2name(lastStep)}`;
|
||||
|
||||
const val = process.env[name];
|
||||
if (val != null && val != undefined) {
|
||||
_assign(path, lastStep, val);
|
||||
}
|
||||
|
||||
const file = process.env[`${name}_FILE`];
|
||||
if (file) {
|
||||
_assign(path, lastStep, fs.readFileSync(file, 'utf-8').trim());
|
||||
}
|
||||
}
|
||||
|
||||
const alwaysStrings = { 'chmodSocket': 1 };
|
||||
|
||||
function _assign(path: (string | number)[], lastStep: string | number, value: string) {
|
||||
let thisConfig = config;
|
||||
for (const step of path) {
|
||||
if (!thisConfig[step]) {
|
||||
thisConfig[step] = {};
|
||||
}
|
||||
thisConfig = thisConfig[step];
|
||||
}
|
||||
|
||||
if (!alwaysStrings[lastStep]) {
|
||||
if (value.match(/^[0-9]+$/)) {
|
||||
value = parseInt(value);
|
||||
} else if (value.match(/^(true|false)$/i)) {
|
||||
value = !!value.match(/^true$/i);
|
||||
}
|
||||
}
|
||||
|
||||
thisConfig[lastStep] = value;
|
||||
}
|
||||
|
||||
// these are all the settings that can be overridden
|
||||
|
||||
_apply_top([['url', 'port', 'socket', 'chmodSocket', 'disableHsts']]);
|
||||
_apply_top(['db', ['host', 'port', 'db', 'user', 'pass']]);
|
||||
_apply_top(['dbSlaves', config.dbSlaves?.keys(), ['host', 'port', 'db', 'user', 'pass']]);
|
||||
_apply_top([
|
||||
['redis', 'redisForPubsub', 'redisForJobQueue', 'redisForTimelines'],
|
||||
['host','port','username','pass','db','prefix'],
|
||||
]);
|
||||
_apply_top(['meilisearch', ['host', 'port', 'apikey', 'ssl', 'index', 'scope']]);
|
||||
_apply_top([['clusterLimit', 'deliverJobConcurrency', 'inboxJobConcurrency', 'relashionshipJobConcurrency', 'deliverJobPerSec', 'inboxJobPerSec', 'relashionshipJobPerSec', 'deliverJobMaxAttempts', 'inboxJobMaxAttempts']]);
|
||||
_apply_top([['outgoingAddress', 'outgoingAddressFamily', 'proxy', 'proxySmtp', 'mediaProxy', 'videoThumbnailGenerator']]);
|
||||
_apply_top([['maxFileSize', 'maxNoteLength', 'pidFile']]);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue