1
0
Fork 0
mirror of https://github.com/diamondburned/arikawa.git synced 2024-11-01 12:34:28 +00:00
arikawa/api/api.go

115 lines
3.1 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"
2021-06-02 02:53:19 +00:00
"github.com/diamondburned/arikawa/v3/api/rate"
"github.com/diamondburned/arikawa/v3/discord"
2021-06-02 02:53:19 +00:00
"github.com/diamondburned/arikawa/v3/utils/httputil"
"github.com/diamondburned/arikawa/v3/utils/httputil/httpdriver"
2020-01-02 05:39:52 +00:00
)
var (
BaseEndpoint = "https://discord.com"
Version = "9"
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/v3)"
2020-01-02 05:39:52 +00:00
type Client struct {
2020-04-19 21:53:53 +00:00
*httputil.Client
*Session
2021-05-29 20:28:45 +00:00
AcquireOptions rate.AcquireOptions
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 {
2021-05-29 20:28:45 +00:00
c := &Client{
Session: &Session{
Limiter: rate.NewLimiter(Path),
Token: token,
UserAgent: UserAgent,
},
Client: httpClient.Copy(),
2020-01-02 05:39:52 +00:00
}
2021-05-29 20:28:45 +00:00
c.Client.OnRequest = append(c.Client.OnRequest, c.InjectRequest)
c.Client.OnResponse = append(c.Client.OnResponse, c.OnResponse)
2020-05-03 21:02:03 +00:00
2021-05-29 20:28:45 +00:00
return c
2020-05-03 21:02:03 +00:00
}
// WithLocale creates a copy of Client with an explicitly stated language locale
// using the X-Discord-Locale HTTP header.
func (c *Client) WithLocale(language discord.Language) *Client {
client := c.Client.Copy()
client.OnRequest = append(client.OnRequest, func(r httpdriver.Request) error {
r.AddHeader(http.Header{"X-Discord-Locale": []string{string(language)}})
return nil
})
return &Client{
Client: client,
Session: c.Session,
AcquireOptions: c.AcquireOptions,
}
}
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{
2021-05-29 20:28:45 +00:00
Client: c.Client.WithContext(ctx),
Session: c.Session,
AcquireOptions: c.AcquireOptions,
2020-01-02 05:39:52 +00:00
}
2020-05-03 21:02:03 +00:00
}
2021-05-29 20:28:45 +00:00
func (c *Client) InjectRequest(r httpdriver.Request) error {
r.AddHeader(http.Header{
"Authorization": {c.Session.Token},
"User-Agent": {c.Session.UserAgent},
})
ctx := c.AcquireOptions.Context(r.GetContext())
return c.Session.Limiter.Acquire(ctx, r.GetPath())
}
func (c *Client) OnResponse(r httpdriver.Request, resp httpdriver.Response) error {
return c.Session.Limiter.Release(r.GetPath(), httpdriver.OptHeader(resp))
}
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
}
// AuditLogReason is the type embedded in data structs when the action
// performed by calling that api endpoint supports attaching a custom audit log
// reason.
type AuditLogReason string
// Header returns a http.Header containing the reason, or nil if the reason is
// empty.
func (r AuditLogReason) Header() http.Header {
if len(r) == 0 {
return nil
}
return http.Header{"X-Audit-Log-Reason": []string{string(r)}}
}