forked from tomnomnom/meg
-
Notifications
You must be signed in to change notification settings - Fork 3
/
ratelimit.go
58 lines (48 loc) · 1.08 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
package main
import (
"sync"
"time"
)
// a rateLimiter allows you to delay operations
// on a per-key basis. I.e. only one operation for
// a given key can be done within the delay time
type rateLimiter struct {
sync.Mutex
delay time.Duration
ops map[string]time.Time
}
// newRateLimiter returns a new *rateLimiter for the
// provided delay
func newRateLimiter(delay time.Duration) *rateLimiter {
return &rateLimiter{
delay: delay,
ops: make(map[string]time.Time),
}
}
// Block blocks until an operation for key is
// allowed to proceed
func (r *rateLimiter) Block(key string) {
now := time.Now()
r.Lock()
// if there's nothing in the map we can
// return straight away
if _, ok := r.ops[key]; !ok {
r.ops[key] = now
r.Unlock()
return
}
// if time is up we can return straight away
t := r.ops[key]
deadline := t.Add(r.delay)
if now.After(deadline) {
r.ops[key] = now
r.Unlock()
return
}
remaining := deadline.Sub(now)
// Set the time of the operation
r.ops[key] = now.Add(remaining)
r.Unlock()
// Block for the remaining time
<-time.After(remaining)
}