A decentralized music tracking and discovery platform built on AT Protocol 馃幍
at feat/scrobble-user-avatar 39 lines 1.1 kB view raw
1import { ctx } from "context"; 2import type { Context, MiddlewareHandler } from "hono"; 3 4type RateLimitOptions = { 5 limit: number; // max requests 6 window: number; // window in seconds 7 keyPrefix?: string; 8}; 9 10export const rateLimiter = (options: RateLimitOptions): MiddlewareHandler => { 11 const { limit, window, keyPrefix = "ratelimit" } = options; 12 13 return async (c: Context, next) => { 14 const ip = 15 c.req.header("x-forwarded-for") || 16 c.req.raw.headers.get("x-real-ip") || 17 c.req.raw.headers.get("host"); 18 const key = `${keyPrefix}:${ip}`; 19 20 const current = await ctx.redis.incr(key); 21 22 if (current === 1) { 23 await ctx.redis.expire(key, window); 24 } 25 26 const remaining = limit - current; 27 c.header("X-RateLimit-Limit", limit.toString()); 28 c.header("X-RateLimit-Remaining", Math.max(remaining, 0).toString()); 29 30 if (current > limit) { 31 c.status(429); 32 const reset = await ctx.redis.ttl(key); 33 c.header("X-RateLimit-Reset", reset.toString()); 34 return c.text("Too Many Requests"); 35 } 36 37 await next(); 38 }; 39};