Socket
Socket
Sign inDemoInstall

rate-limiter-flexible

Package Overview
Dependencies
0
Maintainers
1
Versions
163
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.8.3 to 0.9.0

lib/RateLimiterMongo.js

3

.eslintrc.json

@@ -25,4 +25,5 @@ {

"allowModules": ["mocha", "chai", "redis-mock"]
}]
}],
"node/no-unsupported-features": "off"
}
}
const RateLimiterRedis = require('./lib/RateLimiterRedis');
const RateLimiterMongo = require('./lib/RateLimiterMongo');
const { RateLimiterClusterMaster, RateLimiterCluster } = require('./lib/RateLimiterCluster');

@@ -7,5 +8,6 @@ const RateLimiterMemory = require('./lib/RateLimiterMemory');

RateLimiterRedis,
RateLimiterMongo,
RateLimiterMemory,
RateLimiterClusterMaster,
RateLimiterCluster,
};
};
const Record = require('./Record');
const Res = require('./Res');
const RateLimiterRes = require('../../RateLimiterRes');

@@ -19,3 +19,3 @@ module.exports = class MemoryStorage {

return new Res(this._storage[key].value, msBeforeExpires);
return new RateLimiterRes(0, msBeforeExpires, this._storage[key].value, false);
}

@@ -37,3 +37,3 @@ clearTimeout(this._storage[key].timeoutId);

return new Res(value, durationMs);
return new RateLimiterRes(0, durationMs, this._storage[key].value, true);
}

@@ -49,3 +49,3 @@

const msBeforeExpires = this._storage[key].expiresAt.getTime() - new Date().getTime();
return new Res(this._storage[key].value, msBeforeExpires);
return new RateLimiterRes(0, msBeforeExpires, this._storage[key].value, false);
}

@@ -52,0 +52,0 @@ return null;

