rate-limiter-flexible
Advanced tools
Comparing version 0.14.7 to 0.15.0
@@ -32,2 +32,13 @@ /** | ||
const masterSendToWorker = function (worker, msg, type, res) { | ||
let data; | ||
if (res === null) { | ||
data = null; | ||
} else { | ||
data = { | ||
remainingPoints: res.remainingPoints, | ||
msBeforeNext: res.msBeforeNext, | ||
consumedPoints: res.consumedPoints, | ||
isFirstInDuration: res.isFirstInDuration, | ||
}; | ||
} | ||
worker.send({ | ||
@@ -38,8 +49,3 @@ channel, | ||
type, | ||
data: { | ||
remainingPoints: res.remainingPoints, | ||
msBeforeNext: res.msBeforeNext, | ||
consumedPoints: res.consumedPoints, | ||
isFirstInDuration: res.isFirstInDuration, | ||
}, | ||
data, | ||
}); | ||
@@ -99,2 +105,5 @@ }; | ||
break; | ||
case 'get': | ||
promise = this._rateLimiters[msg.keyPrefix].get(msg.data.key); | ||
break; | ||
default: | ||
@@ -122,8 +131,13 @@ return false; | ||
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 | ||
); | ||
let res; | ||
if (msg.data === null) { | ||
res = null; | ||
} else { | ||
res = new RateLimiterRes( | ||
msg.data.remainingPoints, | ||
msg.data.msBeforeNext, | ||
msg.data.consumedPoints, | ||
msg.data.isFirstInDuration // eslint-disable-line comma-dangle | ||
); | ||
} | ||
@@ -159,3 +173,3 @@ switch (msg.type) { | ||
const getPromiseId = function () { | ||
const savePromise = function (resolve, reject) { | ||
const hrtime = process.hrtime(); | ||
@@ -168,6 +182,2 @@ let id = hrtime[0].toString() + hrtime[1].toString(); | ||
return id; | ||
}; | ||
const savePromise = function (id, resolve, reject) { | ||
this._promises[id] = { | ||
@@ -181,2 +191,4 @@ resolve, | ||
}; | ||
return id; | ||
}; | ||
@@ -192,2 +204,4 @@ | ||
cluster.setMaxListeners(0); | ||
cluster.on('message', (worker, msg) => { | ||
@@ -252,4 +266,3 @@ if (msg && msg.channel === channel && msg.type === 'init') { | ||
return new Promise((resolve, reject) => { | ||
const id = getPromiseId.call(this); | ||
savePromise.call(this, id, resolve, reject); | ||
const id = savePromise.call(this, resolve, reject); | ||
@@ -262,4 +275,3 @@ workerSendToMaster.call(this, 'consume', id, key, pointsToConsume); | ||
return new Promise((resolve, reject) => { | ||
const id = getPromiseId.call(this); | ||
savePromise.call(this, id, resolve, reject); | ||
const id = savePromise.call(this, resolve, reject); | ||
@@ -272,4 +284,3 @@ workerSendToMaster.call(this, 'penalty', id, key, points); | ||
return new Promise((resolve, reject) => { | ||
const id = getPromiseId.call(this); | ||
savePromise.call(this, id, resolve, reject); | ||
const id = savePromise.call(this, resolve, reject); | ||
@@ -282,4 +293,3 @@ workerSendToMaster.call(this, 'reward', id, key, points); | ||
return new Promise((resolve, reject) => { | ||
const id = getPromiseId.call(this); | ||
savePromise.call(this, id, resolve, reject); | ||
const id = savePromise.call(this, resolve, reject); | ||
@@ -289,2 +299,10 @@ workerSendToMaster.call(this, 'block', id, key, secDuration); | ||
} | ||
get(key) { | ||
return new Promise((resolve, reject) => { | ||
const id = savePromise.call(this, resolve, reject); | ||
workerSendToMaster.call(this, 'get', id, key); | ||
}); | ||
} | ||
} | ||
@@ -296,2 +314,1 @@ | ||
}; | ||
@@ -63,3 +63,7 @@ const RateLimiterStoreAbstract = require('./RateLimiterStoreAbstract'); | ||
if (typeof result.value === 'undefined') { | ||
[doc] = result.ops; // ops set on replaceOne | ||
if (result._id) { | ||
doc = result; | ||
} else { | ||
[doc] = result.ops; // ops set on replaceOne | ||
} | ||
} else { | ||
@@ -156,11 +160,10 @@ doc = result.value; | ||
_block(rlKey, initPoints, msDuration) { | ||
return new Promise((resolve, reject) => { | ||
this._upsert(rlKey, initPoints, msDuration, true) | ||
.then(() => { | ||
resolve(new RateLimiterRes(0, msDuration, initPoints)); | ||
}) | ||
.catch((err) => { | ||
this._handleError(err, 'block', resolve, reject, this.parseKey(rlKey), initPoints); | ||
}); | ||
_get(rlKey) { | ||
if (!this._collection) { | ||
return Promise.reject(Error('Mongo connection is not established')); | ||
} | ||
return this._collection.findOne({ | ||
key: rlKey, | ||
expire: { $gt: new Date() }, | ||
}); | ||
@@ -167,0 +170,0 @@ } |
@@ -69,3 +69,9 @@ const RateLimiterStoreAbstract = require('./RateLimiterStoreAbstract'); | ||
const res = new RateLimiterRes(); | ||
const row = result[2][0]; | ||
let row; | ||
if (result.length === 1) { | ||
[row] = result; | ||
} else { | ||
const [, , rows] = result; | ||
[row] = rows; | ||
} | ||
@@ -116,4 +122,28 @@ res.isFirstInDuration = changedPoints === row.points; | ||
} | ||
_get(rlKey) { | ||
if (!this._tableCreated) { | ||
return Promise.reject(Error('Table is not created yet')); | ||
} | ||
const q = 'SELECT points, expire FROM ?? WHERE `key` = ? AND `expire` > ?'; | ||
return new Promise((resolve, reject) => { | ||
this.client.query( | ||
q, | ||
[this.tableName, rlKey, new Date()], | ||
(err, res) => { | ||
if (err) { | ||
reject(err); | ||
} else if (res.length === 0) { | ||
resolve(null); | ||
} else { | ||
resolve(res); | ||
} | ||
} // eslint-disable-line | ||
); | ||
}); | ||
} | ||
} | ||
module.exports = RateLimiterMySQL; |
{ | ||
"name": "rate-limiter-flexible", | ||
"version": "0.14.7", | ||
"version": "0.15.0", | ||
"description": "Flexible API rate limiter backed by Redis for distributed node.js applications", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -30,3 +30,3 @@ [![Build Status](https://travis-ci.org/animir/node-rate-limiter-flexible.png)](https://travis-ci.org/animir/node-rate-limiter-flexible) | ||
* database errors don't result to broken app if `insuranceLimiter` set up | ||
* useful `block`, `penalty` and `reward` methods | ||
* useful `get`, `block`, `penalty` and `reward` methods | ||
@@ -155,2 +155,15 @@ ### Links | ||
### rateLimiter.get(key) | ||
Get `RateLimiterRes` in current duration. | ||
Returns Promise, which: | ||
* **resolved** with `RateLimiterRes` if key is set | ||
* **resolved** with `null` if key is NOT set or expired | ||
* **rejected** only for database limiters if `insuranceLimiter` isn't setup: when some error happened, where reject reason `rejRes` is Error object | ||
* **rejected** only for RateLimiterCluster if `insuranceLimiter` isn't setup: when `timeoutMs` exceeded, where reject reason `rejRes` is Error object | ||
Arguments: | ||
* `key` is usually IP address or some unique client id | ||
### rateLimiter.penalty(key, points = 1) | ||
@@ -157,0 +170,0 @@ |
93239
27
1437
530