@jwn-js/common 2.2.2 → 2.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ApiError.js +37 -1
- package/ApiError.mjs +35 -1
- package/Jwt-B4QZ2Ypb.js +80 -0
- package/Jwt-Be4GWrIO.js +75 -0
- package/Jwt.js +8 -1
- package/Jwt.mjs +2 -1
- package/Memcached.js +166 -9
- package/Memcached.mjs +164 -9
- package/Server.js +316 -1
- package/Server.mjs +313 -1
- package/cookieParse.js +25 -1
- package/cookieParse.mjs +23 -1
- package/cookieString.js +22 -1
- package/cookieString.mjs +20 -1
- package/docs/classes/ApiError.html +2 -2
- package/docs/classes/AsyncJwt.html +2 -2
- package/docs/classes/Controller.html +2 -2
- package/docs/classes/Jwt.html +2 -2
- package/docs/classes/Memcached.html +2 -2
- package/docs/classes/Model.html +2 -2
- package/docs/classes/Server.html +2 -2
- package/docs/classes/Ssr.html +2 -2
- package/docs/classes/Web.html +2 -2
- package/docs/functions/action.html +2 -2
- package/docs/functions/body.html +2 -2
- package/docs/functions/codeToStatus.html +2 -2
- package/docs/functions/config.html +2 -2
- package/docs/functions/connection.html +2 -2
- package/docs/functions/context.html +2 -2
- package/docs/functions/controller-1.html +2 -2
- package/docs/functions/cookies.html +2 -2
- package/docs/functions/db.html +2 -2
- package/docs/functions/headers.html +2 -2
- package/docs/functions/home.html +2 -2
- package/docs/functions/hostname.html +2 -2
- package/docs/functions/http.html +2 -2
- package/docs/functions/init.html +2 -2
- package/docs/functions/json.html +2 -2
- package/docs/functions/logerror.html +2 -2
- package/docs/functions/method.html +2 -2
- package/docs/functions/mixin.html +2 -2
- package/docs/functions/mount.html +2 -2
- package/docs/functions/pool.html +2 -2
- package/docs/functions/protocol.html +2 -2
- package/docs/functions/request.html +2 -2
- package/docs/functions/selectControllersSchema.html +1 -1
- package/docs/functions/stream.html +2 -2
- package/docs/functions/subaction.html +2 -2
- package/docs/functions/url.html +2 -2
- package/docs/functions/xml.html +2 -2
- package/docs/index.html +2 -2
- package/docs/interfaces/ApiErrorMessage.html +2 -2
- package/docs/interfaces/ContextSsr.html +2 -2
- package/docs/interfaces/ContextWeb.html +2 -2
- package/docs/interfaces/OptionsSsr.html +2 -2
- package/docs/interfaces/OptionsWeb.html +2 -2
- package/docs/interfaces/ResponseOptions.html +2 -2
- package/docs/interfaces/Route.html +2 -2
- package/docs/interfaces/Schema.html +2 -2
- package/docs/interfaces/ServerHandler.html +2 -2
- package/docs/interfaces/ServerOptions.html +2 -2
- package/docs/interfaces/ServerWebsocket.html +2 -2
- package/docs/modules.html +2 -2
- package/docs/types/ServerRoutes.html +1 -1
- package/docs/variables/helpers.html +2 -2
- package/index.js +1473 -4
- package/index.mjs +1417 -4
- package/jsonBody.js +25 -1
- package/jsonBody.mjs +23 -1
- package/multipartBody.js +42 -1
- package/multipartBody.mjs +40 -1
- package/package.json +1 -1
- package/readConfig.js +11 -1
- package/readConfig.mjs +9 -1
- package/readConfigSync.js +11 -1
- package/readConfigSync.mjs +9 -1
- package/staticBody.js +205 -1
- package/staticBody.mjs +200 -1
- package/urlencodedBody.js +26 -1
- package/urlencodedBody.mjs +24 -1
- package/Jwt-7tQL-rwa.js +0 -1
- package/Jwt-CDdbxwvH.js +0 -1
package/Server.js
CHANGED
|
@@ -1 +1,316 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var dns = require('dns');
|
|
4
|
+
var uws = require('uWebSockets.js');
|
|
5
|
+
var cookieParse = require('./cookieParse.js');
|
|
6
|
+
|
|
7
|
+
const status = {
|
|
8
|
+
100: "100 Continue",
|
|
9
|
+
101: "101 Switching Protocols",
|
|
10
|
+
200: "200 OK",
|
|
11
|
+
201: "201 Created",
|
|
12
|
+
202: "202 Accepted",
|
|
13
|
+
203: "203 Non-Authoritative Information",
|
|
14
|
+
204: "No Content",
|
|
15
|
+
205: "205 Reset Content",
|
|
16
|
+
206: "206 Partial Content",
|
|
17
|
+
300: "300 Multiple Choices",
|
|
18
|
+
301: "301 Moved Permanently",
|
|
19
|
+
302: "302 Found",
|
|
20
|
+
303: "303 See Other",
|
|
21
|
+
304: "304 Not Modified",
|
|
22
|
+
305: "305 Use Proxy",
|
|
23
|
+
306: "306 (Unused)",
|
|
24
|
+
307: "307 Temporary Redirect",
|
|
25
|
+
400: "400 Bad Request",
|
|
26
|
+
401: "401 Unauthorized",
|
|
27
|
+
402: "402 Payment Required",
|
|
28
|
+
403: "403 Forbidden",
|
|
29
|
+
404: "404 Not Found",
|
|
30
|
+
405: "405 Method Not Allowed",
|
|
31
|
+
406: "406 Not Acceptable",
|
|
32
|
+
407: "407 Proxy Authentication Required",
|
|
33
|
+
408: "408 Request Timeout",
|
|
34
|
+
409: "409 Conflict",
|
|
35
|
+
410: "410 Gone",
|
|
36
|
+
411: "411 Length Required",
|
|
37
|
+
412: "412 Precondition Failed",
|
|
38
|
+
413: "413 Request Entity Too Large",
|
|
39
|
+
414: "414 Request-URI Too Long",
|
|
40
|
+
415: "415 Unsupported Media Type",
|
|
41
|
+
416: "416 Requested Range Not Satisfiable",
|
|
42
|
+
417: "417 Expectation Failed",
|
|
43
|
+
500: "500 Internal Server Error",
|
|
44
|
+
501: "501 Not Implemented",
|
|
45
|
+
502: "502 Bad Gateway",
|
|
46
|
+
503: "503 Service Unavailable",
|
|
47
|
+
504: "504 Gateway Timeout",
|
|
48
|
+
505: "505 HTTP Version Not Supported"
|
|
49
|
+
};
|
|
50
|
+
const codeToStatus = (code) => {
|
|
51
|
+
return status.hasOwnProperty(code) ? status[code] : `${code}`;
|
|
52
|
+
};
|
|
53
|
+
class Server {
|
|
54
|
+
/**
|
|
55
|
+
* @constructor
|
|
56
|
+
* @param options
|
|
57
|
+
*/
|
|
58
|
+
constructor(options) {
|
|
59
|
+
this._logLevel = "info";
|
|
60
|
+
/**
|
|
61
|
+
* Listen socket
|
|
62
|
+
* @private
|
|
63
|
+
*/
|
|
64
|
+
this._socket = null;
|
|
65
|
+
/**
|
|
66
|
+
* Request timeout
|
|
67
|
+
* @private
|
|
68
|
+
*/
|
|
69
|
+
this._timeout = 0;
|
|
70
|
+
this._routes = [];
|
|
71
|
+
this._host = "localhost";
|
|
72
|
+
this._port = 3e3;
|
|
73
|
+
this._mode = "production";
|
|
74
|
+
this._appOptions = {};
|
|
75
|
+
/**
|
|
76
|
+
* Default route options
|
|
77
|
+
* @private
|
|
78
|
+
*/
|
|
79
|
+
this._defaultRoute = {
|
|
80
|
+
method: "get",
|
|
81
|
+
pattern: "/*",
|
|
82
|
+
handler: (res, req, next) => next()
|
|
83
|
+
};
|
|
84
|
+
this._routes = options.routes || this._routes;
|
|
85
|
+
this._host = options.host || this._host;
|
|
86
|
+
this._port = options.port || this._port;
|
|
87
|
+
this._timeout = options.timeout || this._timeout;
|
|
88
|
+
this._mode = options.mode || this._mode;
|
|
89
|
+
this._appOptions = options.appOptions || this._appOptions;
|
|
90
|
+
this._logLevel = options.logLevel || this._logLevel;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Get TemplatedApp instance
|
|
94
|
+
*/
|
|
95
|
+
getApp() {
|
|
96
|
+
return this._app;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Create app (server http)
|
|
100
|
+
* @returns this
|
|
101
|
+
*/
|
|
102
|
+
app() {
|
|
103
|
+
this._protocol = "http";
|
|
104
|
+
this._app = uws.App(this._appOptions);
|
|
105
|
+
return this;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Create sslApp
|
|
109
|
+
* @returns this
|
|
110
|
+
*/
|
|
111
|
+
sslApp() {
|
|
112
|
+
this._protocol = "https";
|
|
113
|
+
this._app = uws.SSLApp(this._appOptions);
|
|
114
|
+
return this;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Push route
|
|
118
|
+
* @param route
|
|
119
|
+
* @returns this
|
|
120
|
+
*/
|
|
121
|
+
push(route) {
|
|
122
|
+
this._routes.push(route);
|
|
123
|
+
return this;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* unshift route
|
|
127
|
+
* @param route
|
|
128
|
+
* @returns this
|
|
129
|
+
*/
|
|
130
|
+
unshift(route) {
|
|
131
|
+
this._routes.unshift(route);
|
|
132
|
+
return this;
|
|
133
|
+
}
|
|
134
|
+
listen(host, port, fn = () => {
|
|
135
|
+
}) {
|
|
136
|
+
if (typeof port === "number") {
|
|
137
|
+
this._port = port;
|
|
138
|
+
this._host = host;
|
|
139
|
+
} else if (typeof host === "number") {
|
|
140
|
+
if (typeof port === "function") {
|
|
141
|
+
fn = port;
|
|
142
|
+
}
|
|
143
|
+
this._port = host;
|
|
144
|
+
} else if (typeof host === "function") {
|
|
145
|
+
fn = host;
|
|
146
|
+
}
|
|
147
|
+
if (!this._app) {
|
|
148
|
+
throw new Error("Create app or sslApp first");
|
|
149
|
+
}
|
|
150
|
+
this._lookup(this._host, (ip) => {
|
|
151
|
+
for (let route of this._routes) {
|
|
152
|
+
route = typeof route === "function" ? { handler: route } : route;
|
|
153
|
+
route = Object.assign({}, this._defaultRoute, route);
|
|
154
|
+
switch (route.method) {
|
|
155
|
+
case "ws":
|
|
156
|
+
this._app[route.method](route.pattern, route.behavior);
|
|
157
|
+
break;
|
|
158
|
+
default:
|
|
159
|
+
const routeHandler = route;
|
|
160
|
+
this._app[routeHandler.method](
|
|
161
|
+
route.pattern,
|
|
162
|
+
(res, req) => {
|
|
163
|
+
res.redirect = (url, code = 307) => this.constructor._redirect(res, req, url, code);
|
|
164
|
+
req.cookies = cookieParse.cookieParse(req.getHeader("cookie"));
|
|
165
|
+
Promise.race([
|
|
166
|
+
this._abortTimeout(res, req),
|
|
167
|
+
this._createHandler(
|
|
168
|
+
res,
|
|
169
|
+
req,
|
|
170
|
+
routeHandler.handler
|
|
171
|
+
)
|
|
172
|
+
]);
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
this._app.listen(ip, this._port, (listenSocket) => {
|
|
178
|
+
fn(listenSocket);
|
|
179
|
+
if (listenSocket) {
|
|
180
|
+
this._socket = listenSocket;
|
|
181
|
+
if (this._mode === "development") {
|
|
182
|
+
["info"].includes(this._logLevel) && console.log(
|
|
183
|
+
`Listening ${this._protocol}://${this._host}:${this._port}`
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
["info", "warn", "error"].includes(this._logLevel) && console.error(
|
|
188
|
+
`Error start server on ${this._protocol}://${this._host}:${this._port}`
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
return this;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Closes a uSockets listen socket.
|
|
197
|
+
*/
|
|
198
|
+
async close() {
|
|
199
|
+
if (this._socket) {
|
|
200
|
+
await uws.us_listen_socket_close(this._socket);
|
|
201
|
+
while (true) {
|
|
202
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
203
|
+
if (await this.socketPort() < 0) {
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
this._socket = null;
|
|
208
|
+
}
|
|
209
|
+
return this;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Return socket port
|
|
213
|
+
*/
|
|
214
|
+
async socketPort() {
|
|
215
|
+
if (!this._socket) {
|
|
216
|
+
return -1;
|
|
217
|
+
}
|
|
218
|
+
return uws.us_socket_local_port(this._socket);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Create decoration of handler
|
|
222
|
+
* @param res http response
|
|
223
|
+
* @param req http request
|
|
224
|
+
* @param fn handler
|
|
225
|
+
* @private
|
|
226
|
+
*/
|
|
227
|
+
_createHandler(res, req, fn) {
|
|
228
|
+
return new Promise(async (resolve) => {
|
|
229
|
+
const end = () => {
|
|
230
|
+
clearTimeout(this._timeoutId);
|
|
231
|
+
resolve();
|
|
232
|
+
};
|
|
233
|
+
try {
|
|
234
|
+
const next = (param, code = 307) => {
|
|
235
|
+
if (typeof param === "boolean") {
|
|
236
|
+
req.setYield(param);
|
|
237
|
+
}
|
|
238
|
+
if (param instanceof Error) {
|
|
239
|
+
throw param;
|
|
240
|
+
}
|
|
241
|
+
if (typeof param === "string") {
|
|
242
|
+
res.redirect(param, code);
|
|
243
|
+
}
|
|
244
|
+
end();
|
|
245
|
+
};
|
|
246
|
+
const result = fn(res, req, next);
|
|
247
|
+
if (result instanceof Promise) {
|
|
248
|
+
next(await result);
|
|
249
|
+
}
|
|
250
|
+
} catch (e) {
|
|
251
|
+
["info", "warn", "error"].includes(this._logLevel) && console.error(e);
|
|
252
|
+
const body = this._mode === "development" ? e.message : "";
|
|
253
|
+
res.cork(() => {
|
|
254
|
+
res.writeStatus("404 Not Found").end(body);
|
|
255
|
+
});
|
|
256
|
+
end();
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Redirect request
|
|
262
|
+
* @param res
|
|
263
|
+
* @param req
|
|
264
|
+
* @param url string of url
|
|
265
|
+
* @param code redirect status code
|
|
266
|
+
* @private
|
|
267
|
+
*/
|
|
268
|
+
static _redirect(res, req, url, code = 307) {
|
|
269
|
+
let status2 = "307 Temporary Redirect";
|
|
270
|
+
if (code === 301) {
|
|
271
|
+
status2 = "301 Moved Permanently";
|
|
272
|
+
}
|
|
273
|
+
res.cork(() => {
|
|
274
|
+
res.writeStatus(status2).writeHeader("location", url).end();
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Abort request by timeout
|
|
279
|
+
* @private
|
|
280
|
+
*/
|
|
281
|
+
_abortTimeout(res, req) {
|
|
282
|
+
return new Promise((resolve) => {
|
|
283
|
+
if (this._timeout && !req.getHeader("x-no-timeout")) {
|
|
284
|
+
this._timeoutId = setTimeout(() => {
|
|
285
|
+
try {
|
|
286
|
+
res.cork(() => {
|
|
287
|
+
res.writeStatus("408 Request Timeout").end();
|
|
288
|
+
resolve();
|
|
289
|
+
});
|
|
290
|
+
} catch (e) {
|
|
291
|
+
}
|
|
292
|
+
}, this._timeout);
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* lookup for host
|
|
298
|
+
* @param host
|
|
299
|
+
* @param resolve
|
|
300
|
+
* @private
|
|
301
|
+
*/
|
|
302
|
+
_lookup(host, resolve) {
|
|
303
|
+
dns.lookup(this._host, (err, addresses) => {
|
|
304
|
+
if (err) {
|
|
305
|
+
["info", "warn", "error"].includes(this._logLevel) && console.log(
|
|
306
|
+
`${this._host} error: ${err.message}`
|
|
307
|
+
);
|
|
308
|
+
} else {
|
|
309
|
+
resolve(Buffer.from(addresses));
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
exports.Server = Server;
|
|
316
|
+
exports.codeToStatus = codeToStatus;
|
package/Server.mjs
CHANGED
|
@@ -1 +1,313 @@
|
|
|
1
|
-
import
|
|
1
|
+
import dns from 'dns';
|
|
2
|
+
import uws from 'uWebSockets.js';
|
|
3
|
+
import { cookieParse } from './cookieParse.mjs';
|
|
4
|
+
|
|
5
|
+
const status = {
|
|
6
|
+
100: "100 Continue",
|
|
7
|
+
101: "101 Switching Protocols",
|
|
8
|
+
200: "200 OK",
|
|
9
|
+
201: "201 Created",
|
|
10
|
+
202: "202 Accepted",
|
|
11
|
+
203: "203 Non-Authoritative Information",
|
|
12
|
+
204: "No Content",
|
|
13
|
+
205: "205 Reset Content",
|
|
14
|
+
206: "206 Partial Content",
|
|
15
|
+
300: "300 Multiple Choices",
|
|
16
|
+
301: "301 Moved Permanently",
|
|
17
|
+
302: "302 Found",
|
|
18
|
+
303: "303 See Other",
|
|
19
|
+
304: "304 Not Modified",
|
|
20
|
+
305: "305 Use Proxy",
|
|
21
|
+
306: "306 (Unused)",
|
|
22
|
+
307: "307 Temporary Redirect",
|
|
23
|
+
400: "400 Bad Request",
|
|
24
|
+
401: "401 Unauthorized",
|
|
25
|
+
402: "402 Payment Required",
|
|
26
|
+
403: "403 Forbidden",
|
|
27
|
+
404: "404 Not Found",
|
|
28
|
+
405: "405 Method Not Allowed",
|
|
29
|
+
406: "406 Not Acceptable",
|
|
30
|
+
407: "407 Proxy Authentication Required",
|
|
31
|
+
408: "408 Request Timeout",
|
|
32
|
+
409: "409 Conflict",
|
|
33
|
+
410: "410 Gone",
|
|
34
|
+
411: "411 Length Required",
|
|
35
|
+
412: "412 Precondition Failed",
|
|
36
|
+
413: "413 Request Entity Too Large",
|
|
37
|
+
414: "414 Request-URI Too Long",
|
|
38
|
+
415: "415 Unsupported Media Type",
|
|
39
|
+
416: "416 Requested Range Not Satisfiable",
|
|
40
|
+
417: "417 Expectation Failed",
|
|
41
|
+
500: "500 Internal Server Error",
|
|
42
|
+
501: "501 Not Implemented",
|
|
43
|
+
502: "502 Bad Gateway",
|
|
44
|
+
503: "503 Service Unavailable",
|
|
45
|
+
504: "504 Gateway Timeout",
|
|
46
|
+
505: "505 HTTP Version Not Supported"
|
|
47
|
+
};
|
|
48
|
+
const codeToStatus = (code) => {
|
|
49
|
+
return status.hasOwnProperty(code) ? status[code] : `${code}`;
|
|
50
|
+
};
|
|
51
|
+
class Server {
|
|
52
|
+
/**
|
|
53
|
+
* @constructor
|
|
54
|
+
* @param options
|
|
55
|
+
*/
|
|
56
|
+
constructor(options) {
|
|
57
|
+
this._logLevel = "info";
|
|
58
|
+
/**
|
|
59
|
+
* Listen socket
|
|
60
|
+
* @private
|
|
61
|
+
*/
|
|
62
|
+
this._socket = null;
|
|
63
|
+
/**
|
|
64
|
+
* Request timeout
|
|
65
|
+
* @private
|
|
66
|
+
*/
|
|
67
|
+
this._timeout = 0;
|
|
68
|
+
this._routes = [];
|
|
69
|
+
this._host = "localhost";
|
|
70
|
+
this._port = 3e3;
|
|
71
|
+
this._mode = "production";
|
|
72
|
+
this._appOptions = {};
|
|
73
|
+
/**
|
|
74
|
+
* Default route options
|
|
75
|
+
* @private
|
|
76
|
+
*/
|
|
77
|
+
this._defaultRoute = {
|
|
78
|
+
method: "get",
|
|
79
|
+
pattern: "/*",
|
|
80
|
+
handler: (res, req, next) => next()
|
|
81
|
+
};
|
|
82
|
+
this._routes = options.routes || this._routes;
|
|
83
|
+
this._host = options.host || this._host;
|
|
84
|
+
this._port = options.port || this._port;
|
|
85
|
+
this._timeout = options.timeout || this._timeout;
|
|
86
|
+
this._mode = options.mode || this._mode;
|
|
87
|
+
this._appOptions = options.appOptions || this._appOptions;
|
|
88
|
+
this._logLevel = options.logLevel || this._logLevel;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Get TemplatedApp instance
|
|
92
|
+
*/
|
|
93
|
+
getApp() {
|
|
94
|
+
return this._app;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Create app (server http)
|
|
98
|
+
* @returns this
|
|
99
|
+
*/
|
|
100
|
+
app() {
|
|
101
|
+
this._protocol = "http";
|
|
102
|
+
this._app = uws.App(this._appOptions);
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Create sslApp
|
|
107
|
+
* @returns this
|
|
108
|
+
*/
|
|
109
|
+
sslApp() {
|
|
110
|
+
this._protocol = "https";
|
|
111
|
+
this._app = uws.SSLApp(this._appOptions);
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Push route
|
|
116
|
+
* @param route
|
|
117
|
+
* @returns this
|
|
118
|
+
*/
|
|
119
|
+
push(route) {
|
|
120
|
+
this._routes.push(route);
|
|
121
|
+
return this;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* unshift route
|
|
125
|
+
* @param route
|
|
126
|
+
* @returns this
|
|
127
|
+
*/
|
|
128
|
+
unshift(route) {
|
|
129
|
+
this._routes.unshift(route);
|
|
130
|
+
return this;
|
|
131
|
+
}
|
|
132
|
+
listen(host, port, fn = () => {
|
|
133
|
+
}) {
|
|
134
|
+
if (typeof port === "number") {
|
|
135
|
+
this._port = port;
|
|
136
|
+
this._host = host;
|
|
137
|
+
} else if (typeof host === "number") {
|
|
138
|
+
if (typeof port === "function") {
|
|
139
|
+
fn = port;
|
|
140
|
+
}
|
|
141
|
+
this._port = host;
|
|
142
|
+
} else if (typeof host === "function") {
|
|
143
|
+
fn = host;
|
|
144
|
+
}
|
|
145
|
+
if (!this._app) {
|
|
146
|
+
throw new Error("Create app or sslApp first");
|
|
147
|
+
}
|
|
148
|
+
this._lookup(this._host, (ip) => {
|
|
149
|
+
for (let route of this._routes) {
|
|
150
|
+
route = typeof route === "function" ? { handler: route } : route;
|
|
151
|
+
route = Object.assign({}, this._defaultRoute, route);
|
|
152
|
+
switch (route.method) {
|
|
153
|
+
case "ws":
|
|
154
|
+
this._app[route.method](route.pattern, route.behavior);
|
|
155
|
+
break;
|
|
156
|
+
default:
|
|
157
|
+
const routeHandler = route;
|
|
158
|
+
this._app[routeHandler.method](
|
|
159
|
+
route.pattern,
|
|
160
|
+
(res, req) => {
|
|
161
|
+
res.redirect = (url, code = 307) => this.constructor._redirect(res, req, url, code);
|
|
162
|
+
req.cookies = cookieParse(req.getHeader("cookie"));
|
|
163
|
+
Promise.race([
|
|
164
|
+
this._abortTimeout(res, req),
|
|
165
|
+
this._createHandler(
|
|
166
|
+
res,
|
|
167
|
+
req,
|
|
168
|
+
routeHandler.handler
|
|
169
|
+
)
|
|
170
|
+
]);
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
this._app.listen(ip, this._port, (listenSocket) => {
|
|
176
|
+
fn(listenSocket);
|
|
177
|
+
if (listenSocket) {
|
|
178
|
+
this._socket = listenSocket;
|
|
179
|
+
if (this._mode === "development") {
|
|
180
|
+
["info"].includes(this._logLevel) && console.log(
|
|
181
|
+
`Listening ${this._protocol}://${this._host}:${this._port}`
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
["info", "warn", "error"].includes(this._logLevel) && console.error(
|
|
186
|
+
`Error start server on ${this._protocol}://${this._host}:${this._port}`
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
return this;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Closes a uSockets listen socket.
|
|
195
|
+
*/
|
|
196
|
+
async close() {
|
|
197
|
+
if (this._socket) {
|
|
198
|
+
await uws.us_listen_socket_close(this._socket);
|
|
199
|
+
while (true) {
|
|
200
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
201
|
+
if (await this.socketPort() < 0) {
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
this._socket = null;
|
|
206
|
+
}
|
|
207
|
+
return this;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Return socket port
|
|
211
|
+
*/
|
|
212
|
+
async socketPort() {
|
|
213
|
+
if (!this._socket) {
|
|
214
|
+
return -1;
|
|
215
|
+
}
|
|
216
|
+
return uws.us_socket_local_port(this._socket);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Create decoration of handler
|
|
220
|
+
* @param res http response
|
|
221
|
+
* @param req http request
|
|
222
|
+
* @param fn handler
|
|
223
|
+
* @private
|
|
224
|
+
*/
|
|
225
|
+
_createHandler(res, req, fn) {
|
|
226
|
+
return new Promise(async (resolve) => {
|
|
227
|
+
const end = () => {
|
|
228
|
+
clearTimeout(this._timeoutId);
|
|
229
|
+
resolve();
|
|
230
|
+
};
|
|
231
|
+
try {
|
|
232
|
+
const next = (param, code = 307) => {
|
|
233
|
+
if (typeof param === "boolean") {
|
|
234
|
+
req.setYield(param);
|
|
235
|
+
}
|
|
236
|
+
if (param instanceof Error) {
|
|
237
|
+
throw param;
|
|
238
|
+
}
|
|
239
|
+
if (typeof param === "string") {
|
|
240
|
+
res.redirect(param, code);
|
|
241
|
+
}
|
|
242
|
+
end();
|
|
243
|
+
};
|
|
244
|
+
const result = fn(res, req, next);
|
|
245
|
+
if (result instanceof Promise) {
|
|
246
|
+
next(await result);
|
|
247
|
+
}
|
|
248
|
+
} catch (e) {
|
|
249
|
+
["info", "warn", "error"].includes(this._logLevel) && console.error(e);
|
|
250
|
+
const body = this._mode === "development" ? e.message : "";
|
|
251
|
+
res.cork(() => {
|
|
252
|
+
res.writeStatus("404 Not Found").end(body);
|
|
253
|
+
});
|
|
254
|
+
end();
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Redirect request
|
|
260
|
+
* @param res
|
|
261
|
+
* @param req
|
|
262
|
+
* @param url string of url
|
|
263
|
+
* @param code redirect status code
|
|
264
|
+
* @private
|
|
265
|
+
*/
|
|
266
|
+
static _redirect(res, req, url, code = 307) {
|
|
267
|
+
let status2 = "307 Temporary Redirect";
|
|
268
|
+
if (code === 301) {
|
|
269
|
+
status2 = "301 Moved Permanently";
|
|
270
|
+
}
|
|
271
|
+
res.cork(() => {
|
|
272
|
+
res.writeStatus(status2).writeHeader("location", url).end();
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Abort request by timeout
|
|
277
|
+
* @private
|
|
278
|
+
*/
|
|
279
|
+
_abortTimeout(res, req) {
|
|
280
|
+
return new Promise((resolve) => {
|
|
281
|
+
if (this._timeout && !req.getHeader("x-no-timeout")) {
|
|
282
|
+
this._timeoutId = setTimeout(() => {
|
|
283
|
+
try {
|
|
284
|
+
res.cork(() => {
|
|
285
|
+
res.writeStatus("408 Request Timeout").end();
|
|
286
|
+
resolve();
|
|
287
|
+
});
|
|
288
|
+
} catch (e) {
|
|
289
|
+
}
|
|
290
|
+
}, this._timeout);
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* lookup for host
|
|
296
|
+
* @param host
|
|
297
|
+
* @param resolve
|
|
298
|
+
* @private
|
|
299
|
+
*/
|
|
300
|
+
_lookup(host, resolve) {
|
|
301
|
+
dns.lookup(this._host, (err, addresses) => {
|
|
302
|
+
if (err) {
|
|
303
|
+
["info", "warn", "error"].includes(this._logLevel) && console.log(
|
|
304
|
+
`${this._host} error: ${err.message}`
|
|
305
|
+
);
|
|
306
|
+
} else {
|
|
307
|
+
resolve(Buffer.from(addresses));
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export { Server, codeToStatus };
|
package/cookieParse.js
CHANGED
|
@@ -1 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const cookieParse = (str) => {
|
|
4
|
+
if (!str) {
|
|
5
|
+
return {};
|
|
6
|
+
}
|
|
7
|
+
return str.split(/; */).reduce((obj, str2) => {
|
|
8
|
+
if (str2 === "") {
|
|
9
|
+
return obj;
|
|
10
|
+
}
|
|
11
|
+
const eq = str2.indexOf("=");
|
|
12
|
+
const key = eq > 0 ? str2.slice(0, eq) : str2;
|
|
13
|
+
let val = eq > 0 ? str2.slice(eq + 1) : null;
|
|
14
|
+
if (val != null) {
|
|
15
|
+
try {
|
|
16
|
+
val = decodeURIComponent(val);
|
|
17
|
+
} catch (ex) {
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
obj[key] = val;
|
|
21
|
+
return obj;
|
|
22
|
+
}, {});
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
exports.cookieParse = cookieParse;
|
package/cookieParse.mjs
CHANGED
|
@@ -1 +1,23 @@
|
|
|
1
|
-
const
|
|
1
|
+
const cookieParse = (str) => {
|
|
2
|
+
if (!str) {
|
|
3
|
+
return {};
|
|
4
|
+
}
|
|
5
|
+
return str.split(/; */).reduce((obj, str2) => {
|
|
6
|
+
if (str2 === "") {
|
|
7
|
+
return obj;
|
|
8
|
+
}
|
|
9
|
+
const eq = str2.indexOf("=");
|
|
10
|
+
const key = eq > 0 ? str2.slice(0, eq) : str2;
|
|
11
|
+
let val = eq > 0 ? str2.slice(eq + 1) : null;
|
|
12
|
+
if (val != null) {
|
|
13
|
+
try {
|
|
14
|
+
val = decodeURIComponent(val);
|
|
15
|
+
} catch (ex) {
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
obj[key] = val;
|
|
19
|
+
return obj;
|
|
20
|
+
}, {});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export { cookieParse };
|