package limiter import ( "sync" "golang.org/x/time/rate" ) // Limit represents an IP request rate limit. type Limit struct { limiters map[string]*rate.Limiter mu *sync.RWMutex rateLimit rate.Limit burstSize int } // NewLimit returns a new Limit with the specified request and burst rate limit per second. func NewLimit(r rate.Limit, b int) *Limit { i := &Limit{ limiters: make(map[string]*rate.Limiter), mu: &sync.RWMutex{}, rateLimit: r, burstSize: b, } return i } // AddIP adds a new rate limiter for the specified IP address. func (i *Limit) AddIP(ip string) *rate.Limiter { i.mu.Lock() defer i.mu.Unlock() limiter := rate.NewLimiter(i.rateLimit, i.burstSize) i.limiters[ip] = limiter return limiter } // IP returns the rate limiter for the specified IP address. func (i *Limit) IP(ip string) *rate.Limiter { i.mu.Lock() limiter, exists := i.limiters[ip] if !exists { i.mu.Unlock() return i.AddIP(ip) } i.mu.Unlock() return limiter } // Allow reports whether the request is allowed at this time and increments the request counter. func (i *Limit) Allow(ip string) bool { return i.IP(ip).Allow() } // Reserve increments the request counter and returns a rate.Reservation. func (i *Limit) Reserve(ip string) *rate.Reservation { return i.IP(ip).Reserve() } // Reject reports whether the request limit has been exceeded, but does not change the request counter. func (i *Limit) Reject(ip string) bool { return i.IP(ip).Tokens() < 1 }