60 lines
925 B
Go
60 lines
925 B
Go
package limiter
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// NewRateLimiter returns a rate limiter that will will emit from the C
|
|
// channel only 'n' times every 'rate' seconds.
|
|
func NewRateLimiter(n int, rate time.Duration) *rateLimiter {
|
|
r := &rateLimiter{
|
|
C: make(chan bool),
|
|
rate: rate,
|
|
n: n,
|
|
shutdown: make(chan bool),
|
|
}
|
|
r.wg.Add(1)
|
|
go r.limiter()
|
|
return r
|
|
}
|
|
|
|
type rateLimiter struct {
|
|
C chan bool
|
|
rate time.Duration
|
|
n int
|
|
|
|
shutdown chan bool
|
|
wg sync.WaitGroup
|
|
}
|
|
|
|
func (r *rateLimiter) Stop() {
|
|
close(r.shutdown)
|
|
r.wg.Wait()
|
|
close(r.C)
|
|
}
|
|
|
|
func (r *rateLimiter) limiter() {
|
|
defer r.wg.Done()
|
|
ticker := time.NewTicker(r.rate)
|
|
defer ticker.Stop()
|
|
counter := 0
|
|
for {
|
|
select {
|
|
case <-r.shutdown:
|
|
return
|
|
case <-ticker.C:
|
|
counter = 0
|
|
default:
|
|
if counter < r.n {
|
|
select {
|
|
case r.C <- true:
|
|
counter++
|
|
case <-r.shutdown:
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|