github.com/diamondburned/arikawa/v2@v2.1.0/api/api.go (about)

     1  // Package api provides an interface to interact with the Discord REST API. It
     2  // handles rate limiting, as well as authorizing and more.
     3  package api
     4  
     5  import (
     6  	"context"
     7  	"net/http"
     8  
     9  	"github.com/diamondburned/arikawa/v2/api/rate"
    10  	"github.com/diamondburned/arikawa/v2/utils/httputil"
    11  	"github.com/diamondburned/arikawa/v2/utils/httputil/httpdriver"
    12  )
    13  
    14  var (
    15  	BaseEndpoint = "https://discord.com"
    16  	Version      = "8"
    17  	Path         = "/api/v" + Version
    18  
    19  	Endpoint           = BaseEndpoint + Path + "/"
    20  	EndpointGateway    = Endpoint + "gateway"
    21  	EndpointGatewayBot = EndpointGateway + "/bot"
    22  )
    23  
    24  var UserAgent = "DiscordBot (https://github.com/diamondburned/arikawa/v2)"
    25  
    26  type Client struct {
    27  	*httputil.Client
    28  	*Session
    29  }
    30  
    31  func NewClient(token string) *Client {
    32  	return NewCustomClient(token, httputil.NewClient())
    33  }
    34  
    35  func NewCustomClient(token string, httpClient *httputil.Client) *Client {
    36  	ses := Session{
    37  		Limiter:   rate.NewLimiter(Path),
    38  		Token:     token,
    39  		UserAgent: UserAgent,
    40  	}
    41  
    42  	hcl := httpClient.Copy()
    43  	hcl.OnRequest = append(hcl.OnRequest, ses.InjectRequest)
    44  	hcl.OnResponse = append(hcl.OnResponse, ses.OnResponse)
    45  
    46  	return &Client{
    47  		Client:  hcl,
    48  		Session: &ses,
    49  	}
    50  }
    51  
    52  // WithContext returns a shallow copy of Client with the given context. It's
    53  // used for method timeouts and such. This method is thread-safe.
    54  func (c *Client) WithContext(ctx context.Context) *Client {
    55  	return &Client{
    56  		Client:  c.Client.WithContext(ctx),
    57  		Session: c.Session,
    58  	}
    59  }
    60  
    61  // Session keeps a single session. This is typically wrapped around Client.
    62  type Session struct {
    63  	Limiter *rate.Limiter
    64  
    65  	Token     string
    66  	UserAgent string
    67  }
    68  
    69  func (s *Session) InjectRequest(r httpdriver.Request) error {
    70  	r.AddHeader(http.Header{
    71  		"Authorization": {s.Token},
    72  		"User-Agent":    {s.UserAgent},
    73  	})
    74  
    75  	// Rate limit stuff
    76  	return s.Limiter.Acquire(r.GetContext(), r.GetPath())
    77  }
    78  
    79  func (s *Session) OnResponse(r httpdriver.Request, resp httpdriver.Response) error {
    80  	return s.Limiter.Release(r.GetPath(), httpdriver.OptHeader(resp))
    81  }