diff --git a/package.json b/package.json index 312da65..4237976 100644 --- a/package.json +++ b/package.json @@ -16,10 +16,11 @@ "mocha": "^8.3.2", "pre-commit": "^1.2.2", "redis": "^3.1.2", + "redis4": "npm:redis@4", "sinon": "^10.0.0" }, "scripts": { - "test": "mocha test/test-ioredis.js test/test-node-redis.js", + "test": "mocha test/test-ioredis.js test/test-node-redis.js test/test-node-redis4.js", "test-cluster": "mocha test/test-cluster.js", "build": "node ./build/hashLua.js ./lua/rollingLimit.lua", "lint": "eslint .", diff --git a/rollingLimit.js b/rollingLimit.js index 54bc0c7..c973714 100644 --- a/rollingLimit.js +++ b/rollingLimit.js @@ -33,11 +33,25 @@ class RollingLimit { if(!/:$/.test(this.prefix)) this.prefix += ':'; this.force = options.force ? 'true' : 'false'; if (!this.redis.evalshaAsync) { - if (this.redis.Promise) { + if (typeof this.redis.executeScript !== 'undefined') { + // node-redis @4...; already promisified, but different args + this.redis.pttlAsync = this.redis.PTTL; + + const nodeRedis4Polyfill = (method, script, ...args) => { + return this.redis[method](script, { + keys: args.slice(1, args[0] + 1), + arguments: args.slice(args[0] + 1).map((a) => String(a)), + }); + } + + this.redis.evalshaAsync = (script, ...args) => nodeRedis4Polyfill('evalSha', script, ...args); + this.redis.evalAsync = (script, ...args) => nodeRedis4Polyfill('eval', script, ...args); + } else if (this.redis.Promise) { // ioredis; already promisified this.redis.evalshaAsync = this.redis.evalsha; this.redis.evalAsync = this.redis.eval; } else { + // node-redis @3... const promisify = require('util').promisify; this.redis.evalshaAsync = promisify(this.redis.evalsha).bind(this.redis); this.redis.evalAsync = promisify(this.redis.eval).bind(this.redis); @@ -79,7 +93,6 @@ class RollingLimit { amount, // ARGV[3] this.force // ARGV[4] ]; - return this.redis.evalshaAsync(luaScript.sha1, ...redisKeysAndArgs) .catch((err) => { if (err instanceof Error && err.message.includes('NOSCRIPT')) { diff --git a/test/_test-common.js b/test/_test-common.js index fbf013d..34bd071 100644 --- a/test/_test-common.js +++ b/test/_test-common.js @@ -55,7 +55,10 @@ function makeTestSuite(name, redisClient, lag) { redis: redisClient, prefix: prefix }); - redisClient.pttlAsync = promisify(redisClient.pttl).bind(redisClient); + + if (typeof redisClient.pttlAsync === 'undefined') { + redisClient.pttlAsync = promisify(redisClient.pttl).bind(redisClient); + } return limiter.use('ttl') .then((res) => { @@ -152,7 +155,11 @@ function makeTestSuite(name, redisClient, lag) { const NAME = 'clockSkewTest'; // Set the date into the future - const clock = sinon.useFakeTimers(Date.now() + 300); + const clock = sinon.useFakeTimers({ + now: Date.now() + 300, + // Exclude 'setImmediate' as it is used by native promises + toFake: ['setTimeout', 'setInterval', 'Date', 'nextTick'] + }); return limiter.use(NAME, 1) .then((res) => { diff --git a/test/test-node-redis4.js b/test/test-node-redis4.js new file mode 100644 index 0000000..ab87e16 --- /dev/null +++ b/test/test-node-redis4.js @@ -0,0 +1,17 @@ +const { createClient } = require("redis4"); +const { makeTestSuite } = require('./_test-common.js'); + +const port = Number(process.env.PORT) || 6379; + +const redisClient = createClient({ + socket: { port }, +}); + +redisClient.on('error', (e) => { + console.error(`Error connecting to Redis (@4). Did you start a local server on ${port}?`); + console.error(e); +}); + +redisClient.connect().then(() => { + makeTestSuite('single client (node-redis@4)', redisClient, 0 /* lag */); +}); diff --git a/yarn.lock b/yarn.lock index 50a80db..1345e53 100644 --- a/yarn.lock +++ b/yarn.lock @@ -38,6 +38,40 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" +"@redis/bloom@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.2.0.tgz#d3fd6d3c0af3ef92f26767b56414a370c7b63b71" + integrity sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg== + +"@redis/client@1.5.8": + version "1.5.8" + resolved "https://registry.yarnpkg.com/@redis/client/-/client-1.5.8.tgz#a375ba7861825bd0d2dc512282b8bff7b98dbcb1" + integrity sha512-xzElwHIO6rBAqzPeVnCzgvrnBEcFL1P0w8P65VNLRkdVW8rOE58f52hdj0BDgmsdOm4f1EoXPZtH4Fh7M/qUpw== + dependencies: + cluster-key-slot "1.1.2" + generic-pool "3.9.0" + yallist "4.0.0" + +"@redis/graph@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@redis/graph/-/graph-1.1.0.tgz#cc2b82e5141a29ada2cce7d267a6b74baa6dd519" + integrity sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg== + +"@redis/json@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@redis/json/-/json-1.0.4.tgz#f372b5f93324e6ffb7f16aadcbcb4e5c3d39bda1" + integrity sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw== + +"@redis/search@1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@redis/search/-/search-1.1.3.tgz#b5a6837522ce9028267fe6f50762a8bcfd2e998b" + integrity sha512-4Dg1JjvCevdiCBTZqjhKkGoC5/BcB7k9j99kdMnaXFXg8x4eyOIVg9487CMv7/BUVkFLZCaIh8ead9mU15DNng== + +"@redis/time-series@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.0.4.tgz#af85eb080f6934580e4d3b58046026b6c2b18717" + integrity sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng== + "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.8.1": version "1.8.3" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" @@ -66,11 +100,6 @@ resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ== -"@types/color-name@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" - integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== - "@ungap/promise-all-settled@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" @@ -246,6 +275,11 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +cluster-key-slot@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" + integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== + cluster-key-slot@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" @@ -565,6 +599,11 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +generic-pool@3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.9.0.tgz#36f4a678e963f4fdb8707eab050823abc4e8f5e4" + integrity sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g== + get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -874,7 +913,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.1.1: +ms@2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -1060,6 +1099,18 @@ redis-parser@^3.0.0: dependencies: redis-errors "^1.0.0" +"redis4@npm:redis@4": + version "4.6.7" + resolved "https://registry.yarnpkg.com/redis/-/redis-4.6.7.tgz#c73123ad0b572776223f172ec78185adb72a6b57" + integrity sha512-KrkuNJNpCwRm5vFJh0tteMxW8SaUzkm5fBH7eL5hd/D0fAkzvapxbfGPP/r+4JAXdQuX7nebsBkBqA2RHB7Usw== + dependencies: + "@redis/bloom" "1.2.0" + "@redis/client" "1.5.8" + "@redis/graph" "1.1.0" + "@redis/json" "1.0.4" + "@redis/search" "1.1.3" + "@redis/time-series" "1.0.4" + redis@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/redis/-/redis-3.1.2.tgz#766851117e80653d23e0ed536254677ab647638c" @@ -1374,16 +1425,16 @@ y18n@^5.0.5: resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== +yallist@4.0.0, yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - yargs-parser@20.2.4: version "20.2.4" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"