1
0
Fork 0
mirror of https://github.com/diamondburned/arikawa.git synced 2025-08-31 02:45:18 +00:00
arikawa/api/api.go
diamondburned daf47b3491
api: Add upload size consts and DetermineUploadSize
This commit adds a new method `DetermineUploadSize` into both api.Client
and state.State, which implement the core logic to determine the right
upload size limit for the current user. Bots can ignore this method.

This commit also adds constants for the upload size limits, with
different constants for different scenarios (nitro, server boosts).
Bots can directly use the `UploadSizeLimit` constant, which is the
default lowest limit.
2025-06-20 01:25:20 -07:00

123 lines
3.3 KiB
Go

// Package api provides an interface to interact with the Discord REST API. It
// handles rate limiting, as well as authorizing and more.
package api
import (
"context"
"net/http"
"strings"
"github.com/diamondburned/arikawa/v3/api/rate"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/utils/httputil"
"github.com/diamondburned/arikawa/v3/utils/httputil/httpdriver"
)
var (
BaseEndpoint = "https://discord.com"
Version = "9"
Path = "/api/v" + Version
Endpoint = BaseEndpoint + Path + "/"
EndpointGateway = Endpoint + "gateway"
EndpointGatewayBot = EndpointGateway + "/bot"
)
var UserAgent = "DiscordBot (https://github.com/diamondburned/arikawa/v3)"
type Client struct {
*httputil.Client
*Session
AcquireOptions rate.AcquireOptions
}
func NewClient(token string) *Client {
return NewCustomClient(token, httputil.NewClient())
}
func NewCustomClient(token string, httpClient *httputil.Client) *Client {
c := &Client{
Session: &Session{
Limiter: rate.NewLimiter(Path),
Token: token,
UserAgent: UserAgent,
},
Client: httpClient.Copy(),
}
c.Client.OnRequest = append(c.Client.OnRequest, c.InjectRequest)
c.Client.OnResponse = append(c.Client.OnResponse, c.OnResponse)
return c
}
// 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,
}
}
// WithContext returns a shallow copy of Client with the given context. It's
// used for method timeouts and such. This method is thread-safe.
func (c *Client) WithContext(ctx context.Context) *Client {
return &Client{
Client: c.Client.WithContext(ctx),
Session: c.Session,
AcquireOptions: c.AcquireOptions,
}
}
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))
}
// Session keeps a single session. This is typically wrapped around Client.
type Session struct {
Limiter *rate.Limiter
Token string
UserAgent string
}
// IsBot checks if the session is a bot session.
// This is determined by the token's prefix.
func (s *Session) IsBot() bool {
prefix, _, _ := strings.Cut(s.Token, " ")
return prefix == "Bot"
}
// 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)}}
}