sorare/graphql/client.go

112 lines
2.4 KiB
Go

package graphql
import (
"context"
"net/http"
"sync"
"time"
"github.com/llehouerou/go-graphql-client"
"github.com/pkg/errors"
"golang.org/x/time/rate"
)
const (
rateLimitPeriod = time.Second
rateLimitBurst = 60
MaxAuthenticatedQueryComplexity = 30000
MaxAnonymousQueryComplexity = 500
)
type Client struct {
httpClient *http.Client
gql *graphql.Client
rl *rate.Limiter
lock *sync.Mutex
authenticated bool
token JwtToken
}
func NewClient(httpclient *http.Client, baseUrl string) *Client {
return &Client{
httpClient: httpclient,
gql: graphql.NewClient(baseUrl, httpclient),
rl: rate.NewLimiter(rate.Every(rateLimitPeriod), rateLimitBurst),
lock: &sync.Mutex{},
authenticated: false,
}
}
func (c *Client) GetCurrentToken() JwtToken {
return c.token
}
func (c *Client) SetJWTToken(token JwtToken, audience string) {
c.gql = c.gql.WithRequestModifier(func(request *http.Request) {
request.Header.Set("Authorization", "Bearer "+token.Token)
request.Header.Set("JWT-AUD", audience)
})
c.token = token
c.authenticated = true
}
func (c *Client) MaxComplexity() int {
if c.authenticated {
return MaxAuthenticatedQueryComplexity
} else {
return MaxAnonymousQueryComplexity
}
}
func (c *Client) ConstructRawQuery(
q interface{},
variables map[string]interface{},
) (string, error) {
return graphql.ConstructQuery(q, variables)
}
func (c *Client) Query(
ctx context.Context,
q interface{},
variables interface{},
options ...graphql.Option,
) error {
err := c.rl.Wait(ctx)
if err != nil {
return errors.Wrap(err, "waiting for rate limit")
}
c.lock.Lock()
defer c.lock.Unlock()
return c.gql.Query(ctx, q, variables, options...)
}
func (c *Client) QueryRaw(
ctx context.Context,
q interface{},
variables interface{},
options ...graphql.Option,
) ([]byte, error) {
err := c.rl.Wait(ctx)
if err != nil {
return nil, errors.Wrap(err, "waiting for rate limit")
}
c.lock.Lock()
defer c.lock.Unlock()
return c.gql.QueryRaw(ctx, q, variables, options...)
}
func (c *Client) Mutate(
ctx context.Context,
q interface{},
variables interface{},
options ...graphql.Option,
) error {
err := c.rl.Wait(ctx)
if err != nil {
return errors.Wrap(err, "waiting for rate limit")
}
c.lock.Lock()
defer c.lock.Unlock()
return c.gql.Mutate(ctx, q, variables, options...)
}