UNPKG

@fastify/rate-limit

Version:

A low overhead rate limiter for your routes

59 lines (48 loc) 1.85 kB
'use strict' const lua = ` -- Key to operate on local key = KEYS[1] -- Time window for the TTL local timeWindow = tonumber(ARGV[1]) -- Max requests local max = tonumber(ARGV[2]) -- Flag to determine if TTL should be reset after exceeding local continueExceeding = ARGV[3] == 'true' --Flag to determine if exponential backoff should be applied local exponentialBackoff = ARGV[4] == 'true' --Max safe integer local MAX_SAFE_INTEGER = (2^53) - 1 -- Increment the key's value local current = redis.call('INCR', key) if current == 1 or (continueExceeding and current > max) then redis.call('PEXPIRE', key, timeWindow) elseif exponentialBackoff and current > max then local backoffExponent = current - max - 1 timeWindow = math.min(timeWindow * (2 ^ backoffExponent), MAX_SAFE_INTEGER) redis.call('PEXPIRE', key, timeWindow) else timeWindow = redis.call('PTTL', key) end return {current, timeWindow} ` function RedisStore (continueExceeding, exponentialBackoff, redis, key = 'fastify-rate-limit-') { this.continueExceeding = continueExceeding this.exponentialBackoff = exponentialBackoff this.redis = redis this.key = key if (!this.redis.rateLimit) { this.redis.defineCommand('rateLimit', { numberOfKeys: 1, lua }) } } RedisStore.prototype.incr = function (ip, cb, timeWindow, max) { this.redis.rateLimit(this.key + ip, timeWindow, max, this.continueExceeding, this.exponentialBackoff, (err, result) => { err ? cb(err, null) : cb(null, { current: result[0], ttl: result[1] }) }) } RedisStore.prototype.child = function (routeOptions) { return new RedisStore(routeOptions.continueExceeding, routeOptions.exponentialBackoff, this.redis, `${this.key}${routeOptions.routeInfo.method}${routeOptions.routeInfo.url}-`) } module.exports = RedisStore