package middleware import ( "net/http" "sync" "time" ) type rateLimiter struct { mu sync.Mutex visitors map[string][]time.Time limit int window time.Duration } func newRateLimiter(limit int) *rateLimiter { return &rateLimiter{ visitors: make(map[string][]time.Time), limit: limit, window: time.Minute, } } func (rl *rateLimiter) allow(ip string) bool { rl.mu.Lock() defer rl.mu.Unlock() now := time.Now() cutoff := now.Add(-rl.window) var valid []time.Time for _, t := range rl.visitors[ip] { if t.After(cutoff) { valid = append(valid, t) } } if len(valid) >= rl.limit { rl.visitors[ip] = valid return false } rl.visitors[ip] = append(valid, now) return true } func RateLimit(limit int) func(http.Handler) http.Handler { rl := newRateLimiter(limit) return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ip := r.RemoteAddr if xff := r.Header.Get("X-Forwarded-For"); xff != "" { ip = xff } if !rl.allow(ip) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusTooManyRequests) w.Write([]byte(`{"error":{"code":"RATE_LIMITED","message":"Previse zahteva, pokusajte ponovo za minut"}}`)) return } next.ServeHTTP(w, r) }) } }