Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const { parse, format } = require('@lukeed/ms')

const LocalStore = require('./store/LocalStore')
const RedisStore = require('./store/RedisStore')
const NodeRedisStore = require('./store/NodeRedisStore')

const defaultMax = 1000
const defaultTimeWindow = 60000
Expand Down Expand Up @@ -117,7 +118,11 @@ async function fastifyRateLimit (fastify, settings) {
pluginComponent.store = new Store(globalParams)
} else {
if (settings.redis) {
pluginComponent.store = new RedisStore(globalParams.continueExceeding, globalParams.exponentialBackoff, settings.redis, settings.nameSpace)
if (settings.redis.constructor.name === 'Commander') {
pluginComponent.store = new NodeRedisStore(globalParams.continueExceeding, globalParams.exponentialBackoff, settings.redis, settings.nameSpace)
} else {
pluginComponent.store = new RedisStore(globalParams.continueExceeding, globalParams.exponentialBackoff, settings.redis, settings.nameSpace)
}
} else {
pluginComponent.store = new LocalStore(globalParams.continueExceeding, globalParams.exponentialBackoff, settings.cache)
}
Expand Down Expand Up @@ -290,3 +295,4 @@ module.exports = fp(fastifyRateLimit, {
})
module.exports.default = fastifyRateLimit
module.exports.fastifyRateLimit = fastifyRateLimit
module.exports.NodeRedisStore = NodeRedisStore
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
],
"devDependencies": {
"@fastify/pre-commit": "^2.1.0",
"@redis/client": "^1.6.0",
"@sinonjs/fake-timers": "^14.0.0",
"@types/node": "^22.0.0",
"c8": "^10.1.2",
Expand Down
52 changes: 52 additions & 0 deletions store/NodeRedisStore.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
'use strict'

/**
* When using node-redis, you need to initialize the client with the rateLimit script like this:
* ```js
* const redis = createClient({
* scripts: {
* rateLimit: rateLimit.NodeRedisStore.rateLimitScript
* }
* });
* ```
*/

const { lua } = require('./RedisStore')
const { defineScript } = require('@redis/client')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not add a depedency to @redis/client here. we should be taking an instance of that in the constructor instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah same as #413 (comment)

The goal is to not depend on the lib

Only the client that's passed should be used


const rateLimitScript = defineScript({
NUMBER_OF_KEYS: 1,
SCRIPT: lua,
transformArguments (key, timeWindow, max, continueExceeding, exponentialBackoff) {
return [key, String(timeWindow), String(max), String(continueExceeding), String(exponentialBackoff)]
},
transformReply (reply) {
return reply
},
})

function NodeRedisStore (continueExceeding, exponentialBackoff, redis, key = 'fastify-rate-limit-') {
this.continueExceeding = continueExceeding
this.exponentialBackoff = exponentialBackoff
this.redis = redis
this.key = key
}

NodeRedisStore.prototype.incr = function (ip, cb, timeWindow, max) {
this
.redis
.rateLimit(this.key + ip, timeWindow, max, this.continueExceeding, this.exponentialBackoff)
.then(result => {
cb(null, { current: result[0], ttl: result[1] })
})
.catch(err => {
cb(err, null)
})
}

NodeRedisStore.prototype.child = function (routeOptions) {
return new NodeRedisStore(routeOptions.continueExceeding, routeOptions.exponentialBackoff, this.redis, `${this.key}${routeOptions.routeInfo.method}${routeOptions.routeInfo.url}-`)
}

module.exports = NodeRedisStore
module.exports.rateLimitScript = rateLimitScript
1 change: 1 addition & 0 deletions store/RedisStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,4 @@ RedisStore.prototype.child = function (routeOptions) {
}

module.exports = RedisStore
module.exports.lua = lua
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need lua script for NodeRedisStore instead of copy&paste. Both of those should always be the same for all Redis clients.

Should we move lua script to other place instead?

Loading