-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patheslp.mjs
executable file
·112 lines (89 loc) · 3.71 KB
/
eslp.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#!/usr/bin/env node
/** @typedef { import('./lib/types').Server } Server */
/** @typedef { import('./lib/types').Cors } Cors */
/** @typedef { import('./lib/servers.mjs').Servers } Servers */
// import fs from 'node:fs'
import { watch, readFile } from 'node:fs/promises'
import path from 'node:path'
import * as readline from 'node:readline/promises'
import { log } from './lib/log.mjs'
import { pkg } from './lib/pkg.mjs'
import { getCli } from './lib/cli.mjs'
import { startProxy, updateCors } from './lib/proxy.mjs'
import { createServers } from './lib/servers.mjs'
import { advertiseHostNamesViaMDNS } from './lib/m-dns.mjs'
import { getConfig, expandInitialTilde } from './lib/config.mjs'
const DEFAULT_PORT = 19200
main()
async function main() {
// get cli arguments, read and generate config
const cli = getCli(process.argv.slice(2))
const { help, version, debug, configFile: rawConfigFile } = cli
const configFile = expandInitialTilde(rawConfigFile)
log.setDebug(!!debug)
const config = getConfig(configFile)
const { servers: configServers, fileName: configFileName } = config
log.debug(`cli: ${JSON.stringify(cli)}`)
log.debug(`config: ${JSON.stringify(config, redactSecrets)}`)
// handle flags
if (help) { console.log(await getHelp()); process.exit(1) }
if (version) { console.log(pkg.version); process.exit(1) }
// build data structures
const port = cli.port || config.port || DEFAULT_PORT
const servers = createServers(port, configServers, !!config.cert)
// set up config file re-loaders
reloadConfigWhenChanged(configFileName, servers, cli.output)
reloadConfigWhenHumans(configFileName, servers, cli.output)
// print servers
servers.output(cli.output)
// start 'er up!
start(servers, port, config.cert, config.key, config.cors || {})
}
/** @type { (servers: Servers, port: number, cert: string | undefined, key: string | undefined, cors: Cors) => Promise<void> } */
async function start(servers, port, cert, key, cors) {
try {
await startProxy(servers, port, cert, key, cors)
} catch (err) {
log.exit(`error starting server: ${err}`, 1)
}
advertiseHostNamesViaMDNS(servers)
}
/** @type { (fileName: string, servers: Servers, outputType: string) => Promise<void> } */
async function reloadConfigWhenChanged(fileName, servers, outputType) {
try {
const watcher = watch(fileName)
for await (const event of watcher) {
reload(fileName, servers, 'config file changed', outputType)
}
} catch (err) {
log(`error watching config file "${fileName}", not watching for file: ${err}`)
return
}
}
/** @type { (fileName: string, servers: Servers, outputType: string) => Promise<void> } */
async function reloadConfigWhenHumans(fileName, servers, outputType) {
const rl = readline.createInterface({ input: process.stdin })
rl.on('line', () => reload(fileName, servers, 'humans', outputType))
}
/** @type { (fileName: string, servers: Servers, reason: string, outputType: string) => Promise<void> } */
async function reload(fileName, servers, reason, outputType) {
const date = new Date().toISOString()
log(`${date} - reloading config file: ${fileName} because ${reason}`)
const newConfig = getConfig(fileName)
servers.replaceServers(newConfig.servers)
updateCors(newConfig.cors || {})
servers.output(outputType)
}
/** @type { () => Promise<string> } */
async function getHelp() {
const thisFile = new URL(import.meta.url).pathname
const thisDir = path.dirname(thisFile)
return await readFile(`${thisDir}/README.md`, 'utf-8')
}
/** @type { (key: string, val: any) => any } */
function redactSecrets(key, val) {
if (key === 'user') return '<** user **>'
if (key === 'pass') return '<** pass **>'
if (key === 'apiKey') return '<** apiKey **>'
return val
}