https support
Massimo Melina committed
Jan 18, 2022 at 18:42 UTC
0b1728c0f151edd5e0eb3c3b3059149c29f9e4fc
4 files changed
+87
-21
README.md
+7
@@ -12,6 +12,7 @@ This is a full rewrite of [the Delphi version](https://github.com/rejetto/hfs2).
12
You won't find all previous features here (yet), but still we got:
13
14
# Features
15
+- https
16
- unicode
17
- virtual file system
18
- mobile friendly front-end
@@ -45,6 +46,12 @@ Supported entries are:
46
You can use the special value `auto` to attempt automatic detection.
47
- `max_kbps` throttle output speed. Default is Infinity.
48
- `max_kbps_per_ip` throttle output speed on a per-ip basis. Default is Infinity.
49
+- `zip-calculate-size-for-seconds` how long should we wait before the zip archive starts streaming, trying to understand its finale size. Default is 1.
50
+- `open_browser_at_start` should HFS open browser on localhost on start? Default is true.
51
+- `https_port` listen on a specific port. Default is 443.
52
+- `cert` use this file for https certificate. Minimum to start https is to give a cert and a private_key. Default is none.
53
+- `private_key` use this file for https private key. Default is none.
54
+- `plugins_config`
55
56
## Virtual File System (VFS)
57
config.yaml
+3
@@ -5,6 +5,9 @@
5
#error_log:
6
#zip-calculate-size-for-seconds: 1
7
#open_browser_at_start: false
8
+#https_port: 443
9
+#cert: filepath
10
+#private_key: filepath
11
mime:
12
"*.jpg|*.png|*.mp3|*.txt": auto
13
disable_plugins: [ 'theme-example', 'middleware-example', 'download-counter' ]
src/listen.ts
+76
-19
@@ -1,37 +1,94 @@
1
-import { Server } from 'http'
1
+import * as http from 'http'
2
import { getConfig, subscribeConfig } from './config'
3
import open from 'open'
4
import { app } from './index'
5
+import * as https from 'https'
6
+import { watchLoad } from './watchLoad'
7
6
-let srv: Server
8
let firstTime = true
9
+let httpSrv: http.Server
10
+let httpsSrv: http.Server
11
+let cert:string, key: string
12
+
13
subscribeConfig({ k:'port', defaultValue: 80 }, async (port: number) => {
9
- await new Promise(resolve => {
10
- if (!srv)
11
- return resolve(null)
12
- srv.close(err => {
13
- if (err && (err as any).code !== 'ERR_SERVER_NOT_RUNNING')
14
- console.debug('failed to stop server', String(err))
15
- resolve(err)
16
- })
14
+ await stopServer(httpSrv)
15
+ httpSrv = http.createServer(app.callback());
16
+ await startServer(httpSrv, port ?? 80)
17
+})
18
+
19
+
20
+subscribeConfig({ k:'cert' }, async (v: string) => {
21
+ await stopServer(httpsSrv)
22
+ cert = v
23
+ if (!cert) return
24
+ if (cert.includes('\n'))
25
+ return considerHttps()
26
+ // it's a path
27
+ watchLoad(cert, data => {
28
+ cert = data
29
+ considerHttps()
30
+ })
31
+ cert = ''
32
+})
33
+
34
+subscribeConfig({ k:'private_key' }, async (v: string) => {
35
+ await stopServer(httpsSrv)
36
+ key = v
37
+ if (!key) return
38
+ if (key.includes('\n'))
39
+ return considerHttps()
40
+ // it's a path
41
+ watchLoad(key, data => {
42
+ key = data
43
+ considerHttps()
44
})
18
- await new Promise(resolve => {
45
+ key = ''
46
+})
47
+
48
+const CFG_HTTPS_PORT = 'https_port'
49
+subscribeConfig({ k:CFG_HTTPS_PORT, defaultValue: 443 }, considerHttps)
50
+
51
+async function considerHttps() {
52
+ if (!cert || !key)
53
+ return stopServer(httpsSrv)
54
+ httpsSrv = https.createServer({ key, cert }, app.callback());
55
+ return await startServer(httpsSrv, getConfig('https_port'), 's')
56
+}
57
+
58
+function startServer(srv: http.Server, port: number, secure:string='') {
59
+ return new Promise((resolve, reject) => {
60
try {
20
- srv = app.listen(port, () => {
21
- console.log('running on port', port)
22
- if (firstTime && getConfig('open_browser_at_start') !== false)
23
- open('http://localhost:'+port)
24
- firstTime = false
61
+ if (port < 0)
62
+ return resolve(null)
63
+ srv.listen(port, () => {
64
+ const proto = 'http' + secure
65
+ console.log(proto + ` serving on port`, port)
66
+ if (firstTime && getConfig('open_browser_at_start') !== false) {
67
+ open(proto + '://localhost:' + port).then()
68
+ firstTime = false
69
+ }
70
resolve(null)
71
}).on('error', e => {
72
const { code } = e as any
28
- if (code === 'EADDRINUSE')
29
- console.error(`couldn't listen on busy port ${port}`)
73
+ console.error(code === 'EADDRINUSE' ? `couldn't listen on busy port ${port}` : e)
74
+ reject(e)
75
})
76
}
77
catch(e) {
78
console.error("couldn't listen on port", port, String(e))
79
+ reject(e)
80
}
81
+ })
82
+}
83
84
+function stopServer(srv: http.Server) {
85
+ return new Promise(resolve => {
86
+ if (!srv?.listening)
87
+ return resolve(null)
88
+ srv.close(err => {
89
+ if (err && (err as any).code !== 'ERR_SERVER_NOT_RUNNING')
90
+ console.debug('failed to stop server', String(err))
91
+ resolve(err)
92
+ })
93
})
37
-})
94
+}
todo.md
+1
-2
@@ -6,10 +6,9 @@
6
- update tests to SRP login
7
- upload
8
- upload unzipping (while streaming?)
9
-- https
9
+- plugin to automatic generate letsencrypt cert?
10
- delete
11
- updater (stop,unzip,start)
12
-- search and login dialogs should push to history so that mobile can use back button to close them
12
- node.comment
13
- config: max connections (total/per-ip)
14
- config: bans