arikawa/api/api.go

83 lines
2.0 KiB
Go
Raw Normal View History

2020-01-15 04:56:50 +00:00
// Package api provides an interface to interact with the Discord REST API. It
// handles rate limiting, as well as authorizing and more.
2020-01-02 05:39:52 +00:00
package api
import (
2020-05-03 21:02:03 +00:00
"context"
2020-01-02 05:39:52 +00:00
"net/http"
2020-01-08 18:43:15 +00:00
"github.com/diamondburned/arikawa/api/rate"
"github.com/diamondburned/arikawa/utils/httputil"
2020-04-19 21:53:53 +00:00
"github.com/diamondburned/arikawa/utils/httputil/httpdriver"
2020-01-02 05:39:52 +00:00
)
var (
BaseEndpoint = "https://discord.com"
Version = "6"
Path = "/api/v" + Version
2020-01-02 05:39:52 +00:00
Endpoint = BaseEndpoint + Path + "/"
2020-01-02 05:39:52 +00:00
EndpointGateway = Endpoint + "gateway"
EndpointGatewayBot = EndpointGateway + "/bot"
)
var UserAgent = "DiscordBot (https://github.com/diamondburned/arikawa, v0.0.1)"
type Client struct {
2020-04-19 21:53:53 +00:00
*httputil.Client
2020-05-03 21:02:03 +00:00
Session
2020-01-02 05:39:52 +00:00
}
func NewClient(token string) *Client {
2020-04-19 21:53:53 +00:00
return NewCustomClient(token, httputil.NewClient())
}
func NewCustomClient(token string, httpClient *httputil.Client) *Client {
2020-05-03 21:02:03 +00:00
ses := Session{
Limiter: rate.NewLimiter(Path),
2020-04-19 21:53:53 +00:00
Token: token,
UserAgent: UserAgent,
2020-01-02 05:39:52 +00:00
}
2020-05-03 21:02:03 +00:00
hcl := httpClient.Copy()
hcl.OnRequest = append(hcl.OnRequest, ses.InjectRequest)
hcl.OnResponse = append(hcl.OnResponse, ses.OnResponse)
return &Client{
Client: hcl,
Session: ses,
2020-01-08 18:43:15 +00:00
}
2020-05-03 21:02:03 +00:00
}
2020-05-03 21:04:09 +00:00
// WithContext returns a shallow copy of Client with the given context. It's
// used for method timeouts and such. This method is thread-safe.
2020-05-03 21:02:03 +00:00
func (c *Client) WithContext(ctx context.Context) *Client {
return &Client{
Client: c.Client.WithContext(ctx),
Session: c.Session,
2020-01-02 05:39:52 +00:00
}
2020-05-03 21:02:03 +00:00
}
// Session keeps a single session. This is typically wrapped around Client.
type Session struct {
Limiter *rate.Limiter
Token string
UserAgent string
}
func (s *Session) InjectRequest(r httpdriver.Request) error {
r.AddHeader(http.Header{
"Authorization": {s.Token},
"User-Agent": {s.UserAgent},
"X-RateLimit-Precision": {"millisecond"},
})
// Rate limit stuff
return s.Limiter.Acquire(r.GetContext(), r.GetPath())
}
2020-01-02 05:39:52 +00:00
2020-05-03 21:02:03 +00:00
func (s *Session) OnResponse(r httpdriver.Request, resp httpdriver.Response) error {
return s.Limiter.Release(r.GetPath(), httpdriver.OptHeader(resp))
2020-01-02 05:39:52 +00:00
}