@@ -40,2 +40,4 @@ /**

msBeforeNext: res.msBeforeNext,
consumedPoints: res.consumedPoints,
isFirstInDuration: res.isFirstInDuration,
},

@@ -115,9 +117,15 @@ });

clearTimeout(this._promises[msg.id].timeoutId);
const res = new RateLimiterRes(
msg.data.remainingPoints,
msg.data.msBeforeNext,
msg.data.consumedPoints,
msg.data.isFirstInDuration // eslint-disable-line comma-dangle
);
switch (msg.type) {
case 'resolve':
this._promises[msg.id].resolve(new RateLimiterRes(msg.data.remainingPoints, msg.data.msBeforeNext));
this._promises[msg.id].resolve(res);
break;
case 'reject':
this._promises[msg.id].reject(new RateLimiterRes(msg.data.remainingPoints, msg.data.msBeforeNext));
this._promises[msg.id].reject(res);
break;

@@ -124,0 +132,0 @@ default:

@@ -20,10 +20,9 @@ const RateLimiterAbstract = require('./RateLimiterAbstract');

const rlKey = this.getKey(key);
const isFirstInDuration = this._memoryStorage.get(rlKey) === null;
const storageRes = this._memoryStorage.incrby(rlKey, pointsToConsume, this.duration);
const res = new RateLimiterRes(this.points - storageRes.consumedPoints, storageRes.msBeforeNext);
const res = this._memoryStorage.incrby(rlKey, pointsToConsume, this.duration);
res.remainingPoints = this.points - res.consumedPoints;
if (storageRes.consumedPoints > this.points) {
reject(new RateLimiterRes(0, storageRes.msBeforeNext));
} else if (this.execEvenly && storageRes.msBeforeNext > 0 && !isFirstInDuration) {
const delay = Math.ceil(storageRes.msBeforeNext / ((this.points - storageRes.consumedPoints) + 2));
if (res.consumedPoints > this.points) {
reject(new RateLimiterRes(0, res.msBeforeNext));
} else if (this.execEvenly && res.msBeforeNext > 0 && !res.isFirstInDuration) {
const delay = Math.ceil(res.msBeforeNext / ((this.points - res.consumedPoints) + 2));

@@ -41,3 +40,4 @@ setTimeout(resolve, delay, res);

const res = this._memoryStorage.incrby(rlKey, points, this.duration);
resolve(new RateLimiterRes(this.points - res.consumedPoints, res.msBeforeNext));
res.remainingPoints = this.points - res.consumedPoints;
resolve(res);
});

@@ -50,3 +50,4 @@ }

const res = this._memoryStorage.incrby(rlKey, -points, this.duration);
resolve(new RateLimiterRes(this.points - res.consumedPoints, res.msBeforeNext));
res.remainingPoints = this.points - res.consumedPoints;
resolve(res);
});

@@ -53,0 +54,0 @@ }

@@ -28,7 +28,7 @@ const RateLimiterAbstract = require('./RateLimiterAbstract');

const res = new RateLimiterRes();
let isFirstInDuration = resSet === 'OK';
res.isFirstInDuration = resSet === 'OK';
res.remainingPoints = Math.max(this.points - consumed, 0);
if (resTtlMs === -1) { // If rlKey created by incrby() not by set()
isFirstInDuration = true;
res.isFirstInDuration = true;
res.msBeforeNext = this.duration;

@@ -48,3 +48,3 @@ this.redis.expire(rlKey, this.duration);

reject(res);
} else if (this.execEvenly && res.msBeforeNext > 0 && !isFirstInDuration) {
} else if (this.execEvenly && res.msBeforeNext > 0 && !res.isFirstInDuration) {
const delay = Math.ceil(res.msBeforeNext / (res.remainingPoints + 2));

@@ -160,7 +160,7 @@ setTimeout(resolve, delay, res);

return new Promise((resolve, reject) => {
this.redis.incrby(rlKey, points, (err, value) => {
this.redis.incrby(rlKey, points, (err, consumedPoints) => {
if (err) {
handleRedisError.call(this, 'penalty', resolve, reject, key, points);
} else {
resolve(value);
resolve(new RateLimiterRes(this.points - consumedPoints, 0, consumedPoints));
}

@@ -174,7 +174,7 @@ });

return new Promise((resolve, reject) => {
this.redis.incrby(rlKey, -points, (err, value) => {
this.redis.incrby(rlKey, -points, (err, consumedPoints) => {
if (err) {
handleRedisError.call(this, 'reward', resolve, reject, key, points);
} else {
resolve(value);
resolve(new RateLimiterRes(this.points - consumedPoints, 0, consumedPoints));
}

@@ -181,0 +181,0 @@ });

module.exports = class RateLimiterRes {
constructor(remainingPoints, msBeforeNext) {
constructor(remainingPoints, msBeforeNext, consumedPoints, isFirstInDuration) {
this.remainingPoints = typeof remainingPoints === 'undefined' ? 0 : remainingPoints; // Remaining points in current duration
this.msBeforeNext = typeof msBeforeNext === 'undefined' ? 0 : msBeforeNext; // Milliseconds before next action
this.consumedPoints = typeof consumedPoints === 'undefined' ? 0 : consumedPoints; // Consumed points in current duration
this.isFirstInDuration = typeof isFirstInDuration === 'undefined' ? false : isFirstInDuration;
}

@@ -24,2 +26,19 @@

}
get consumedPoints() {
return this._consumedPoints;
}
set consumedPoints(p) {
this._consumedPoints = p;
return this;
}
get isFirstInDuration() {
return this._isFirstInDuration;
}
set isFirstInDuration(value) {
this._isFirstInDuration = Boolean(value);
}
};
{
"name": "rate-limiter-flexible",
"version": "0.8.3",
"version": "0.9.0",
"description": "Flexible API rate limiter backed by Redis for distributed node.js applications",

@@ -30,5 +30,2 @@ "main": "index.js",

"homepage": "https://github.com/animir/node-rate-limiter-flexible#readme",
"engines": {
"node": "^6.0.0"
},
"devDependencies": {

@@ -44,4 +41,5 @@ "chai": "^4.1.2",

"mocha": "^5.1.1",
"redis-mock": "^0.22.0"
"redis-mock": "^0.22.0",
"sinon": "^5.0.10"
}
}

@@ -12,3 +12,3 @@ [![Build Status](https://travis-ci.org/animir/node-rate-limiter-flexible.png)](https://travis-ci.org/animir/node-rate-limiter-flexible)

Flexible rate limiter and anti-DDoS protector works in process
_Memory_, _Cluster_ or _Redis_ allows to control requests rate in single process or distributed environment.
_Memory_, _Cluster_, _MongoDB_ or _Redis_ allows to control requests rate in single process or distributed environment.

@@ -26,3 +26,3 @@ It uses **fixed window** as it is much faster than rolling window.

* no prod dependencies
* Redis errors don't result to broken app if `insuranceLimiter` set up
* Redis and Mongo errors don't result to broken app if `insuranceLimiter` set up
* useful `penalty` and `reward` methods to change limits on some results of an action

@@ -34,5 +34,5 @@

By `bombardier -c 1000 -l -d 10s -r 2500 -t 5s http://127.0.0.1:3000/pricing`
By `bombardier -c 1000 -l -d 30s -r 2000 -t 5s http://127.0.0.1:3000/pricing`
Test with 1000 concurrent requests with maximum 2500 requests per sec during 10 seconds
Test with 1000 concurrent requests with maximum 2000 requests per sec during 30 seconds

@@ -133,2 +133,57 @@ ```text

### RateLimiterMongo
It supports `mongodb` native and `mongoose` packages
[See RateLimiterMongo benchmark here](https://github.com/animir/node-rate-limiter-flexible/blob/master/MONGO.md)
```javascript
const { RateLimiterMongo } = require('rate-limiter-flexible');
const mongoose = require('mongoose');
const mongoOpts = {
reconnectTries: Number.MAX_VALUE, // Never stop trying to reconnect
reconnectInterval: 100, // Reconnect every 100ms
};
mongoose.createConnection('mongodb://localhost:27017/' + RateLimiterMongo.getDbName(), mongoOpts)
.then((mongo) => {
const opts = {
mongo: mongo,
points: 10, // Number of points
duration: 1, // Per second(s)
};
const rateLimiterMongo = new RateLimiterMongo(opts);
// Usage is the same as for RateLimiterRedis
});
// Or with native mongodb package
const { MongoClient } = require('mongodb');
const mongoOpts = {
useNewUrlParser: true,
reconnectTries: Number.MAX_VALUE, // Never stop trying to reconnect
reconnectInterval: 100, // Reconnect every 100ms
};
MongoClient.connect(
'mongodb://localhost:27017',
mongoOpts
).then((mongo) => {
const opts = {
mongo: mongo,
points: 10, // Number of points
duration: 1, // Per second(s)
};
const rateLimiterMongo = new RateLimiterMongo(opts);
// Usage is the same as for RateLimiterRedis
rateLimiterMongo.consume(remoteAddress)
.then(() => {})
.catch(() => {});
});
```
### RateLimiterCluster

@@ -233,3 +288,5 @@

msBeforeNext: 250, // Number of milliseconds before next action can be done
remainingPoints: 0 // Number of remaining points in current duration
remainingPoints: 0, // Number of remaining points in current duration
consumedPoints: 5, // Number of consumed points in current duration
isFirstInDuration: false, // action is first in current duration
}

@@ -277,3 +334,3 @@ ````

Make sure you've launched `npm run eslint`, before creating PR.
Make sure you've launched `npm run eslint` before creating PR, all errors have to be fixed.

@@ -280,0 +337,0 @@ You can try to run `npm run eslint-fix` to fix some issues.

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc