package ratelimit import ( "sync" "time" ) type TokenBucket struct { mu sync.Mutex capacity int tokens int refillRate float64 // tokens per second lastRefill time.Time } func NewTokenBucket(capacity int, refillPerSecond float64) *TokenBucket { return &TokenBucket{ capacity: capacity, tokens: capacity, refillRate: refillPerSecond, lastRefill: time.Now(), } } func (tb *TokenBucket) Allow() bool { return tb.AllowN(1) } func (tb *TokenBucket) AllowN(n int) bool { tb.mu.Lock() defer tb.mu.Unlock() tb.refill() if tb.tokens >= n { tb.tokens -= n return true } return false } func (tb *TokenBucket) Remaining() int { tb.mu.Lock() defer tb.mu.Unlock() tb.refill() return tb.tokens } func (tb *TokenBucket) Capacity() int { return tb.capacity } func (tb *TokenBucket) refill() { now := time.Now() elapsed := now.Sub(tb.lastRefill).Seconds() tb.lastRefill = now add := int(elapsed * tb.refillRate) if add > 0 { tb.tokens += add if tb.tokens > tb.capacity { tb.tokens = tb.capacity } } }