-
Notifications
You must be signed in to change notification settings - Fork 7
/
gcra.go
71 lines (58 loc) · 1.36 KB
/
gcra.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
64
65
66
67
68
69
70
71
// https://github.com/go-redis/redis_rate
package go_limiter
import (
"context"
"strconv"
"time"
)
const GCRAAlgorithmName = "gcra"
type gcra struct {
key string
limit *Limit
rdb rediser
}
func (c *gcra) Reset(ctx context.Context) error {
res := c.rdb.Del(ctx, c.key)
return res.Err()
}
// Allow is shorthand for AllowN(key, 1).
func (c *gcra) Allow(ctx context.Context) (*Result, error) {
return c.AllowN(ctx, 1)
}
// SetKey _
func (c *gcra) SetKey(key string) {
c.key = key
}
// AllowN reports whether n events may happen at time now.
func (c *gcra) AllowN(ctx context.Context, n int) (*Result, error) {
limit := c.limit
values := []interface{}{limit.Burst, limit.Rate, limit.Period.Seconds(), n}
v, err := script.Run(ctx, c.rdb, []string{c.key}, values...).Result()
if err != nil {
return nil, err
}
values = v.([]interface{})
retryAfter, err := strconv.ParseFloat(values[2].(string), 64)
if err != nil {
return nil, err
}
resetAfter, err := strconv.ParseFloat(values[3].(string), 64)
if err != nil {
return nil, err
}
res := &Result{
Limit: limit,
Key: c.key,
Allowed: values[0].(int64) == 0,
Remaining: values[1].(int64),
RetryAfter: dur(retryAfter),
ResetAfter: dur(resetAfter),
}
return res, nil
}
func dur(f float64) time.Duration {
if f == -1 {
return -1
}
return time.Duration(f * float64(time.Second))
}