diff --git a/lib/db.js b/lib/db.js index df556bd..42c6503 100644 --- a/lib/db.js +++ b/lib/db.js @@ -24,7 +24,8 @@ function normalizeType(params) { 'per_interval', 'interval', 'size', - 'unlimited' + 'unlimited', + 'discrete' ]); INTERVAL_SHORTCUTS.forEach(ish => { @@ -100,7 +101,11 @@ class LimitDB { const now = Date.now(); const deltaMS = Math.max(now - bucket.lastDrip, 0); const dripAmount = deltaMS * (type.per_interval / type.interval); - const content = Math.min(bucket.content + dripAmount, type.size); + var content = bucket.content; + + if (!type.discrete || dripAmount >= type.per_interval) { + content = Math.floor(Math.min(bucket.content + dripAmount, type.size)); + } return { content: content, @@ -204,7 +209,7 @@ class LimitDB { if (err) { return callback(err); } callback(null, { conformant: bucket.lastConformant, - remaining: Math.floor(bucket.content), + remaining: bucket.content, reset: bucket.reset, limit: typeParams.size }); diff --git a/test/discrete_example.tests.js b/test/discrete_example.tests.js new file mode 100644 index 0000000..d96f55e --- /dev/null +++ b/test/discrete_example.tests.js @@ -0,0 +1,46 @@ +const LimitDB = require('../lib/db'); +const MockDate = require('mockdate'); +const assert = require('chai').assert; + +const types = { + ip: { + size: 5, + per_interval: 5, + interval: 500, + discrete: true + } +}; + +describe('when the fill rate is discrete', () => { + afterEach(function () { + MockDate.reset(); + }); + + const db = new LimitDB({ + inMemory: true, + types + }); + + beforeEach(function(done) { + MockDate.set(Date.now()); + db.take({ type: 'ip', key: '21.17.65.41', count: 5 }, done); + }); + + it('should not add less than the per_interval amount', function(done) { + MockDate.set(Date.now() + 150); + db.status({ type: 'ip', prefix: '21.17.65.41' }, (err, result) => { + if (err) { return done(err); } + assert.equal(result.items[0].remaining, 0); + done(); + }); + }); + + it('should add the per_interval amount after the elapsed interval', function(done) { + MockDate.set(Date.now() + 500); + db.status({ type: 'ip', prefix: '21.17.65.41' }, (err, result) => { + if (err) { return done(err); } + assert.equal(result.items[0].remaining, 5); + done(); + }); + }); +});