24 lines
1.0 KiB
TypeScript
24 lines
1.0 KiB
TypeScript
import { Inject, Injectable } from "@nestjs/common";
|
|
import { RedisService } from "../redis/redis.service.js";
|
|
|
|
@Injectable()
|
|
export class ChatRateLimiter {
|
|
constructor(@Inject(RedisService) private readonly redis: RedisService) {}
|
|
async consume(accountId: string, sessionId: string): Promise<boolean> {
|
|
const prefix = process.env.REDIS_KEY_PREFIX ?? "drift:auth:";
|
|
const max = Number(process.env.CHAT_MESSAGE_RATE_LIMIT ?? 30);
|
|
const ttl = Number(process.env.CHAT_MESSAGE_RATE_WINDOW_SECONDS ?? 60);
|
|
const keys = [
|
|
`${prefix}chat:account:${accountId}`,
|
|
`${prefix}chat:session:${sessionId}`,
|
|
];
|
|
const result = await this.redis.executeWithDeadline((client) =>
|
|
client.eval(
|
|
`for _,k in ipairs(KEYS) do if tonumber(redis.call('GET',k) or '0')+1>tonumber(ARGV[1]) then return 0 end end; for _,k in ipairs(KEYS) do local n=redis.call('INCR',k); if n==1 then redis.call('EXPIRE',k,ARGV[2]) end end; return 1`,
|
|
{ keys, arguments: [String(max), String(ttl)] },
|
|
),
|
|
);
|
|
return Number(result) === 1;
|
|
}
|
|
}
|