|
|
@@ -1,27 +1,29 @@
|
|
|
settings = require("settings-sharelatex")
|
|
|
RedisWrapper = require('./RedisWrapper')
|
|
|
rclient = RedisWrapper.client('ratelimiter')
|
|
|
+RollingRateLimiter = require('rolling-rate-limiter')
|
|
|
|
|
|
|
|
|
module.exports = RateLimiter =
|
|
|
|
|
|
- _buildKey: (endpoint, subject) ->
|
|
|
- return "RateLimiter:#{endpoint}:{#{subject}}"
|
|
|
-
|
|
|
addCount: (opts, callback = (err, shouldProcess)->)->
|
|
|
- k = RateLimiter._buildKey(opts.endpointName, opts.subjectName)
|
|
|
- multi = rclient.multi()
|
|
|
- multi.incr(k)
|
|
|
- multi.get(k)
|
|
|
- multi.expire(k, opts.timeInterval)
|
|
|
- multi.exec (err, results)->
|
|
|
- count = results[1]
|
|
|
- # account for the different results from `multi` when using cluster
|
|
|
- if count instanceof Object
|
|
|
- count = count[1]
|
|
|
- allow = count < opts.throttle
|
|
|
- callback err, allow
|
|
|
+ console.log ">> opts", opts
|
|
|
+ namespace = "RateLimit:#{opts.endpointName}:"
|
|
|
+ k = "{#{opts.subjectName}}"
|
|
|
+ limiter = RollingRateLimiter({
|
|
|
+ redis: rclient,
|
|
|
+ namespace: namespace,
|
|
|
+ interval: opts.timeInterval * 1000,
|
|
|
+ maxInInterval: opts.throttle
|
|
|
+ })
|
|
|
+ limiter k, (err, timeLeft, actionsLeft) ->
|
|
|
+ if err?
|
|
|
+ return callback(err)
|
|
|
+ allowed = timeLeft == 0
|
|
|
+ console.log ">> limit", namespace, k, timeLeft, actionsLeft, ", allowed", allowed
|
|
|
+ callback(null, allowed)
|
|
|
|
|
|
clearRateLimit: (endpointName, subject, callback) ->
|
|
|
- k = RateLimiter._buildKey(endpointName, subject)
|
|
|
- rclient.del k, callback
|
|
|
+ # same as the key which will be built by RollingRateLimiter (namespace+k)
|
|
|
+ keyName = "RateLimit:#{endpointName}:{#{subject}}"
|
|
|
+ rclient.del keyName, callback
|