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 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
- * @param {Function} callback The function to execute after starting the server.
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, callback = () => {}) {
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
- function mainServerHandler (req, res) {
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
- callback(this.server);
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
- close = function () {
425
- this.server.close();
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
- module.exports = { clone, noop, slugify, isSparseEqual, toBool, last, renderDynamicHTML, setSocketLocals, setSocketSecurityHeaders, setResponseAssessors };
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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slower",
3
- "version": "1.1.22",
3
+ "version": "1.1.25",
4
4
  "description": "A package for simple HTTP server routing.",
5
5
  "main": "index.js",
6
6
  "directories": {