-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
102 lines (92 loc) · 3.25 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
96
97
98
99
100
101
102
const util = require('util');
const setTimeoutPromise = util.promisify(setTimeout);
const DEFAULT_ROUTE = "/timeouttest";
const DEFAULT_RES_STATUS = 200;
const DEFAULT_RES_FAIL_STATUS = 429;
const DEFAULT_TIMEOUT = 5*60*1000; // 5 mins
const DEFAULT_LOG_INTERVAL = 10*1000; // 10 Seconds
const MAX_TESTS = 1
/**
* Converts milliseconds into greater time units as possible
* @param {int} ms - Amount of time measured in milliseconds
* @return {Object|null} Reallocated time units. NULL on failure.
*/
function timeUnits( ms ) {
if ( !Number.isInteger(ms) ) {
return null
}
/**
* Takes as many whole units from the time pool (ms) as possible
* @param {int} msUnit - Size of a single unit in milliseconds
* @return {int} Number of units taken from the time pool
*/
const allocate = msUnit => {
const units = Math.trunc(ms / msUnit)
ms -= units * msUnit
return units
}
// Property order is important here.
// These arguments are the respective units in ms.
return {
days: allocate(86400000),
hours: allocate(3600000),
minutes: allocate(60000),
seconds: allocate(1000),
ms: ms // remainder
}
}
function printUnit(val, unit, strAfter=""){
if (val > 0) {
return `${val} ${unit}${strAfter?`, ${strAfter}`:""}`
}
return strAfter
}
function timeUnitsStr({days=0, hours=0, minutes=0, seconds=0, ms=0}={}){
return `${printUnit(days,"Days", printUnit(hours,"Hours", printUnit(minutes,"Minutes", printUnit(seconds,"Seconds", printUnit(ms, "Milliseconds")))))}`
}
function log(verbose){
if(verbose){
return console.log
}
return ()=>{}
}
module.exports = function ({
timeout_route=DEFAULT_ROUTE,
timeout=DEFAULT_TIMEOUT,
interval=DEFAULT_LOG_INTERVAL,
res_status=DEFAULT_RES_STATUS,
res_fail_status=DEFAULT_RES_FAIL_STATUS,
max_tests=MAX_TESTS,
check_auth=false,
verbose=true
}={}) {
return async function (req, res, next) {
// Implement the middleware function based on the options object
const logger = log(verbose)
const url = req.originalUrl
if(url.toLowerCase().startsWith(timeout_route)){
if(check_auth&&!req.isAuthenticated()){
return res.sendStatus(403);
}
let {ongoing_timeout_tests=0} = req.app.locals
req.app.locals.ongoing_timeout_tests = ongoing_timeout_tests
if(req.app.locals.ongoing_timeout_tests>=max_tests){
logger(`[${url}] Exceeded max timeout tests`)
return res.sendStatus(res_fail_status);
}
req.app.locals.ongoing_timeout_tests += 1;
logger(`[${url}] Waiting for ${timeUnitsStr(timeUnits(timeout))}`);
let startCount = interval
const intervalId = setInterval(()=>{
logger(`[${url}] ${timeUnitsStr(timeUnits(startCount))} elapsed, ${timeUnitsStr(timeUnits(timeout-startCount))} left`)
startCount += interval;
},interval)
await setTimeoutPromise(timeout, true);
clearInterval(intervalId);
req.app.locals.ongoing_timeout_tests -= 1;
res.sendStatus(res_status)
}else{
next();
}
}
}