made a util for the rate limiter to get config

This commit is contained in:
Tanya Byrne
2020-08-19 16:18:13 +01:00
parent 413144a9d8
commit d1ab3f2ff6
2 changed files with 87 additions and 42 deletions

View File

@@ -5,53 +5,13 @@
* in future
*/
import { RequestHandler } from 'express';
import redis from 'redis';
import asyncHandler from 'express-async-handler';
import { RateLimiterRedis, RateLimiterMemory } from 'rate-limiter-flexible';
import { HitRateLimitException } from '../exceptions';
import { RedisNotFoundException } from '../exceptions';
import env from '../env';
const redisClient = redis.createClient({
enable_offline_queue: false,
host: env.REDIS_HOST,
port: env.REDIS_PORT,
password: env.REDIS_PASSWORD,
});
import rateLimiterConfig from '../utils/get-rate-limiter-config';
const rateLimiter: RequestHandler = asyncHandler(async (req, res, next) => {
// options for the rate limiter are set below. Opts can be found
// at https://github.com/animir/node-rate-limiter-flexible/wiki/Options
// more basic for memory store
const opts = {
points: env.CONSUMED_POINTS_LIMIT, // Number of points
duration: env.CONSUMED_RESET_DURATION, // Number of seconds before consumed points are reset.
keyPrefix: 'rlflx', // must be unique for limiters with different purpose
};
let rateLimiterSet = new RateLimiterMemory(opts);
if (env.RATE_LIMIT_TYPE === 'redis') {
const redisOpts = {
...opts,
storeClient: redisClient,
// Custom
execEvenly: env.EXEC_EVENLY, // delay actions after first action - this may need adjusting (leaky bucket)
blockDuration: env.BLOCK_POINT_DURATION, // Do not block if consumed more than points
inmemoryBlockOnConsumed: env.INMEMORY_BLOCK_CONSUMED, // eg if 200 points consumed
inmemoryBlockDuration: env.INMEMEMORY_BLOCK_DURATION, // block for certain amount of seconds
};
rateLimiterSet = new RateLimiterRedis(redisOpts);
// first need to check that redis is running!
if (!redisClient) {
throw new RedisNotFoundException('Redis client does not exist');
}
}
try {
await rateLimiterSet.consume(req.ip);
await rateLimiterConfig.consume(req.ip);
} catch (rejRes) {
// If there is no error, rateLimiterRedis promise rejected with number of ms before next request allowed
const secs = Math.round(rejRes.msBeforeNext / 1000) || 1;

View File

@@ -0,0 +1,85 @@
import redis from 'redis';
import {
RateLimiterRedis,
RateLimiterMemory,
IRateLimiterStoreOptions,
IRateLimiterOptions,
} from 'rate-limiter-flexible';
import { RedisNotFoundException } from '../exceptions';
import env from '../env';
// options for the rate limiter are set below. Opts can be found
// at https://github.com/animir/node-rate-limiter-flexible/wiki/Options
const redisClient = redis.createClient({
enable_offline_queue: false,
host: env.REDIS_HOST,
port: env.REDIS_PORT,
password: env.REDIS_PASSWORD,
});
let rateLimiterConfig = new RateLimiterMemory(getRateLimiterConfig());
// need to pick redis or memory
if (env.RATE_LIMIT_TYPE === 'redis') {
rateLimiterConfig = new RateLimiterRedis(getRateLimiterRedisConfig());
}
// first need to check that redis is running!
if (!redisClient) {
throw new RedisNotFoundException('Redis client does not exist');
}
export default rateLimiterConfig;
function getRateLimiterConfig(): IRateLimiterOptions {
const config: any = {};
config.keyPrefix = 'rlflx';
for (const [key, value] of Object.entries(env)) {
if (key === 'CONSUMED_POINTS_LIMIT') {
config.points = value;
continue;
}
if (key === 'CONSUMED_RESET_DURATION') {
config.duration = value;
continue;
}
}
return config;
}
function getRateLimiterRedisConfig(): IRateLimiterStoreOptions {
const redisConfig: any = {};
redisConfig.keyPrefix = 'rlflx';
redisConfig.storeClient = redisClient;
for (const [key, value] of Object.entries(env)) {
if (key === 'CONSUMED_POINTS_LIMIT') {
redisConfig.points = value;
continue;
}
if (key === 'CONSUMED_RESET_DURATION') {
redisConfig.duration = value;
continue;
}
if (key === 'EXEC_EVENLY') {
redisConfig.execEvenly = value;
continue;
}
if (key === 'BLOCK_POINT_DURATION') {
redisConfig.blockDuration = value;
continue;
}
if (key === 'INMEMORY_BLOCK_CONSUMED') {
redisConfig.inmemoryBlockOnConsumed = value;
continue;
}
if (key === 'INMEMEMORY_BLOCK_DURATION') {
redisConfig.inmemoryBlockDuration = value;
continue;
}
}
return redisConfig;
}