CLI arguments will now be considered user requests to modify configuration, exactly as it was done via the Admin panel

Massimo Melina committed Apr 10, 2022 at 14:47 UTC d515e49b3c7d8dd6f042d45a317a58287d98fcd5
3 files changed +15 -7
server/src/config.ts
+12 -7
@@ -5,7 +5,7 @@ import { argv } from './const'
5 import { watchLoad } from './watchLoad'
6 import yaml from 'yaml'
7 import _ from 'lodash'
8 -import { debounceAsync, objSameKeys, onOff } from './misc'
8 +import { debounceAsync, objSameKeys, onOff, wait } from './misc'
9 import { exists } from 'fs'
10 import { promisify } from 'util'
11
@@ -20,7 +20,7 @@ let state: Record<string, any> = {}
20 const cfgEvents = new EventEmitter()
21 cfgEvents.setMaxListeners(10_000)
22 const path = argv.config || process.env.HFS_CONFIG || PATH
23 -const { save } = watchLoad(path, values => setConfig(values||{}, false), {
23 +const { save } = watchLoad(path, values => setConfig(values||{}, false), {
24 failedOnFirstAttempt(){
25 console.log("No config file, using defaults")
26 setTimeout(() => // for consistency with asynchronous success callback (without this http server is started before the koa app is ready)
@@ -37,7 +37,6 @@ export function defineConfig<T>(k: string, definition: Partial<ConfigProps<T>>)
37 const { caster = _.identity } = definition
38 configProps[k] = {
39 caster,
40 - arg: caster(argv[k]),
40 ...definition,
41 defaultValue: _.cloneDeep(definition.defaultValue),
42 }
@@ -46,9 +45,7 @@ export function defineConfig<T>(k: string, definition: Partial<ConfigProps<T>>)
45 export function subscribeConfig<T>({ k, ...definition }:{ k:string } & Partial<ConfigProps<T>>, cb:(v:T, was?:T)=>void) {
46 if (definition)
47 defineConfig(k, definition)
49 - const { defaultValue, arg } = configProps[k] ?? {}
50 - if (arg !== undefined) // it was passed at command line, and it will never change
51 - return cb(arg)
48 + const { defaultValue } = configProps[k] ?? {}
49 const eventName = 'new.'+k
50 if (started) {
51 let v = state[k]
@@ -68,7 +65,6 @@ export function getWholeConfig({ omit=[], only=[] }: { omit:string[], only:strin
65 let copy = Object.assign(
66 objSameKeys(configProps, x => x.defaultValue),
67 state,
71 - _.pickBy(objSameKeys(configProps, x => x.arg), x => x !== undefined),
68 )
69 copy = _.omit(copy, omit)
70 if (only.length)
@@ -78,6 +74,13 @@ export function getWholeConfig({ omit=[], only=[] }: { omit:string[], only:strin
74
75 // pass a value to `save` to force saving decision, or leave undefined for auto. Passing false will also reset previously loaded configs.
76 export function setConfig(newCfg: Record<string,any>, save?: boolean) {
77 + if (!started) { // first time we consider also CLI args
78 + const argCfg = _.pickBy(objSameKeys(configProps, (x,k) => argv[k]), x => x !== undefined)
79 + if (! _.isEmpty(argCfg)) {
80 + saveConfigAsap().then() // don't set `save` argument, as it would interfere below at check `save===false`
81 + Object.assign(newCfg, argCfg)
82 + }
83 + }
84 for (const k in newCfg)
85 check(k)
86 if (save) {
@@ -118,6 +121,8 @@ export function setConfig(newCfg: Record<string,any>, save?: boolean) {
121 }
122
123 export const saveConfigAsap = debounceAsync(async () => {
124 + while (!started)
125 + await wait(100)
126 let txt = yaml.stringify(state, { lineWidth:1000 })
127 if (txt.trim() === '{}') // most users wouldn't understand
128 if (await promisify(exists)(path)) // if a file exists then empty it, else don't bother creating it
server/src/listen.ts
+2
@@ -58,6 +58,8 @@ async function considerHttps() {
58 stopServer(httpsSrv).then()
59 let port = getConfig('https_port')
60 try {
61 + while (!app)
62 + await wait(100)
63 httpsSrv = Object.assign(
64 https.createServer(port < 0 ? {} : { key: httpsNeeds.private_key, cert: httpsNeeds.cert }, app.callback()),
65 { name: 'https' }
todo.md
+1
@@ -1,4 +1,5 @@
1 # To do
2 +- custom text to display on the frontend
3 - log exceptions
4 - watch certificates for change
5 - admin/fs: render virtual folders differently