-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
95 lines (84 loc) · 2.5 KB
/
index.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
const { Server, STATUS_CODES } = require('http');
const { EventEmitter } = require('events');
const { AsyncLocalStorage } = require('async_hooks');
const asyncLocalStorage = new AsyncLocalStorage();
class Application extends EventEmitter {
static NOT_FOUND_ROUTE = '__NOT_FOUND_ROUTE__';
constructor(options) {
super({
captureRejections: true,
...options
});
this._server = new Server();
}
[Symbol.for('nodejs.rejection')](error) {
const context = asyncLocalStorage.getStore();
this.handleError(context, error);
}
hasListeners(eventName) {
return this.listenerCount(eventName) > 0;
}
handleError(context, error) {
context.error = error;
if (this.hasListeners('error')) {
this.emit('error', context);
} else {
const status = error.statusCode || error.status || 500;
const statusMessage = STATUS_CODES[status];
const message = error.message || statusMessage;
context.res.statusCode = status;
context.res.end(message);
}
}
onRequest = (req, res) => {
const context = { req, res };
asyncLocalStorage.run(context, () => {
try {
const { pathname } = new URL(req.url, 'http://localhost')
const eventName = req.method.toUpperCase() + ' ' + pathname;
if (this.hasListeners(eventName)) {
this.emit(eventName, context);
} else {
if (this.hasListeners(Application.NOT_FOUND_ROUTE)) {
this.emit(Application.NOT_FOUND_ROUTE, context);
} else {
const notFoundError = new Error('Not Found');
notFoundError.name = 'NotFound';
notFoundError.status = notFoundError.statusCode = 404;
throw notFoundError;
}
}
} catch (error) {
this.handleError(context, error);
}
});
}
listen(...args) {
this._server.on('request', this.onRequest);
this._server.listen(...args);
}
close(callback) {
return new Promise((resolve, reject) => {
this._server.off('request', this.onRequest);
this._server.close((error) => {
if (error) {
reject(error);
callback && callback(error);
} else {
resolve();
callback && callback();
}
})
})
}
}
async function parseBody(req) {
const body = [];
for await (const chunk of req) {
body.push(chunk);
}
return Buffer.concat(body).toString();
};
module.exports = Application;
module.exports.Application = Application;
module.exports.parseBody = parseBody;