mirror of
https://github.com/directus/directus.git
synced 2026-01-25 19:58:23 -05:00
made a util for the rate limiter to get config
This commit is contained in:
@@ -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;
|
||||
|
||||
85
api/src/utils/get-rate-limiter-config.ts
Normal file
85
api/src/utils/get-rate-limiter-config.ts
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user