slower 1.1.22 → 1.1.25
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/lib/router.js +58 -13
- package/lib/utils.js +9 -1
- package/package.json +1 -1
package/lib/router.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const http = require('http');
|
|
2
2
|
const https = require('https');
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
const { clone, noop, slugify, isSparseEqual, last, renderDynamicHTML, setSocketLocals, setSocketSecurityHeaders, setResponseAssessors } = require('./utils');
|
|
4
|
+
const { clone, noop, slugify, isSparseEqual, last, renderDynamicHTML, setSocketLocals, setSocketSecurityHeaders, setResponseAssessors, isPromise, UUID } = require('./utils');
|
|
5
5
|
const mimetable = require('./mimetable.json');
|
|
6
6
|
|
|
7
7
|
class Route {
|
|
@@ -36,6 +36,7 @@ class SlowerRouter {
|
|
|
36
36
|
this.blockedMethodCallback = noop;
|
|
37
37
|
this.tls = { use: false, key: null, cert: null };
|
|
38
38
|
this.server = null;
|
|
39
|
+
this.connectionpool = {};
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
enableStrictHeaders () {
|
|
@@ -355,10 +356,9 @@ class SlowerRouter {
|
|
|
355
356
|
* @category Router
|
|
356
357
|
* @param {Number} port The port number the server will listen to.
|
|
357
358
|
* @param {String} host The host's network interface address the server will listen into (use a falsy value or '0.0.0.0' for listening on all).
|
|
358
|
-
* @
|
|
359
|
-
* @returns {Object<http.Server>} The server instance
|
|
359
|
+
* @returns {Promise<http.Server>} The server instance
|
|
360
360
|
*/
|
|
361
|
-
start = function (port = 8080, host = undefined
|
|
361
|
+
start = async function (port = 8080, host = undefined) {
|
|
362
362
|
let routes = this.routes;
|
|
363
363
|
let middle = this.middleware;
|
|
364
364
|
let fallback = this.fallback;
|
|
@@ -372,7 +372,15 @@ class SlowerRouter {
|
|
|
372
372
|
this.server = http.createServer({}, mainServerHandler);
|
|
373
373
|
}
|
|
374
374
|
|
|
375
|
-
|
|
375
|
+
this.server.on('connection', (socket) => {
|
|
376
|
+
const id = UUID();
|
|
377
|
+
this.connectionpool[id] = socket;
|
|
378
|
+
socket.on('close', () => delete this.connectionpool[id]);
|
|
379
|
+
socket.on('error', () => delete this.connectionpool[id]);
|
|
380
|
+
socket.on('timeout', () => { this.connectionpool[id].destroy(); delete this.connectionpool[id]; });
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
async function mainServerHandler (req, res) {
|
|
376
384
|
try {
|
|
377
385
|
// Sets local req.session object
|
|
378
386
|
setSocketLocals(req);
|
|
@@ -383,7 +391,8 @@ class SlowerRouter {
|
|
|
383
391
|
if (!!this.strictHeaders) setSocketSecurityHeaders(req);
|
|
384
392
|
// Runs all middlewares
|
|
385
393
|
for (let i = 0; i < middle.length; i++) {
|
|
386
|
-
middle[i](req, res);
|
|
394
|
+
const rr = middle[i](req, res);
|
|
395
|
+
if (isPromise(rr)) await rr;
|
|
387
396
|
if (res.writableEnded) return; // if res.end() is caller early in a middleware
|
|
388
397
|
}
|
|
389
398
|
// Only respond to allowed methods with callbacks, else, use the default empty response.
|
|
@@ -398,13 +407,15 @@ class SlowerRouter {
|
|
|
398
407
|
)
|
|
399
408
|
) {
|
|
400
409
|
i = routes.length;
|
|
401
|
-
route.callback(req, res);
|
|
410
|
+
const rr = route.callback(req, res);
|
|
411
|
+
if (isPromise(rr)) await rr;
|
|
402
412
|
// if (res.writableEnded) return; // if res.end() was called
|
|
403
413
|
// else res.end(); // if res.end() was not called
|
|
404
414
|
return;
|
|
405
415
|
}
|
|
406
416
|
}
|
|
407
|
-
fallback(req,res);
|
|
417
|
+
const rr = fallback(req,res);
|
|
418
|
+
if (isPromise(rr)) await rr;
|
|
408
419
|
if (!res.writableEnded) res.end();
|
|
409
420
|
} else {
|
|
410
421
|
blockedMethodCallback(req, res);
|
|
@@ -415,14 +426,48 @@ class SlowerRouter {
|
|
|
415
426
|
}
|
|
416
427
|
}
|
|
417
428
|
|
|
418
|
-
|
|
429
|
+
this.port = port;
|
|
430
|
+
this.host = host;
|
|
419
431
|
if (!host) host = undefined; // Turn falsy values into undefined, for default behaviour
|
|
420
|
-
this.server.listen(port, host);
|
|
421
|
-
return this;
|
|
432
|
+
return new Promise((resolve, reject) => this.server.listen(port, host, () => resolve(this)));
|
|
422
433
|
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
*
|
|
437
|
+
* @param {Object} options
|
|
438
|
+
* @returns
|
|
439
|
+
* Options include:
|
|
440
|
+
* forceDisconnection: boolean (default: false) - If enabled, force sockets to disconnect after a 2 seconds timeout.
|
|
441
|
+
* instantClose: boolean (default: false) - Only relevant if 'forceDisconnection' is enabled. If enabled, force sockets to disconnect immediately.
|
|
442
|
+
* silent: boolean (default: true) - If set to false, show the disconnection status messages.
|
|
443
|
+
*/
|
|
444
|
+
close = async function ({ forceDisconnection = false, instantClose = false, silent = true }) {
|
|
445
|
+
return new Promise (async (resolve, reject) => {
|
|
446
|
+
this.server.on('close', () => resolve());
|
|
447
|
+
this.server.on('error', (err) => reject(err));
|
|
448
|
+
|
|
449
|
+
// After this, no more sockets can connect, but the already connected ones, remain
|
|
450
|
+
this.server.close();
|
|
451
|
+
if (!silent) console.log('<> Shutting down server...');
|
|
423
452
|
|
|
424
|
-
|
|
425
|
-
|
|
453
|
+
if (forceDisconnection) {
|
|
454
|
+
// wait 1 second before continuing
|
|
455
|
+
if (!instantClose) await new Promise ((resolve1, reject1) => setTimeout(resolve1, 1000));
|
|
456
|
+
|
|
457
|
+
// If there are sockets still connected (waiting for timeout),
|
|
458
|
+
// wait until all disconnected or force all to disconnect after 2 seconds
|
|
459
|
+
if (!silent) {
|
|
460
|
+
const activesockets = await new Promise((resolve2, reject2) => this.server.getConnections((err,count) => resolve2(count)));
|
|
461
|
+
console.log(`<> Awaiting disconnection of active sockets [${activesockets}]`);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// wait 1 second and destroy the ones still connected
|
|
465
|
+
if (!instantClose) await new Promise ((resolve1, reject1) => setTimeout(resolve1, 1000));
|
|
466
|
+
for (let sock in this.connectionpool) {
|
|
467
|
+
this.connectionpool[sock].destroy();
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
});
|
|
426
471
|
}
|
|
427
472
|
}
|
|
428
473
|
|
package/lib/utils.js
CHANGED
|
@@ -161,4 +161,12 @@ const toBool = [() => true, () => false];
|
|
|
161
161
|
|
|
162
162
|
const clone = (object) => JSON.parse(JSON.stringify(object));
|
|
163
163
|
|
|
164
|
-
|
|
164
|
+
const isPromise = obj => {
|
|
165
|
+
return obj !== null &&
|
|
166
|
+
(typeof obj === 'object' || typeof obj === 'function') &&
|
|
167
|
+
typeof obj.then === 'function';
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const UUID = () => '################################'.replace(new RegExp(`[#]`, 'gim'), () => Math.random().toString(16)[6]);
|
|
171
|
+
|
|
172
|
+
module.exports = { clone, noop, slugify, isSparseEqual, toBool, last, renderDynamicHTML, setSocketLocals, setSocketSecurityHeaders, setResponseAssessors, isPromise, UUID };
|