-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.js
128 lines (115 loc) · 3.98 KB
/
main.js
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
const https = require('https')
const http = require('http')
const fs = require('fs')
const qs = require('querystring')
const path = require('path')
const fsPromises = fs.promises
const location = process.argv[1]
const isDev = (process.argv[2] == '--dev')
if(process.argv[2] != undefined && !isDev) {
/* process.argv[2] is defined and it is not "--dev" */ throw {}
}
let myPath
if(fs.lstatSync(location).isDirectory()) {
myPath = location
} else {
myPath = path.dirname(location)
}
myPath += path.sep
let originalHTML
async function _serveHTML(res, file, dict={}) {
if(originalHTML == undefined || isDev) {
originalHTML = (await fsPromises.readFile(file)).toString()
}
let html = originalHTML
for(const key in dict) {
html = html.replaceAll(`@{${key}}`, dict[key])
}
res.end(html.replace(/@{.*?}/g, ''))
}
function makeSafe(func) {
if(typeof func == 'function') {
return async (serveHTML, data) => {
await func.apply(null, [serveHTML, data])
}
}
return async (serveHTML) => serveHTML()
}
module.exports = function (file, [port, hostname],
/** @type {(serveHTML: Function, data: Record<string, string>) => {}} */ postLoad,
/** @type {(serveHTML: Function) => {}} */ firstLoad,
httpsOptions={key: null, cert: null}
) {
file = myPath + file
hostname ??= 'localhost'
postLoad = makeSafe(postLoad)
firstLoad = makeSafe(firstLoad)
let /** @type {http} */ protocol
if(httpsOptions.key && httpsOptions.cert) {
httpsOptions.key = fs.readFileSync(myPath + httpsOptions.key)
httpsOptions.cert = fs.readFileSync(myPath + httpsOptions.cert)
protocol = https
} else {
protocol = http
}
const otherThanHTML = {}
const server = protocol.createServer(httpsOptions, (req, res) => {
let serveNeeded = true
req.url = req.url.split('?')[0]
if(req.url != '/') {
if(req.url.endsWith('.js') || req.url.endsWith('.mjs')) {
res.setHeader('content-type', 'text/javascript')
}
if(req.url.endsWith('.wasm')) {
res.setHeader('content-type', 'application/wasm')
}
if(otherThanHTML[req.url] && !isDev) {
res.end(otherThanHTML[req.url])
} else {
fsPromises.readFile(path.resolve(file, '..', req.url.substring(1))).then((buffer) => {
res.end(buffer)
otherThanHTML[req.url] = buffer
}).catch((_) => {
fsPromises.readFile(path.resolve(file, '..', req.url.substring(1), 'index.html')).then((buffer) => {
res.end(buffer)
otherThanHTML[req.url] = buffer
}).catch((_) => {
res.writeHead(404)
res.end()
})
})
}
} else {
if(req.method == 'POST') {
let body = ''
req.on('data', chunk => {
body += chunk.toString()
})
req.on('end', () => {
postLoad(dict => {
serveNeeded = false
_serveHTML(res, file, dict)
}, qs.parse(body))
.then(() => {
if(serveNeeded) {
_serveHTML(res, file)
}
})
})
} else if(req.method == 'GET') {
firstLoad(dict => {
serveNeeded = false
_serveHTML(res, file, dict)
})
.then(() => {
if(serveNeeded) {
_serveHTML(res, file)
}
})
}
}
})
server.listen(port, hostname, () => {
console.log(`Listening on ${hostname}:${server.address().port}`)
})
}