2021-07-07 05:38:56 -04:00
|
|
|
const settings = require('@overleaf/settings')
|
2020-10-30 04:10:50 -04:00
|
|
|
const Metrics = require('@overleaf/metrics')
|
2019-05-29 05:21:06 -04:00
|
|
|
const RedisWrapper = require('./RedisWrapper')
|
|
|
|
const rclient = RedisWrapper.client('ratelimiter')
|
2021-05-07 06:52:07 -04:00
|
|
|
const { RedisRateLimiter } = require('rolling-rate-limiter')
|
|
|
|
const { callbackify } = require('util')
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2021-05-07 06:52:07 -04:00
|
|
|
async function addCount(opts) {
|
|
|
|
if (settings.disableRateLimits) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
const namespace = `RateLimit:${opts.endpointName}:`
|
|
|
|
const k = `{${opts.subjectName}}`
|
|
|
|
const limiter = new RedisRateLimiter({
|
|
|
|
client: rclient,
|
|
|
|
namespace,
|
|
|
|
interval: opts.timeInterval * 1000,
|
|
|
|
maxInInterval: opts.throttle,
|
|
|
|
})
|
|
|
|
const rateLimited = await limiter.limit(k)
|
|
|
|
if (rateLimited) {
|
|
|
|
Metrics.inc('rate-limit-hit', 1, {
|
|
|
|
path: opts.endpointName,
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
2021-05-07 06:52:07 -04:00
|
|
|
}
|
|
|
|
return !rateLimited
|
|
|
|
}
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2021-05-07 06:52:07 -04:00
|
|
|
async function clearRateLimit(endpointName, subject) {
|
|
|
|
// same as the key which will be built by RollingRateLimiter (namespace+k)
|
|
|
|
const keyName = `RateLimit:${endpointName}:{${subject}}`
|
|
|
|
await rclient.del(keyName)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
2019-10-15 09:12:11 -04:00
|
|
|
|
2021-05-07 06:52:07 -04:00
|
|
|
module.exports = {
|
|
|
|
addCount: callbackify(addCount),
|
|
|
|
clearRateLimit: callbackify(clearRateLimit),
|
|
|
|
promises: {
|
|
|
|
addCount,
|
|
|
|
clearRateLimit,
|
|
|
|
},
|
|
|
|
}
|