-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.js
147 lines (131 loc) · 4.39 KB
/
server.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import { createServer } from 'http'
import url from 'url'
import path from 'path'
import zlib from 'zlib'
import { pipeline } from 'stream'
import { open } from 'fs/promises'
import { platform } from 'os'
import { exec } from 'child_process'
import WebSocketServer from './node_modules/websocket/lib/WebSocketServer.js'
import { watch } from 'chokidar'
const osPlatform = platform()
const port = 8080
const root = 'www'
const server = createServer(async (request, response) => {
// console.log(`${request.method} ${request.url}`);
if (request.url.endsWith('/')) request.url = '/index.html'
// parse URL
const parsedUrl = url.parse(request.url)
// extract URL path
let pathname = `./${path.join(root, parsedUrl.pathname)}`
// based on the URL path, extract the file extension. e.g. .js, .doc, ...
const ext = path.parse(pathname).ext
// maps file extension to MIME typere
const map = {
'.ico': 'image/x-icon',
'.html': 'text/html',
'.js': 'text/javascript',
'.json': 'application/json',
'.css': 'text/css',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.wav': 'audio/wav',
'.mp3': 'audio/mpeg',
'.svg': 'image/svg+xml',
'.pdf': 'application/pdf',
'.doc': 'application/msword'
}
try {
const fileHandle = await open(pathname)
// read file from file system
const raw = fileHandle.createReadStream()
// Store both a compressed and an uncompressed version of the resource.
response.setHeader('Vary', 'Accept-Encoding')
response.setHeader('Content-type', map[ext] || 'text/plain')
// response.setHeader('Cache-Control', 'max-age=36000')
let acceptEncoding = request.headers['accept-encoding']
if (!acceptEncoding) {
acceptEncoding = ''
}
const onError = (err) => {
if (err) {
// If an error occurs, there's not much we can do because
// the server has already sent the 200 response code and
// some amount of data has already been sent to the client.
// The best we can do is terminate the response immediately
// and log the error.
response.end()
console.error('An error occurred:', err)
}
}
// Note: This is not a conformant accept-encoding parser.
// See https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
if (/\bdeflate\b/.test(acceptEncoding)) {
response.writeHead(200, { 'Content-Encoding': 'deflate' })
pipeline(raw, zlib.createDeflate(), response, onError)
} else if (/\bgzip\b/.test(acceptEncoding)) {
response.writeHead(200, { 'Content-Encoding': 'gzip' })
pipeline(raw, zlib.createGzip(), response, onError)
} else if (/\bbr\b/.test(acceptEncoding)) {
response.writeHead(200, { 'Content-Encoding': 'br' })
pipeline(raw, zlib.createBrotliCompress(), response, onError)
} else {
response.writeHead(200, {})
pipeline(raw, response, onError)
}
} catch (error) {
response.statusCode = 404
response.end(`404: ${pathname} not found`)
}
}).listen(parseInt(port))
console.log(`Server listening on port ${port}`)
const _url = `http://localhost:${port}`
console.log(`opening ${_url}`)
let command
try {
if (osPlatform === 'win32') {
command = `start chrome ${_url}`
} else if (osPlatform === 'darwin') {
command = `open -a "Google Chrome" ${_url}`
} else {
command = `google-chrome --no-sandbox ${_url}`
}
console.log(`executing command: ${command}`)
exec(command)
} catch (error) {
if (osPlatform === 'win32') {
exec(`start microsoft-edge:${_url}`)
} else throw error
}
const wsServer = new WebSocketServer({
httpServer: server,
autoAcceptConnections: false
})
let connection
wsServer.on('request', function (request) {
connection = request.accept('reload-app', request.origin)
console.log(new Date() + ' Connection accepted.')
connection.on('close', function (reasonCode, description) {
console.log(new Date() + ' Peer ' + connection.remoteAddress + ' disconnected.')
})
})
const initWatcher = () => {
try {
const watcher = watch(['./www/**/*.js'])
let timeout
watcher.on('change', () => {
if (timeout) clearTimeout(timeout)
timeout = setTimeout(() => {
// if (connection && connection.connected) {
connection && connection.send('reload')
// }
}, 100)
})
watcher.on('error', (error) => {
console.log(error)
})
} catch (error) {
initWatcher()
}
}
initWatcher()