Repository navigation
Expand file tree
/
Copy pathindex.js
More file actions
128 lines (105 loc) · 3.07 KB
/
Copy pathindex.js
File metadata and controls
128 lines (105 loc) · 3.07 KB
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
'use strict'
/**
* restana Web Framework implementation
*
* @license MIT
*/
const requestRouter = require('./libs/request-router')
const applySecurityHeaders = require('./libs/security-headers')
const { deepFreezeObject, toHttpStatusCode } = require('./libs/utils')
const exts = {
request: {},
response: require('./libs/response-extensions')
}
module.exports = (options = {}) => {
const config = { ...options }
config.errorHandler =
config.errorHandler ||
((err, req, res) => {
const statusCode = toHttpStatusCode(err.status || err.code || err.statusCode)
res.send({ code: statusCode, message: 'Internal Server Error' }, statusCode)
})
const server = config.server || require('http').createServer()
const prp = config.prioRequestsProcessing ?? true
if (prp) {
server.on('request', (req, res) => {
setImmediate(() => service.handle(req, res))
})
} else {
server.on('request', (req, res) => {
service.handle(req, res)
})
}
const handle = (req, res) => {
// Default security headers (can be overridden by application or disabled via options)
if (config.securityHeaders !== false) {
applySecurityHeaders(config, req, res)
}
// request object population
res.send = exts.response.send(config, req, res)
service.getRouter().lookup(req, res)
}
const service = handle
let frozenConfig = null
const service_ = {
errorHandler: config.errorHandler,
newRouter () {
return requestRouter(config)
},
getServer () {
return server
},
getConfigOptions () {
if (!frozenConfig) {
const copy = { ...config }
// Deep-clone + deep-freeze nested plain objects so the user's originals
// are not mutated as a side effect of calling getConfigOptions().
for (const key of Object.keys(copy)) {
if (key !== 'server') {
copy[key] = deepFreezeObject(copy[key])
}
}
frozenConfig = Object.freeze(copy)
}
return frozenConfig
},
handle,
start: (...args) =>
new Promise((resolve, reject) => {
if (!args.length) args = [3000]
const onError = (err) => {
server.removeListener('listening', onListening)
reject(err)
}
const onListening = () => {
server.removeListener('error', onError)
resolve(server)
}
server.once('error', onError)
server.once('listening', onListening)
try {
server.listen(...args)
} catch (err) {
server.removeListener('error', onError)
server.removeListener('listening', onListening)
reject(err)
}
}),
close: () =>
new Promise((resolve, reject) => {
try {
server.close((err) => {
if (err) return reject(err)
resolve()
})
} catch (err) {
reject(err)
}
})
}
Object.assign(service, service_)
// apply router capabilities
requestRouter(config, service)
service.callback = () => service.handle
return service
}