package web import ( "sync" "time" ) type rateEntry struct { since time.Time n int } type limiter struct { mu sync.Mutex entries map[string]rateEntry } func newLimiter() *limiter { return &limiter{entries: make(map[string]rateEntry)} } func (l *limiter) allow(key string, max int, window time.Duration) bool { now := time.Now() l.mu.Lock() defer l.mu.Unlock() e := l.entries[key] if e.since.IsZero() || now.Sub(e.since) >= window { l.entries[key] = rateEntry{since: now, n: 1} return true } if e.n >= max { return false } e.n++ l.entries[key] = e if len(l.entries) > 10000 { for k, v := range l.entries { if now.Sub(v.since) > 2*window { delete(l.entries, k) } } } return true }