package middleware import ( "net/http" "sync" "time" "github.com/gin-gonic/gin" "golang.org/x/time/rate" ) type client struct { limiter *rate.Limiter lastSeen time.Time } type RateLimiter struct { clients map[string]*client mu sync.Mutex rps rate.Limit burst int } func NewRateLimiter(requestsPerSecond float64, burst int) *RateLimiter { rl := &RateLimiter{ clients: make(map[string]*client), rps: rate.Limit(requestsPerSecond), burst: burst, } go rl.cleanup() return rl } func (rl *RateLimiter) getClient(ip string) *rate.Limiter { rl.mu.Lock() defer rl.mu.Unlock() if c, exists := rl.clients[ip]; exists { c.lastSeen = time.Now() return c.limiter } limiter := rate.NewLimiter(rl.rps, rl.burst) rl.clients[ip] = &client{limiter: limiter, lastSeen: time.Now()} return limiter } func (rl *RateLimiter) cleanup() { for { time.Sleep(time.Minute) rl.mu.Lock() for ip, c := range rl.clients { if time.Since(c.lastSeen) > 3*time.Minute { delete(rl.clients, ip) } } rl.mu.Unlock() } } func (rl *RateLimiter) Middleware() gin.HandlerFunc { return func(c *gin.Context) { ip := c.ClientIP() limiter := rl.getClient(ip) if !limiter.Allow() { c.AbortWithStatusJSON(http.StatusTooManyRequests, gin.H{ "error": "failed", "message": "rate limit exceeded", }) return } c.Next() } }