53 lines
1.6 KiB
TypeScript
53 lines
1.6 KiB
TypeScript
import { Middleware } from "@lib/router.ts";
|
|
import log from "@shared/utils/logger.ts";
|
|
|
|
const requestCounts: Partial<
|
|
Record<string, { count: number; lastReset: number }>
|
|
> = {};
|
|
|
|
const MAX_REQUESTS_PER_WINDOW = 300;
|
|
const RATE_LIMIT_WINDOW = 60000;
|
|
|
|
const rateLimitMiddleware: Middleware = async (c, next) => {
|
|
const hostnameOpt = c.hostname;
|
|
|
|
if (hostnameOpt.isSome()) {
|
|
const hostname = hostnameOpt.value;
|
|
|
|
const clientCount = requestCounts[hostname];
|
|
const now = Date.now();
|
|
|
|
if (!clientCount || now - clientCount.lastReset > RATE_LIMIT_WINDOW) {
|
|
requestCounts[hostname] = { count: 1, lastReset: now };
|
|
} else if (clientCount.count < MAX_REQUESTS_PER_WINDOW) {
|
|
clientCount.count++;
|
|
} else if (c.preferredType.isSome()) {
|
|
log.info(`client ${hostname} is rate limeted`);
|
|
switch (c.preferredType.value) {
|
|
case "html": {
|
|
return c.html("429 Too Many Requests", {
|
|
status: 429,
|
|
});
|
|
}
|
|
case "json": {
|
|
return c.json(
|
|
{
|
|
err: "429 Too Many Requests",
|
|
},
|
|
{
|
|
status: 429,
|
|
},
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
return new Response("429 Too Many Request", {
|
|
status: 429,
|
|
});
|
|
}
|
|
}
|
|
await next();
|
|
};
|
|
|
|
export default rateLimitMiddleware;
|