forked from koajs/ratelimit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
62 lines (48 loc) · 1.49 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
/**
* Module dependencies.
*/
var debug = require('debug')('koa-ratelimit');
var Limiter = require('ratelimiter');
var ms = require('ms');
var thenify = require('thenify');
/**
* Expose `ratelimit()`.
*/
module.exports = ratelimit;
/**
* Initialize ratelimit middleware with the given `opts`:
*
* - `duration` limit duration in milliseconds [1 hour]
* - `max` max requests per `id` [2500]
* - `db` database connection
* - `id` id to compare requests [ip]
*
* @param {Object} opts
* @return {Function}
* @api public
*/
function ratelimit(opts) {
opts = opts || {};
return function *(next){
var id = opts.id ? opts.id(this) : this.ip;
if (false === id) return yield* next;
// initialize limiter
var limiter = new Limiter({ id: id, __proto__: opts });
limiter.get = thenify(limiter.get);
// check limit
var limit = yield limiter.get();
// check if current call is legit
var remaining = limit.remaining > 0 ? limit.remaining - 1 : 0;
// header fields
this.set('X-RateLimit-Limit', limit.total);
this.set('X-RateLimit-Remaining', remaining);
this.set('X-RateLimit-Reset', limit.reset);
debug('remaining %s/%s %s', remaining, limit.total, id);
if (limit.remaining) return yield* next;
var delta = (limit.reset * 1000) - Date.now() | 0;
var after = limit.reset - (Date.now() / 1000) | 0;
this.set('Retry-After', after);
this.status = 429;
this.body = 'Rate limit exceeded, retry in ' + ms(delta, { long: true });
}
}