Skip to content

Commit

Permalink
API: V8 breaking rate limit changes
Browse files Browse the repository at this point in the history
This commit updates Retry-After to be seconds-accurate instead of the
previous millisecond-accurate. Another issue (#153) is opened to get a
more accurate number, which is in the JSON body instead of the header.

This commit also removed the rate limit precision header. It also uses a
more accurate calculation algorithm to derive the reset time.
  • Loading branch information
diamondburned committed Oct 28, 2020
1 parent d405cc2 commit 2af51c9
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 11 deletions.
5 changes: 2 additions & 3 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,8 @@ type Session struct {

func (s *Session) InjectRequest(r httpdriver.Request) error {
r.AddHeader(http.Header{
"Authorization": {s.Token},
"User-Agent": {s.UserAgent},
"X-RateLimit-Precision": {"millisecond"},
"Authorization": {s.Token},
"User-Agent": {s.UserAgent},
})

// Rate limit stuff
Expand Down
17 changes: 9 additions & 8 deletions api/rate/rate.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@ import (
"sync/atomic"
"time"

"github.com/pkg/errors"

"github.com/diamondburned/arikawa/internal/moreatomic"
"github.com/pkg/errors"
)

// ExtraDelay because Discord is trash. I've seen this in both litcord and
// discordgo, with dgo claiming from his experiments.
// discordgo, with dgo claiming from experiments.
// RE: Those who want others to fix it for them: release the source code then.
const ExtraDelay = 250 * time.Millisecond

Expand Down Expand Up @@ -161,18 +160,18 @@ func (l *Limiter) Release(path string, headers http.Header) error {

// seconds
remaining = headers.Get("X-RateLimit-Remaining")
reset = headers.Get("X-RateLimit-Reset")
reset = headers.Get("X-RateLimit-Reset") // float
retryAfter = headers.Get("Retry-After")
)

switch {
case retryAfter != "":
i, err := strconv.Atoi(retryAfter)
if err != nil {
return errors.Wrap(err, "invalid retryAfter "+retryAfter)
return errors.Wrapf(err, "invalid retryAfter %q", retryAfter)
}

at := time.Now().Add(time.Duration(i) * time.Millisecond)
at := time.Now().Add(time.Duration(i) * time.Second)

if global != "" { // probably true
atomic.StoreInt64(l.global, at.UnixNano())
Expand All @@ -186,8 +185,10 @@ func (l *Limiter) Release(path string, headers http.Header) error {
return errors.Wrap(err, "invalid reset "+reset)
}

b.reset = time.Unix(0, int64(unix*float64(time.Second))).
Add(ExtraDelay)
sec := int64(unix)
nsec := int64((unix - float64(sec)) * float64(time.Second))

b.reset = time.Unix(sec, nsec).Add(ExtraDelay)
}

if remaining != "" {
Expand Down

0 comments on commit 2af51c9

Please sign in to comment.