-
-
Notifications
You must be signed in to change notification settings - Fork 115
/
ratelimit.go
63 lines (50 loc) · 1.45 KB
/
ratelimit.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package timeliner
import (
"net/http"
"time"
)
// RateLimit describes a rate limit.
type RateLimit struct {
RequestsPerHour int
BurstSize int
ticker *time.Ticker
token chan struct{}
}
// NewRateLimitedRoundTripper adds rate limiting to rt based on the rate
// limiting policy registered by the data source associated with acc.
func (acc Account) NewRateLimitedRoundTripper(rt http.RoundTripper) http.RoundTripper {
rl, ok := acc.t.rateLimiters[acc.String()]
if !ok && acc.ds.RateLimit.RequestsPerHour > 0 {
secondsBetweenReqs := 60.0 / (float64(acc.ds.RateLimit.RequestsPerHour) / 60.0)
millisBetweenReqs := secondsBetweenReqs * 1000.0
reqInterval := time.Duration(millisBetweenReqs) * time.Millisecond
if reqInterval < minInterval {
reqInterval = minInterval
}
rl.ticker = time.NewTicker(reqInterval)
rl.token = make(chan struct{}, rl.BurstSize)
for i := 0; i < cap(rl.token); i++ {
rl.token <- struct{}{}
}
go func() {
for range rl.ticker.C {
rl.token <- struct{}{}
}
}()
acc.t.rateLimiters[acc.String()] = rl
}
return rateLimitedRoundTripper{
RoundTripper: rt,
token: rl.token,
}
}
type rateLimitedRoundTripper struct {
http.RoundTripper
token <-chan struct{}
}
func (rt rateLimitedRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
<-rt.token
return rt.RoundTripper.RoundTrip(req)
}
var rateLimiters = make(map[string]RateLimit)
const minInterval = 100 * time.Millisecond