start console messages with uppercase
Massimo Melina committed
Apr 7, 2026 at 11:11 UTC
8bfbdba64655ce12ce41417bd5e14056207641e2
33 files changed
+124
-124
src/QuickZipStream.ts
+1
-1
@@ -160,7 +160,7 @@ export class QuickZipStream extends Readable {
160
const data = this.workingFile = getData()
161
data.on('error', (err) => {
162
if ((err as any)?.code !== 'EACCES')
163
- console.error('zipping:', String(err))
163
+ console.error('Zipping:', String(err))
164
data.destroy(err)
165
resolve()
166
})
src/acme.ts
+8
-8
@@ -19,7 +19,7 @@ const acmeListener = (req: IncomingMessage, res: ServerResponse) => { // node li
19
const BASE = '/.well-known/acme-challenge/'
20
if (!req.url?.startsWith(BASE)) return
21
const token = req.url.slice(BASE.length)
22
- console.debug("got http challenge", token)
22
+ console.debug("Got http challenge", token)
23
res.statusCode = HTTP_OK
24
res.end(acmeTokens[token])
25
return true // true = responded
@@ -50,17 +50,17 @@ async function generateSSLCert(domain: string, email?: string, altNames?: string
50
if (tempSrv)
51
await new Promise<void>(resolve =>
52
tempSrv.listen(80, resolve).on('error', (e: any) => {
53
- console.debug("cannot listen on 80", e.code || e)
53
+ console.debug("Cannot listen on 80", e.code || e)
54
resolve() // go on anyway
55
}) )
56
acmeOngoing = true
57
- console.debug("acme challenge server ready")
57
+ console.debug("ACME challenge server ready")
58
let tempMap: any
59
try {
60
const checkUrl = `http://${domain.split(',')[0]}`
61
let check = await selfCheck(checkUrl) // some check services may not consider the domain, but we already verified that
62
if (check?.success === false && nat.upnp && !nat.mapped80) {
63
- console.debug("setting temporary port forward")
63
+ console.debug("Setting temporary port forward")
64
tempMap = await haveTimeout(10_000, upnpClient.createMapping(TEMP_MAP).catch(() => {})).catch(() => {})
65
check = await selfCheck(checkUrl) // repeat test
66
}
@@ -82,17 +82,17 @@ async function generateSSLCert(domain: string, email?: string, altNames?: string
82
async challengeCreateFn(_, c, ka) { acmeTokens[c.token] = ka },
83
async challengeRemoveFn(_, c) { delete acmeTokens[c.token] },
84
})
85
- console.log("acme certificate generated")
85
+ console.log("ACME certificate generated")
86
return { key, cert }
87
}
88
finally {
89
if (tempMap) {
90
- console.debug("removing temporary port forward")
90
+ console.debug("Removing temporary port forward")
91
upnpClient.removeMapping(TEMP_MAP).catch(() => {}) // clean after ourselves
92
}
93
acmeOngoing = false
94
if (tempSrv) await new Promise(res => tempSrv.close(res))
95
- console.debug('acme terminated')
95
+ console.debug('ACME terminated')
96
}
97
}
98
@@ -127,7 +127,7 @@ const renewCert = debounceAsync(async () => {
127
const validTo = new Date(cert.validTo)
128
// not expiring in a month
129
if (now > new Date(cert.validFrom) && now < validTo && validTo.getTime() - now.getTime() >= 30 * DAY)
130
- return console.log("certificate still good")
130
+ return console.log("Certificate still good")
131
await makeCert(domain, undefined, altNames)
132
.catch(e => console.log(acmeRenewError = `Error renewing certificate, expiring ${formatDate(validTo)}: ${String(e.message || e)}`))
133
}, { retain: DAY, retainFailure: HOUR })
src/api.get_file_list.ts
+1
-1
@@ -94,7 +94,7 @@ export const get_file_list: ApiHandler = async ({ uri='/', offset, limit, c, onl
94
continue
95
}
96
catch(e) {
97
- console.log("a plugin with onDirEntry is causing problems:", e)
97
+ console.log("A plugin with onDirEntry is causing problems:", e)
98
}
99
if (offset) {
100
--offset
src/block.ts
+1
-1
@@ -35,7 +35,7 @@ setInterval(() => { // twice a minute, check if any block has expired
35
const next = block.get().filter(x => !x.expire || x.expire > now)
36
const n = block.get().length - next.length
37
if (!n) return
38
- console.log("blocking rules:", n, "expired")
38
+ console.log("Blocking rules:", n, "expired")
39
block.set(next)
40
}, MINUTE/2)
41
src/commands.ts
+8
-8
@@ -56,7 +56,7 @@ if (!argv.updating && !showHelp) {
56
57
}
58
catch {
59
- console.log("console commands not available")
59
+ console.log("Console commands not available")
60
const original = console.debug
61
console.debug = (...args: any[]) => debugEnabled && original(...args)
62
}
@@ -72,17 +72,17 @@ async function parseCommandLine(line: string) {
72
if (cmd?.alias)
73
cmd = (commands as any)[cmd.alias]
74
if (!cmd)
75
- return console.error("invalid command, try 'help'")
75
+ return console.error("Invalid command, try 'help'")
76
if (cmd.cb.length > params.length)
77
- return console.error("insufficient parameters, expected: " + cmd.params)
77
+ return console.error("Insufficient parameters, expected: " + cmd.params)
78
try {
79
await cmd.cb(...params)
80
- console.log("+++ command executed")
80
+ console.log("+++ Command executed")
81
}
82
catch(err: any) {
83
if (typeof err !== 'string' && !err?.message)
84
throw err
85
- console.error("command failed:", err.message || err)
85
+ console.error("Command failed:", err.message || err)
86
}
87
}
88
@@ -92,7 +92,7 @@ const commands = {
92
help: {
93
params: '',
94
cb() {
95
- console.log("available commands:",
95
+ console.log("Available commands:",
96
..._.map(commands, ({ params }, name) =>
97
'\n - ' + name + ' ' + params))
98
}
@@ -151,7 +151,7 @@ const commands = {
151
const update = await getBestUpdate()
152
if (!update)
153
throw "you already have the latest version: " + VERSION
154
- console.log("new version available", update.name)
154
+ console.log("New version available", update.name)
155
}
156
},
157
version: {
@@ -164,7 +164,7 @@ const commands = {
164
params: '',
165
cb() {
166
debugEnabled = !debugEnabled
167
- console.log(`debug messages ${debugEnabled ? "on" : "off"}`)
167
+ console.log(`Debug messages ${debugEnabled ? "on" : "off"}`)
168
}
169
},
170
'start-plugin': {
src/config.ts
+1
-1
@@ -199,7 +199,7 @@ function stringify(obj: any) {
199
}
200
201
let startedWithoutConfig = false
202
-console.log("config", filePath)
202
+console.log("Config", filePath)
203
export const configFile = watchLoad(filePath, text => {
204
startedWithoutConfig = !text
205
try { return setConfig(yaml.parse(text, { uniqueKeys: false }) || {}, false) }
src/connections.ts
+1
-1
@@ -93,7 +93,7 @@ export function disconnect(what: Context | Socket | Connection, logMessage='') {
93
what = what.socket
94
const ip = normalizeIp(what.remoteAddress || '')
95
if (logMessage)
96
- console.debug("disconnection:", logMessage, ip)
96
+ console.debug("Disconnection:", logMessage, ip)
97
ip2country(ip).then(res => {
98
const rec = { ip, country: res || undefined, ts: new Date, msg: logMessage || undefined }
99
disconnectionsLog.unshift(rec)
src/const.ts
+10
-10
@@ -17,7 +17,7 @@ export const COMPATIBLE_API_VERSION = 1 // the day we break with the past, we'll
17
export const ARGS_FILE = join(homedir(), 'hfs-args')
18
try {
19
const s = fs.readFileSync(ARGS_FILE, 'utf-8')
20
- console.log('additional arguments', s)
20
+ console.log('Additional arguments', s)
21
_.defaults(argv, minimist(JSON.parse(s)))
22
fs.unlinkSync(ARGS_FILE)
23
}
@@ -48,9 +48,9 @@ if (DEV) {
48
}
49
console.log(`HFS ~ HTTP File Server`)
50
console.log(`© Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt`)
51
-console.log('started', formatTimestamp(HFS_STARTED), DEV)
52
-console.log('version', VERSION||'-')
53
-console.log('build', BUILD_TIMESTAMP||'-')
51
+console.log('Started', formatTimestamp(HFS_STARTED), DEV)
52
+console.log('Version', VERSION||'-')
53
+console.log('Build', BUILD_TIMESTAMP||'-')
54
// still considering whether to use ".hfs" with Windows users, who may be less accustomed to it
55
const dir = argv.cwd || useHomeDir() && join(homedir(), '.hfs')
56
if (dir) {
@@ -63,14 +63,14 @@ if (dir) {
63
}
64
else if (process.cwd().startsWith(process.env.windir + '\\')) // this happens if you run hfs from task scheduler
65
process.chdir(APP_PATH)
66
-console.log('working directory (cwd)', process.cwd())
66
+console.log('Working directory (cwd)', process.cwd())
67
if (APP_PATH !== process.cwd())
68
- console.log('app', APP_PATH)
69
-console.log('node', process.version)
68
+ console.log('App', APP_PATH)
69
+console.log('Node', process.version)
70
const bun = (globalThis as any).Bun
71
-if (bun) console.log('bun', bun.version)
72
-console.log('platform', process.platform, process.arch, IS_BINARY ? 'binary' : basename(process.execPath))
73
-console.log('pid', process.pid)
71
+if (bun) console.log('Bun', bun.version)
72
+console.log('Platform', process.platform, process.arch, IS_BINARY ? 'binary' : basename(process.execPath))
73
+console.log('Pid', process.pid)
74
75
function useHomeDir() {
76
if (!IS_WINDOWS || !IS_BINARY) return true
src/ddns.ts
+1
-1
@@ -54,7 +54,7 @@ dynamicDnsUrl.sub(v => {
54
}))
55
last = _.find(all, 'error') || all[0] // the system is designed for just one result, and we give precedence to errors
56
events.emit('dynamicDnsError', last)
57
- console.log('dynamic dns update', last?.error || 'ok')
57
+ console.log('Dynamic dns update', last?.error || 'ok')
58
}, { callNow: true })
59
})
60
src/fileAttr.ts
+2
-2
@@ -35,7 +35,7 @@ export async function storeFileAttr(path: string, k: string, v: any) {
35
else await fileAttrDb.open(FN)
36
// pipe should be a safe separator
37
return await fileAttrDb.put(`${path}|${k}`, v)?.catch((e: any) => {
38
- console.error("couldn't store metadata on", path, String(e.message || e))
38
+ console.error("Couldn't store metadata on", path, String(e.message || e))
39
return false
40
}) ?? true // if put is undefined, the value was already there
41
}
@@ -56,5 +56,5 @@ export async function purgeFileAttr() {
56
}))
57
if (n)
58
await fileAttrDb.rewrite()
59
- console.log(`removed ${n} entrie(s)`)
59
+ console.log(`Removed ${n} entrie(s)`)
60
}
\ No newline at end of file
src/first.ts
+2
-2
@@ -12,9 +12,9 @@ export let quitting = false
12
// 'exit' event is handled as the last resort, but it's not compatible with async callbacks
13
onFirstEvent(process, ['exit', 'SIGQUIT', 'SIGTERM', 'SIGINT', 'SIGHUP'], signal => {
14
quitting = true
15
- console.log('quitting', signal || '')
15
+ console.log('Quitting', signal || '')
16
return Promise.allSettled(Array.from(cbsOnExit).map(cb => cb(signal))).then(() => {
17
- console.debug('process exit')
17
+ console.debug('Process exit')
18
process.exit(0)
19
})
20
})
src/geo.ts
+2
-2
@@ -46,7 +46,7 @@ async function checkFiles() {
46
if (+mtime < now - 31 * DAY) // month-old or non-existing
47
try {
48
const req = await httpStream(URL)
49
- console.log(`downloading ${name}`)
49
+ console.log(`Downloading ${name}`)
50
await unzip(req, path => path.toUpperCase().endsWith(ZIP_FILE) && TEMP)
51
await statWithTimeout(TEMP) // check existence
52
if (isOpen())
@@ -60,6 +60,6 @@ async function checkFiles() {
60
console.error(`Failed to download ${name}${mtime ? ", falling back on old data" : ''}:`, e?.message || String(e))
61
}
62
else if (isOpen()) return
63
- console.debug(`loading ${name}`)
63
+ console.debug(`Loading ${name}`)
64
ip2location.open(LOCAL_FILE) // using openAsync causes a DEP0137 error within 10 seconds
65
}
src/github.ts
+5
-5
@@ -57,7 +57,7 @@ export async function downloadPlugin(repo: Repo, { branch='', overwrite=false }=
57
const msg = await isPluginBlacklisted(repo) // check before downloading, in case other filters were passed somehow
58
if (msg)
59
throw new ApiError(HTTP_FORBIDDEN, "blacklisted: " + msg)
60
- console.log('downloading plugin', repo)
60
+ console.log('Downloading plugin', repo)
61
downloadProgress(repo, true)
62
try {
63
const pl = findPluginByRepo(repo)
@@ -117,7 +117,7 @@ export async function downloadPlugin(repo: Repo, { branch='', overwrite=false }=
117
}
118
}
119
catch (e) { // don't abort the whole procedure just because of the check above. It should never fail, but a user reported a mysterious ENOENT on the readFile()
120
- console.warn("plugin's repo check failed", e)
120
+ console.warn("Plugin's repo check failed", e)
121
}
122
// ready to replace
123
const wasRunning = isPluginRunning(folder)
@@ -130,10 +130,10 @@ export async function downloadPlugin(repo: Repo, { branch='', overwrite=false }=
130
const deleteMe = installPath + DELETE_ME_SUFFIX
131
await retry(() => rename(installPath, deleteMe).then(() => 1, (e: any) => {
132
if (e.code === 'ENOENT') return 1 // nothing to do
133
- console.warn("error renaming old plugin folder:", String(e))
133
+ console.warn("Error renaming old plugin folder:", String(e))
134
}))
135
await retry(() => rm(deleteMe, { recursive: true, force: true /*ignore ENOENT*/ }).then(() => 1, e => {
136
- console.warn("error deleting old plugin folder:", String(e))
136
+ console.warn("Error deleting old plugin folder:", String(e))
137
}))
138
// final replace
139
await rename(tempInstallPath, installPath)
@@ -318,7 +318,7 @@ export const getProjectInfo = debounceAsync(async () => {
318
const black = onlyTruthy(Object.keys(obj.repo_blacklist || {}).map(findPluginByRepo))
319
blacklistedInstalledPlugins = onlyTruthy(black.map(x => _.isString(x.repo) && x.repo))
320
if (black.length) {
321
- console.log("blacklisted plugins found:", black.join(', '))
321
+ console.log("Blacklisted plugins found:", black.join(', '))
322
for (const p of black)
323
enablePlugin(p.id, false)
324
}
src/i18n.ts
+2
-2
@@ -45,7 +45,7 @@ export function i18nFromTranslations(translations: Record<string, any>, embedded
45
if (found) break
46
if (!warns.has(key) && langs.length && langs[0] !== embedded) {
47
warns.add(key)
48
- console.debug("miss i18n:", key)
48
+ console.debug("i18n miss:", key)
49
}
50
}
51
if (!found) {
@@ -106,7 +106,7 @@ export function i18nFromTranslations(translations: Record<string, any>, embedded
106
ofs++
107
}
108
if (stack)
109
- return console.debug('tokenizer: unclosed') // invalid, abort
109
+ return console.debug('Tokenizer: unclosed') // invalid, abort
110
yield [s.slice(open + 1, ofs-1), true]
111
}
112
yield [s.slice(ofs), false]
src/index.ts
+2
-2
@@ -68,12 +68,12 @@ function errorHandler(err: Error & { code?: string, path?: string }) {
68
|| code === 'ERR_STREAM_WRITE_AFTER_END' // happens disconnecting uploads, don't care
69
|| code === 'ERR_STREAM_PREMATURE_CLOSE' // happens when many files are sent (not locally), but I checked that the files are written completely. Introduced after node18.5.0 and is thrown by pipeline() used by PUT method handler.
70
|| code?.startsWith('HPE')) return // malformed client/probe HTTP parser errors, not internal failures
71
- console.error('server error', err)
71
+ console.error('Server error', err)
72
}
73
74
process.on('uncaughtException', (err: any) => {
75
if (err.syscall !== 'watch' && err.code !== 'ECONNRESET' && err.code !== 'EIO') // EIO seems to happen when the terminal is closed
76
- try { console.error("uncaught:", err) }
76
+ try { console.error("Uncaught:", err) }
77
catch {} // in case we are writing to a closed terminal, we may throw with "write eio at afterwritedispatched", causing an infinite loop
78
})
79
// this warning is scaring users, and has been removed in node 20.12.0 https://github.com/nodejs/node/pull/51204
src/listen.ts
+9
-9
@@ -89,14 +89,14 @@ export function openAdmin() {
89
const baseUrl = `${srv!.name}://${hostname}:${a.port}`
90
open(baseUrl + ADMIN_URI, { wait: true}).catch(async e => {
91
console.debug(String(e))
92
- console.warn("cannot launch browser on this machine >PLEASE< open your browser and reach one of these (you may need a different address)",
92
+ console.warn("Cannot launch browser on this machine >PLEASE< open your browser and reach one of these (you may need a different address)",
93
...Object.values(await getUrls()).flat().map(x => '\n - ' + x + ADMIN_URI))
94
if (! anyAccountCanLoginAdmin())
95
consoleHint(`you can enter this command: create-admin YOUR_PASSWORD`)
96
})
97
return true
98
}
99
- console.log("openAdmin failed")
99
+ console.log("OpenAdmin failed")
100
}
101
102
export function getCertObject() {
@@ -131,7 +131,7 @@ const considerHttps = debounceAsync(async () => {
131
if (certObj) {
132
const cn = certObj.subject?.CN
133
if (cn)
134
- console.log("certificate loaded for", certObj.altNames?.join(' + ') || cn)
134
+ console.log("Certificate loaded for", certObj.altNames?.join(' + ') || cn)
135
const now = new Date()
136
const from = new Date(certObj.validFrom)
137
const to = new Date(certObj.validTo)
@@ -158,7 +158,7 @@ const considerHttps = debounceAsync(async () => {
158
catch(e: any) {
159
httpsSrv ||= Object.assign(https.createServer({}), { name: 'https' }) // a dummy container, in case creation failed because of certificate errors
160
httpsSrv.error = "bad private key or certificate"
161
- console.error("failed to create https server: check your private key and certificate", e.message)
161
+ console.error("Failed to create https server: check your private key and certificate", e.message)
162
return
163
}
164
httpsSrv.on('connection', newConnection) // this event is emitted as soon as the tcp layer is connected
@@ -215,12 +215,12 @@ export function startServer(srv: typeof httpSrv, { port, host }: StartServer) {
215
srv.on('checkContinue', (req, res) => srv.emit('request', req, res))
216
port = await listen(host)
217
if (port)
218
- console.log(srv.name, "serving on", renderHost(host || ''), ':', port)
218
+ console.log(srv.name, "Serving on", renderHost(host || ''), ':', port)
219
resolve(port)
220
}
221
catch(e) {
222
srv.error = String(e)
223
- console.error(srv.name, `couldn't listen on port ${port}:`, srv.error)
223
+ console.error(srv.name, `Couldn't listen on port ${port}:`, srv.error)
224
resolve(0)
225
}
226
})
@@ -273,10 +273,10 @@ export function stopServer(srv?: http.Server) {
273
return resolve(null)
274
const ad = srv.address()
275
if (ad && typeof ad !== 'string')
276
- console.log("stopped port", ad.port)
276
+ console.log("Stopped port", ad.port)
277
srv.close(err => {
278
if (err && (err as any).code !== 'ERR_SERVER_NOT_RUNNING')
279
- console.debug("failed to stop server", String(err))
279
+ console.debug("Failed to stop server", String(err))
280
resolve(err)
281
})
282
srv.closeAllConnections()
@@ -343,5 +343,5 @@ export async function getUrls() {
343
function printUrls(srvName: string) {
344
getUrls().then(urls =>
345
_.each(urls[srvName], url =>
346
- console.log('serving on', url)))
346
+ console.log('Serving on', url)))
347
}
src/log.ts
+4
-4
@@ -37,7 +37,7 @@ class Logger {
37
}
38
catch {
39
if (await ensureParentFolder(path) === false)
40
- console.log("cannot create folder for", path)
40
+ console.log("Cannot create folder for", path)
41
}
42
this.reopen()
43
}
@@ -54,13 +54,13 @@ const accessErrorLog = new Logger(CFG.error_log)
54
export const loggers = [accessLogger, accessErrorLog]
55
56
defineConfig(accessLogger.name, 'logs/access.log').sub(path => {
57
- console.debug('access log file: ' + (path || 'disabled'))
57
+ console.debug('Access log file: ' + (path || 'disabled'))
58
accessLogger.setPath(path)
59
})
60
61
const errorLogFile = defineConfig(accessErrorLog.name, 'logs/access-error.log')
62
errorLogFile.sub(path => {
63
- console.debug('access error log: ' + (path || 'disabled'))
63
+ console.debug('Access error log: ' + (path || 'disabled'))
64
accessErrorLog.setPath(path)
65
})
66
@@ -204,4 +204,4 @@ debugLogFile.once('open', () => {
204
renameSync(path, 'old-' + path)
205
debugLogFile = createWriteStream(path) // new file
206
})
207
-}).on('error', () => console.log("cannot create debug.log"))
207
+}).on('error', () => console.log("Cannot create debug.log"))
src/middlewares.ts
+1
-1
@@ -143,7 +143,7 @@ export function failAllowNet(ctx: Koa.Context, a: Account | undefined) {
143
ctx.session.allowNet = mask // must be deleted on logout by setLoggedIn
144
const ret = mask && !netMatches(ctx.ip, mask, true)
145
if (ret)
146
- console.debug("login failed: allow_net")
146
+ console.debug("Login failed: allow_net")
147
return ret
148
}
149
src/misc.ts
+1
-1
@@ -68,7 +68,7 @@ export function makeNetMatcher(mask: string, emptyMaskReturns=false) {
68
return (ip: string) => {
69
try { return neg !== bl.check(parseAddress(ip)) }
70
catch {
71
- console.error("invalid address ", ip)
71
+ console.error("Invalid address ", ip)
72
return false
73
}
74
}
src/nat.ts
+4
-4
@@ -31,8 +31,8 @@ const originalMethod = upnpClient.getGateway
31
// other client methods call getGateway too, so this will ensure they reuse this same result
32
upnpClient.getGateway = debounceAsync(() => originalMethod.apply(upnpClient), { retain: HOUR, retainFailure: 30_000 })
33
upnpClient.getGateway().then(res => {
34
- console.log("upnp found", res.gateway.description)
35
-}, e => console.debug('upnp failed:', e.message || String(e)))
34
+ console.log("UPnP found", res.gateway.description)
35
+}, e => console.debug('UPnP failed:', e.message || String(e)))
36
37
// poll external ip – asking the modem is cheap, so it can be done often
38
repeat(MINUTE, () => upnpClient.getPublicIp().then(v => {
@@ -48,7 +48,7 @@ export const getPublicIps = debounceAsync(async () => {
48
Promise.any(singleVersion.map(async (svc: any) => {
49
if (typeof svc === 'string')
50
svc = { type: 'http', url: svc }
51
- console.debug("trying ip service", svc.url || svc.name)
51
+ console.debug("Trying ip service", svc.url || svc.name)
52
if (svc.type === 'http') {
53
const timeout = 5_000
54
return httpString(svc.url, { timeout, proxy: '' }).catch(e => { // first try without a proxy
@@ -74,7 +74,7 @@ export const getNatInfo = debounceAsync(async () => {
74
const res = await haveTimeout(10_000, upnpClient.getGateway()).catch(() => null)
75
const status = await getServerStatus()
76
const mappings = res && await haveTimeout(5_000, upnpClient.getMappings()).catch(() => null)
77
- console.debug("mappings found:", mappings?.map(x => x.description).join(', ') || "none")
77
+ console.debug("Mappings found:", mappings?.map(x => x.description).join(', ') || "none")
78
const localIps = await getIps(false)
79
const gatewayIp = await gatewayIpPromise
80
const localIp = res?.address || (gatewayIp ? _.maxBy(localIps, x => inCommon(x, gatewayIp)) : localIps[0])
src/outboundProxy.ts
+4
-4
@@ -11,12 +11,12 @@ const outboundProxy = defineConfig(CFG.outbound_proxy, '', v => {
11
httpStream.defaultProxy = v
12
if (!v || process.env.HFS_SKIP_PROXY_TEST) return
13
const test = 'https://google.com'
14
- console.debug("testing proxy using", test)
14
+ console.debug("Testing proxy using", test)
15
httpString(test, { noRedirect: true }).catch(e =>
16
- console.error(`proxy test failed on ${test} : ${e?.errors?.[0] || e}`)) // `.errors` in case of AggregateError
16
+ console.error(`Proxy test failed on ${test} : ${e?.errors?.[0] || e}`)) // `.errors` in case of AggregateError
17
}
18
catch {
19
- console.warn("invalid URL", v)
19
+ console.warn("Invalid URL", v)
20
return ''
21
}
22
})
@@ -34,5 +34,5 @@ configReady.then(async ([startedWithoutConfig]) => {
34
|| !read.includes('=') && 'http://' + read // simpler form
35
if (!url) return
36
outboundProxy.set(url)
37
- console.log("detected proxy", read)
37
+ console.log("Detected proxy", read)
38
})
\ No newline at end of file
src/perm.ts
+4
-4
@@ -73,7 +73,7 @@ createAdminConfig.sub(v => {
73
74
export async function createAdmin(password: string, username='admin') {
75
const acc = await addAccount(username, { admin: true, password }, true)
76
- console.log(acc ? "account admin set" : "something went wrong")
76
+ console.log(acc ? "Account admin set" : "Something went wrong")
77
}
78
79
const srp6aNimbusRoutines = new SRPRoutines(new SRPParameters())
@@ -94,7 +94,7 @@ export async function updateAccount(account: Account, change: Partial<Account> |
94
if (!v) delete account[k] // we consider all account fields, when falsy, as equivalent to be missing (so, default value applies)
95
const { username, password } = account
96
if (password) {
97
- console.debug('hashing password for', username)
97
+ console.debug('Hashing password for', username)
98
delete account.password
99
const res = await createVerifierAndSalt(srp6aNimbusRoutines, username, password)
100
saveSrpInfo(account, res.s, res.v)
@@ -103,7 +103,7 @@ export async function updateAccount(account: Account, change: Partial<Account> |
103
account.belongs = wantArray(account.belongs)
104
_.remove(account.belongs, b => {
105
if (accounts.get().hasOwnProperty(b)) return
106
- console.error(`account ${username} belongs to non-existing ${b}`)
106
+ console.error(`Account ${username} belongs to non-existing ${b}`)
107
return true
108
})
109
if (!account.belongs.length)
@@ -245,4 +245,4 @@ declare module "koa" {
245
interface DefaultState {
246
usernames?: Set<string>
247
}
248
-}
\ No newline at end of file
248
+}
src/plugins.ts
+17
-17
@@ -64,7 +64,7 @@ export function enablePlugin(id: string, state=true) {
64
enablePlugins.set(arr => {
65
if (arr.includes(id) === state)
66
return arr
67
- console.log("switching plugin", id, state ? "on" : "off")
67
+ console.log("Switching plugin", id, state ? "on" : "off")
68
return arr.includes(id) === state ? arr
69
: state ? [...arr, id]
70
: arr.filter((x: string) => x !== id)
@@ -192,7 +192,7 @@ export const pluginsMiddleware: Koa.Middleware = async (ctx, next) => {
192
ctx.stop()
193
// don't just check ctx.isStopped, as the async plugin that called ctx.stop will reach here after sync ones
194
if (ctx.isStopped && !ctx.pluginBlockedRequest)
195
- console.debug("plugin blocked request", ctx.pluginBlockedRequest = id)
195
+ console.debug("Plugin blocked request", ctx.pluginBlockedRequest = id)
196
if (typeof res === 'function')
197
after[id] = res
198
}
@@ -228,13 +228,13 @@ export const pluginsMiddleware: Koa.Middleware = async (ctx, next) => {
228
229
function printChange(id: string) {
230
if (id === SERVER_CODE_ID || (lastStatus === ctx.status && lastBody === ctx.body)) return
231
- console.debug("plugin changed response:", id)
231
+ console.debug("Plugin changed response:", id)
232
lastStatus = ctx.status
233
lastBody = ctx.body
234
}
235
236
function printError(id: string, e: any) {
237
- console.log(`error middleware plugin ${id}: ${e?.message || e}`)
237
+ console.log(`Error middleware plugin ${id}: ${e?.message || e}`)
238
console.debug(e)
239
}
240
}
@@ -270,7 +270,7 @@ export class Plugin implements CommonPluginInterface {
270
data[k] = [v]
271
else if (v && !Array.isArray(v)) {
272
delete data[k]
273
- console.warn('invalid', k)
273
+ console.warn('Invalid', k)
274
}
275
}
276
plugins.set(id, this)
@@ -323,11 +323,11 @@ export class Plugin implements CommonPluginInterface {
323
const { id } = this
324
try { await this.data?.unload?.() }
325
catch(e) {
326
- console.log('error unloading plugin', id, String(e))
326
+ console.log('Error unloading plugin', id, String(e))
327
}
328
await this.onUnload()
329
if (!reloading && id !== SERVER_CODE_ID) // we already printed 'reloading'
330
- console.log('unloaded plugin', id)
330
+ console.log('Unloaded plugin', id)
331
if (this.data)
332
this.data.unload = undefined
333
}
@@ -355,7 +355,7 @@ export function mapPlugins<T>(cb:(plugin:Readonly<Plugin>, pluginName:string, id
355
if (!includeServerCode && plName === SERVER_CODE_ID) return
356
try { return cb(pl,plName,i++) }
357
catch(e) {
358
- console.log('plugin error', plName, String(e))
358
+ console.log('Plugin error', plName, String(e))
359
}
360
}).filter(x => x !== undefined) as Exclude<T,undefined>[]
361
}
@@ -369,7 +369,7 @@ export function firstPlugin<T>(cb:(plugin:Readonly<Plugin>, pluginName:string)=>
369
return ret
370
}
371
catch(e) {
372
- console.log('plugin error', plName, String(e))
372
+ console.log('Plugin error', plName, String(e))
373
}
374
}
375
}
@@ -420,7 +420,7 @@ export const PLUGIN_MAIN_FILE = 'plugin.js'
420
const pluginWatchers = new Map<string, ReturnType<typeof watchPlugin>>()
421
422
export async function rescan() {
423
- console.debug('scanning plugins')
423
+ console.debug('Scanning plugins')
424
const patterns = [PATH + '/*']
425
if (APP_PATH !== process.cwd())
426
patterns.unshift(escapeGlobPath(APP_PATH) + '/' + patterns[0]) // first search bundled plugins, because otherwise they won't be loaded because of the folders with same name in .hfs/plugins (used for storage)
@@ -442,7 +442,7 @@ export async function rescan() {
442
}
443
444
function watchPlugin(id: string, path: string) {
445
- console.debug('plugin watch', id)
445
+ console.debug('Plugin watch', id)
446
const module = resolve(path)
447
let starting: PendingPromise | undefined
448
const unsub = subMultipleConfigs(() => {
@@ -465,7 +465,7 @@ function watchPlugin(id: string, path: string) {
465
events.emit(notRunning ? 'pluginUpdated' : 'pluginInstalled', p)
466
})
467
return () => {
468
- console.debug('plugin unwatch', id)
468
+ console.debug('Plugin unwatch', id)
469
unsub()
470
unwatch()
471
return onUninstalled()
@@ -509,7 +509,7 @@ function watchPlugin(id: string, path: string) {
509
if (getPluginInfo(id))
510
setError(id, '')
511
const alreadyRunning = plugins.get(id)
512
- console.log(alreadyRunning ? "reloading plugin" : "loading plugin", id)
512
+ console.log(alreadyRunning ? "Reloading plugin" : "Loading plugin", id)
513
const pluginData = require(module)
514
deleteModule(require.resolve(module)) // avoid caching at next import
515
calculateBadApi(pluginData)
@@ -517,7 +517,7 @@ function watchPlugin(id: string, path: string) {
517
throw Error(pluginData.badApi)
518
519
await alreadyRunning?.unload(true)
520
- console.debug("starting plugin", id)
520
+ console.debug("Starting plugin", id)
521
const storageDir = resolve(PATH, id, STORAGE_FOLDER) + (IS_WINDOWS ? '\\' : '/')
522
await mkdir(storageDir, { recursive: true })
523
const openDbs: KvStorage[] = []
@@ -536,7 +536,7 @@ function watchPlugin(id: string, path: string) {
536
return db
537
},
538
log(...args: any[]) {
539
- console.log('plugin', id+':', ...args)
539
+ console.log('Plugin', id+':', ...args)
540
pluginReady.then(() => { // log() maybe invoked during init(), while plugin is undefined
541
if (!plugin) return
542
const msg = { ts: new Date, msg: args.map(x => x && typeof x === 'object' ? JSON.stringify(x) : String(x)).join(' ') }
@@ -626,7 +626,7 @@ function setError(id: string, error: string) {
626
info.error = error
627
events.emit('pluginUpdated', info)
628
if (!error) return
629
- console.warn(`plugin error: ${id}:`, error)
629
+ console.warn(`Plugin error: ${id}:`, error)
630
return true
631
}
632
@@ -663,7 +663,7 @@ export function parsePluginSource(id: string, source: string) {
663
pl.preview = tryJson(/exports.preview\s*=\s*("(?:[^"\\]|\\.)*"|\[[\s\S]*?\])/.exec(source)?.[1]) ?? undefined
664
pl.depend = tryJson(/exports.depend\s*=\s*(\[[\s\S]*?])/m.exec(source)?.[1])?.filter((x: any) =>
665
typeof x.repo === 'string' && x.version === undefined || typeof x.version === 'number'
666
- || console.warn("plugin dependency discarded", x) )
666
+ || console.warn("Plugin dependency discarded", x) )
667
pl.changelog = tryJson(/exports.changelog\s*=\s*(\[[\s\S]*?])/m.exec(source)?.[1])
668
if (Array.isArray(pl.apiRequired) && (pl.apiRequired.length !== 2 || !pl.apiRequired.every(_.isFinite))) // validate [from,to] form
669
pl.apiRequired = undefined
src/selfCheck.ts
+2
-2
@@ -33,7 +33,7 @@ export async function selfCheck(url: string) {
33
regexpSuccess: string
34
}
35
const prjInfo = await getProjectInfo()
36
- console.log(`checking server ${url}`)
36
+ console.log(`Checking server ${url}`)
37
const parsed = new URL(url)
38
const family = !isIP(parsed.hostname) ? undefined : isIPv6(parsed.hostname) ? 6 : 4
39
try {
@@ -44,7 +44,7 @@ export async function selfCheck(url: string) {
44
if (!svc.url || svc.type) throw 'unsupported ' + svc.type // only default type supported for now
45
let { url: serviceUrl, body, regexpSuccess, regexpFailure, ...rest } = svc
46
const service = new URL(serviceUrl).hostname
47
- console.log('trying external service', service)
47
+ console.log('Trying external service', service)
48
console.debug(svc)
49
body = applySymbols(body)
50
serviceUrl = applySymbols(serviceUrl)!
src/serveGuiAndSharedFiles.ts
+2
-2
@@ -180,9 +180,9 @@ async function calcHash(fn: string, limit=Infinity) {
180
}
181
})
182
fs.createReadStream(fn, { end: limit - 1 }).pipe(stream)
183
- console.debug('hashing', fn)
183
+ console.debug('Hashing', fn)
184
await once(stream, 'finish')
185
- console.debug('hashed', fn)
185
+ console.debug('Hashed', fn)
186
return hash.digest().toString(16)
187
}
188
src/serveGuiFiles.ts
+1
-1
@@ -182,7 +182,7 @@ function serializeCss(v: any) {
182
function serveProxied(port: string | undefined, uri: string) { // used for development only
183
if (!port)
184
return
185
- console.debug('proxied on port', port)
185
+ console.debug('Proxied on port', port)
186
let proxy: Koa.Middleware
187
import('koa-better-http-proxy').then(lib => // dynamic import to avoid having this in final distribution
188
proxy = lib.default('127.0.0.1:'+port, {
src/update.ts
+10
-10
@@ -35,10 +35,10 @@ configReady.then(lastCheckUpdate.ready).then(() => repeat(HOUR, () => {
35
}))
36
37
export const checkForUpdates = debounceAsync(async () => {
38
- console.log("checking for updates")
38
+ console.log("Checking for updates")
39
try {
40
const u = await getBestUpdate()
41
- if (u) console.log("new version available", u.name)
41
+ if (u) console.log("New version available", u.name)
42
autoCheckUpdateResult.set(u)
43
lastCheckUpdate.set(Date.now())
44
}
@@ -86,7 +86,7 @@ export async function getVersions(interrupt?: (r: Release) => boolean) {
86
}
87
88
export async function getUpdates(strict=false) {
89
- console.log("checking for updates")
89
+ console.log("Checking for updates")
90
void getProjectInfo() // also check for alerts and print them asap in the console
91
const stable: Release = prepareRelease(await getRepoInfo(HFS_REPO + '/releases/latest'))
92
const res = await getVersions(r => r.versionScalar < stable.versionScalar) // we don't consider betas before stable
@@ -125,7 +125,7 @@ export async function update(tagOrUrl: string='') {
125
tagOrUrl = 'v' + tagOrUrl
126
const update = !tagOrUrl ? await getBestUpdate()
127
: await getRepoInfo(HFS_REPO + '/releases/tags/' + tagOrUrl).catch(e => {
128
- if (e.message === '404') console.error("version not found")
128
+ if (e.message === '404') console.error("Version not found")
129
else throw e
130
}) as Release | undefined
131
if (!update)
@@ -140,7 +140,7 @@ export async function update(tagOrUrl: string='') {
140
url = asset.browser_download_url
141
}
142
if (url) {
143
- console.log("downloading", url)
143
+ console.log("Downloading", url)
144
const temp = LOCAL_UPDATE + '-temp'
145
await rm(temp, { force: true })
146
try {
@@ -151,7 +151,7 @@ export async function update(tagOrUrl: string='') {
151
throw "Download failed for " + url + prefix(' – ', e?.message)
152
}
153
await rename(temp, LOCAL_UPDATE)
154
- console.debug("download finished")
154
+ console.debug("Download finished")
155
}
156
const bin = process.execPath
157
const binPath = dirname(bin)
@@ -181,10 +181,10 @@ export async function update(tagOrUrl: string='') {
181
try { unlinkSync(oldBin) }
182
catch {}
183
renameSync(bin, oldBin)
184
- console.log("launching new version in background", newBinFile)
184
+ console.log("Launching new version in background", newBinFile)
185
spawnSync(cmdEscape(newBin), ['--updating', binFile, '--cwd .'], { shell: true, stdio: [0,1,2] }) // sync necessary to work on Mac by double-click
186
})
187
- console.log("quitting")
187
+ console.log("Quitting")
188
setTimeout(() => process.exit()) // give time to return (and caller to complete, eg: rest api to reply)
189
}
190
catch (e: any) {
@@ -198,7 +198,7 @@ if (argv.updating) { // we were launched with a temporary name, restore original
198
const dest = join(dirname(bin), argv.updating)
199
renameSync(bin, dest)
200
// have to relaunch with the new name, or otherwise the next update will fail with EBUSY on hfs.exe
201
- console.log(`renamed binary file to "${argv.updating}" and now restarting`)
201
+ console.log(`Renamed binary file to "${argv.updating}" and now restarting`)
202
// if you change anything, be sure to test launching both double-clicking and in a terminal
203
if (IS_WINDOWS) // windows-only; this method on mac+linux works only once, and without the console
204
onProcessExit(() =>
@@ -209,7 +209,7 @@ if (argv.updating) { // we were launched with a temporary name, restore original
209
// For the record, on mac you can: write "./hfs arg1 arg2" to /tmp/tmp.sh with 0o700, and then spawn "open -a Terminal /tmp/tmp.sh"
210
try { writeFileSync(ARGS_FILE, JSON.stringify(['--updated', '--cwd', process.cwd()])) }
211
catch {}
212
- console.log('open-ing')
212
+ console.log('Open-ing')
213
void open(dest)
214
}
215
else { // linux and other *nix
src/upload.ts
+7
-7
@@ -33,7 +33,7 @@ const waitingToBeDeleted: Record<string, {
33
}> = {}
34
onProcessExit(() => {
35
if (!Object.keys(waitingToBeDeleted).length) return
36
- console.log("removing unfinished uploads")
36
+ console.log("Removing unfinished uploads")
37
for (const path in waitingToBeDeleted)
38
try { fs.rmSync(path, { force: true }) }
39
catch {}
@@ -97,7 +97,7 @@ export function uploadWriter(base: VfsNode, baseUri: string, filename: string, c
97
return fail(HTTP_INSUFFICIENT_STORAGE)
98
}
99
catch(e: any) { // warn, but let it through
100
- console.warn("can't check disk size:", e.message || String(e))
100
+ console.warn("Can't check disk size:", e.message || String(e))
101
}
102
// optionally 'skip'
103
if (ctx.query.existing === 'skip' && fs.existsSync(fullPath))
@@ -154,14 +154,14 @@ export function uploadWriter(base: VfsNode, baseUri: string, filename: string, c
154
cancelDeletion(tempName)
155
const tracked = { ctx, got: 0, size: stillToWrite }
156
uploadingFiles.set(fullPath, tracked)
157
- console.debug('upload started')
157
+ console.debug('Upload started')
158
// the file stream doesn't have an event for data being written, so we use 'data' of its feeder, which happens before, so we postpone a bit, trying to have a fresher number
159
writeStream.on('data', () => setTimeout(() => tracked.got = bytesGot()))
160
161
const lockMiddleware = pendingPromise<string>() // expose outside, to let know when all operations stopped
162
let errored: any
163
fileStream.on('error', (e: any) => {
164
- console.warn('file error while uploading', filename, ':', e.message)
164
+ console.warn('File error while uploading', filename, ':', e.message)
165
errored = e
166
fail(HTTP_SERVER_ERROR, e.code) // don't send e.message as it may contain a disk paths we don't want to leak
167
})
@@ -207,14 +207,14 @@ export function uploadWriter(base: VfsNode, baseUri: string, filename: string, c
207
void setCommentFor(dest, String(ctx.query.comment))
208
obj.uri = enforceFinal('/', baseUri) + pathEncode(basename(dest))
209
events.emit('uploadFinished', obj)
210
- console.debug("upload finished", dest)
210
+ console.debug("Upload finished", dest)
211
if (resEvent) for (const cb of resEvent)
212
if (_.isFunction(cb))
213
cb(obj)
214
}
215
catch (err: any) {
216
void setUploadMeta(tempName, ctx)
217
- console.error("couldn't rename temp to", dest, String(err))
217
+ console.error("Couldn't rename temp to", dest, String(err))
218
}
219
}
220
finally {
@@ -284,7 +284,7 @@ export function uploadWriter(base: VfsNode, baseUri: string, filename: string, c
284
}
285
286
function fail(status=ctx.status, msg?: string) {
287
- console.debug('upload failed', status, msg||'')
287
+ console.debug('Upload failed', status, msg||'')
288
ctx.status = status
289
if (msg)
290
ctx.body = msg
src/util-files.ts
+2
-2
@@ -38,7 +38,7 @@ export async function readFileWithBusyRetry(path: string): Promise<string> {
38
return readFile(path, 'utf8').catch(e => {
39
if ((e as any)?.code !== 'EBUSY')
40
throw e
41
- console.debug('busy')
41
+ console.debug('Busy')
42
return wait(100).then(()=> readFileWithBusyRetry(path))
43
})
44
}
@@ -103,7 +103,7 @@ export async function unzip(stream: Readable, cb: (path: string) => Promisable<f
103
const dest = await try_(() => cb(path), e => console.warn(String(e)))
104
if (!dest || type !== 'File')
105
return entry.autodrain()
106
- console.debug('unzip', dest)
106
+ console.debug('Unzip', dest)
107
const thisFile = entry.pipe(await createSafeWriteStream(dest))
108
await once(thisFile, 'finish')
109
}) )
src/util-http.ts
+3
-3
@@ -74,7 +74,7 @@ export function httpStream(url: string, { body, proxy, jar, noRedirect, httpThro
74
75
const proto = options.protocol === 'https:' ? https : http
76
const req = proto.request(options, res => {
77
- console.debug("http responded", res.statusCode, "to", url)
77
+ console.debug("HTTP responded", res.statusCode, "to", url)
78
if (hostJar) for (const entry of res.headers['set-cookie'] || []) {
79
const [, k, v] = /(.+?)=([^;]+)/.exec(entry) || []
80
if (!k) continue
@@ -101,7 +101,7 @@ export function httpStream(url: string, { body, proxy, jar, noRedirect, httpThro
101
resolve(res)
102
}).on('error', (e: any) => {
103
if (proxy && e?.code === 'ECONNREFUSED')
104
- console.debug("cannot connect to proxy ", proxy)
104
+ console.debug("Cannot connect to proxy ", proxy)
105
e.cause ??= req // enrich the error
106
reject(e)
107
})
@@ -126,7 +126,7 @@ export function httpStream(url: string, { body, proxy, jar, noRedirect, httpThro
126
options.createConnection = () => tls.connect({ socket, servername: parsed.hostname || undefined })
127
resolve(true)
128
}).on('response', res => {
129
- console.debug("proxy CONNECT response", res.statusCode, res.statusMessage)
129
+ console.debug("Proxy CONNECT response", res.statusCode, res.statusMessage)
130
resolve(false)
131
}).on('error', reject)
132
.end()
src/util-os.ts
+2
-2
@@ -81,10 +81,10 @@ async function getWindowsServicePids() {
81
82
export const RUNNING_AS_SERVICE = detectRunningAsService().then(ret => {
83
if (ret)
84
- console.log("running as service", ret)
84
+ console.log("Running as service", ret)
85
return ret
86
}, e => {
87
- console.log("couldn't determine if we are running as a service")
87
+ console.log("Couldn't determine if we are running as a service")
88
console.debug(e)
89
return false
90
})
src/vfs.ts
+1
-1
@@ -287,7 +287,7 @@ export function statusCodeForMissingPerm(node: VfsNode, perm: keyof VfsPerms, ct
287
if (typeof who !== 'string' || who === WHO_ANY_ACCOUNT)
288
break
289
if (!max--) {
290
- console.error(`endless loop in permission ${perm}=${node[perm] ?? defaultPerms[perm]} for ${node.url || getNodeName(node)}`)
290
+ console.error(`Endless loop in permission ${perm}=${node[perm] ?? defaultPerms[perm]} for ${node.url || getNodeName(node)}`)
291
return HTTP_SERVER_ERROR
292
}
293
cur = who
src/watchLoad.ts
+3
-3
@@ -59,7 +59,7 @@ export function watchLoad(path:string, parser:(data:any)=>void|Promise<void>, {
59
await save.flush() // apply pending saves first
60
const text = await readFileWithBusyRetry(path).catch(e => { // ignore read errors
61
if (e.code === 'EPERM')
62
- console.error("missing permissions on file", path) // warn user, who could be clueless about this problem
62
+ console.error("Missing permissions on file", path) // warn user, who could be clueless about this problem
63
// keep the last good content on transient read failures so we don't apply accidental "empty file" state
64
if (e.code === 'ENOENT')
65
return ''
@@ -69,12 +69,12 @@ export function watchLoad(path:string, parser:(data:any)=>void|Promise<void>, {
69
return
70
last = text
71
emitter.emit('change', last)
72
- console.debug('loaded', path)
72
+ console.debug('Loaded', path)
73
unwatch(); install() // reinstall, as the original file could have been renamed. We watch by the name.
74
await parser(text)
75
}
76
catch(e) {
77
- console.error("error loading", path, String(e))
77
+ console.error("Error loading", path, String(e))
78
}
79
finally {
80
doing = false