package bridge import ( "sync" "time" ) // limiter is a token bucket in bytes. It allows a one-second burst and then // the configured rate. Two independent limiters gate a session's up and down // streams, so one direction cannot starve the other. type limiter struct { rate int64 mu sync.Mutex tokens float64 last time.Time } func newLimiter(rate int64) *limiter { return &limiter{rate: rate, tokens: float64(rate), last: time.Now()} } func (l *limiter) wait(n int64) { if l == nil || l.rate <= 0 || n <= 0 { return } for { l.mu.Lock() now := time.Now() l.tokens += now.Sub(l.last).Seconds() * float64(l.rate) if l.tokens > float64(l.rate) { l.tokens = float64(l.rate) } l.last = now if l.tokens >= float64(n) { l.tokens -= float64(n) l.mu.Unlock() return } delay := time.Duration((float64(n) - l.tokens) / float64(l.rate) * float64(time.Second)) l.mu.Unlock() if delay < time.Millisecond { delay = time.Millisecond } time.Sleep(delay) } }