var error = require("http-error"); var _ = require("lodash"); /** * In memory rate limiter as connect middleware */ module.exports = ratelimit; function ratelimit(key, duration, max) { var requests = {}; setInterval(function() { _.forIn(requests, function (requestsForHandle, key) { var totalToSplice = 0; var expireTime = Date.now() - duration; /* Requests are already sorted by date as they are appended, so we just loop until we find one that shouldn't have expired and splice them from the list */ for (var i = 0; i < requestsForHandle.length; i++) { if (requestsForHandle[i] >= expireTime) break; totalToSplice++; } requests[key].splice(0, totalToSplice); if (requests[key].length == 0) { delete requests[key]; } }); }, 10); return function(req, res, next) { var handle = req.params[key]; requests[handle] = requests[handle] || []; if (requests[handle].length >= max) { var err = new error.TooManyRequests("Rate limit exceeded"); err.retryIn = Math.min(duration, 5000); return next(err); } requests[handle].push(Date.now()); return next(); }; }