This repository has been archived by the owner on Feb 14, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 67
/
ratelimit.go
103 lines (85 loc) · 2.38 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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package strava
import (
"net/http"
"strconv"
"strings"
"sync"
"time"
)
// RateLimit is the struct used for the `RateLimiting` global that is
// updated after every request.
type RateLimit struct {
lock sync.RWMutex
RequestTime time.Time
LimitShort int
LimitLong int
UsageShort int
UsageLong int
}
// RateLimiting stores rate limit information included in the most recent request.
// Request time will be zero for invalid, or not yet set results.
// Admittedly having a globally updated ratelimit value is a bit clunky. // TODO: fix
var RateLimiting RateLimit
// Exceeded should be called as `strava.RateLimiting.Exceeded() to determine if the most recent
// request exceeded the rate limit
func (rl *RateLimit) Exceeded() bool {
rl.lock.RLock()
defer rl.lock.RUnlock()
if rl.UsageShort >= rl.LimitShort {
return true
}
if rl.UsageLong >= rl.LimitLong {
return true
}
return false
}
// FractionReached returns the current faction of rate used. The greater of the
// short and long term limits. Should be called as `strava.RateLimiting.FractionReached()`
func (rl *RateLimit) FractionReached() float32 {
rl.lock.RLock()
defer rl.lock.RUnlock()
var shortLimitFraction float32 = float32(rl.UsageShort) / float32(rl.LimitShort)
var longLimitFraction float32 = float32(rl.UsageLong) / float32(rl.LimitLong)
if shortLimitFraction > longLimitFraction {
return shortLimitFraction
} else {
return longLimitFraction
}
}
// ignoring error, instead will reset struct to initial values, so rate limiting is ignored
func (rl *RateLimit) updateRateLimits(resp *http.Response) {
rl.lock.Lock()
defer rl.lock.Unlock()
var err error
if resp.Header.Get("X-Ratelimit-Limit") == "" || resp.Header.Get("X-Ratelimit-Usage") == "" {
rl.clear()
return
}
s := strings.Split(resp.Header.Get("X-Ratelimit-Limit"), ",")
if rl.LimitShort, err = strconv.Atoi(s[0]); err != nil {
rl.clear()
return
}
if rl.LimitLong, err = strconv.Atoi(s[1]); err != nil {
rl.clear()
return
}
s = strings.Split(resp.Header.Get("X-Ratelimit-Usage"), ",")
if rl.UsageShort, err = strconv.Atoi(s[0]); err != nil {
rl.clear()
return
}
if rl.UsageLong, err = strconv.Atoi(s[1]); err != nil {
rl.clear()
return
}
rl.RequestTime = time.Now()
return
}
func (rl *RateLimit) clear() {
rl.RequestTime = time.Time{}
rl.LimitShort = 0
rl.LimitLong = 0
rl.UsageShort = 0
rl.UsageLong = 0
}