From cf28f6c8df10535ca22607f1d4e72f163f74a305 Mon Sep 17 00:00:00 2001 From: Laurent Le Houerou Date: Sat, 3 Aug 2024 21:36:25 +0400 Subject: [PATCH] add api key support + misc corrections --- api.go | 4 ++++ football/football.go | 6 +++-- football/rivals.go | 11 +++++++++ graphql/authentication.go | 12 +++++----- graphql/client.go | 49 ++++++++++++++++++++++++++++++++------- user.go | 6 ++--- 6 files changed, 68 insertions(+), 20 deletions(-) create mode 100644 football/rivals.go diff --git a/api.go b/api.go index 55920dc..81fe78d 100644 --- a/api.go +++ b/api.go @@ -97,6 +97,10 @@ func (s *Sorare) Debug() *Sorare { return s } +func (s *Sorare) SetApiKey(apiKey string) { + s.Client.SetApiKey(apiKey) +} + func (s *Sorare) SetJWTToken(token graphql.JwtToken, audience string) { s.Client.SetJWTToken(token, audience) } diff --git a/football/football.go b/football/football.go index 97cd36d..7e6ec4a 100644 --- a/football/football.go +++ b/football/football.go @@ -26,7 +26,8 @@ type Football struct { Players *graphql.Query[[]Player, graphql.SlugsParams] Season *graphql.Query[Season, SeasonParams] - So5 *So5 + So5 *So5 + Rivals *Rivals } func NewFootball(c *graphql.Client) *Football { @@ -116,6 +117,7 @@ func NewFootball(c *graphql.Client) *Football { []string{"football"}, ), - So5: NewSo5(c), + So5: NewSo5(c), + Rivals: NewRivals(c), } } diff --git a/football/rivals.go b/football/rivals.go new file mode 100644 index 0000000..82fe57d --- /dev/null +++ b/football/rivals.go @@ -0,0 +1,11 @@ +package football + +import "git.lehouerou.net/laurent/sorare/graphql" + +type Rivals struct { + c *graphql.Client +} + +func NewRivals(c *graphql.Client) *Rivals { + return &Rivals{c: c} +} diff --git a/graphql/authentication.go b/graphql/authentication.go index 12679b1..1048025 100644 --- a/graphql/authentication.go +++ b/graphql/authentication.go @@ -57,10 +57,10 @@ type JwtToken struct { type SignIn struct { CurrentUser struct { - Slug string - JwtToken JwtToken `graphql:"jwtToken(aud: $aud)"` + Slug string } `graphql:"currentUser"` OtpSessionChallenge string + JwtToken JwtToken `graphql:"jwtToken(aud: $aud)"` Errors []struct { Message string } `graphql:"errors"` @@ -116,12 +116,12 @@ func (c *Client) getNewToken( } if len(res.Errors) == 0 { - if res.CurrentUser.JwtToken.Token == "" { + if res.JwtToken.Token == "" { return JwtToken{}, errors.New( "no errors & no jwt token returned on email/password mutation", ) } - return res.CurrentUser.JwtToken, nil + return res.JwtToken, nil } if res.Errors[0].Message == "invalid" { @@ -146,10 +146,10 @@ func (c *Client) getNewToken( } if len(resOtp.Errors) == 0 { - if resOtp.CurrentUser.JwtToken.Token == "" { + if resOtp.JwtToken.Token == "" { return JwtToken{}, errors.New("no errors & no jwt token returned on otp mutation") } - return resOtp.CurrentUser.JwtToken, nil + return resOtp.JwtToken, nil } return JwtToken{}, errors.Errorf("validating otp: %s", resOtp.Errors[0].Message) } diff --git a/graphql/client.go b/graphql/client.go index 3481732..4e1d366 100644 --- a/graphql/client.go +++ b/graphql/client.go @@ -22,9 +22,11 @@ type Client struct { httpClient *http.Client gql *graphql.Client rl *rate.Limiter + apirl *rate.Limiter lock *sync.Mutex authenticated bool token JwtToken + apiKey string } func NewClient(httpclient *http.Client, baseUrl string) *Client { @@ -32,6 +34,7 @@ func NewClient(httpclient *http.Client, baseUrl string) *Client { httpClient: httpclient, gql: graphql.NewClient(baseUrl, httpclient), rl: rate.NewLimiter(rate.Every(rateLimitPeriod), rateLimitBurst), + apirl: rate.NewLimiter(rate.Every(rateLimitPeriod/10), rateLimitBurst*10), lock: &sync.Mutex{}, authenticated: false, } @@ -50,6 +53,13 @@ func (c *Client) SetJWTToken(token JwtToken, audience string) { c.authenticated = true } +func (c *Client) SetApiKey(apiKey string) { + c.gql = c.gql.WithRequestModifier(func(request *http.Request) { + request.Header.Set("APIKEY", apiKey) + }) + c.apiKey = apiKey +} + func (c *Client) MaxComplexity() int { if c.authenticated { return MaxAuthenticatedQueryComplexity @@ -71,9 +81,16 @@ func (c *Client) Query( variables interface{}, options ...graphql.Option, ) error { - err := c.rl.Wait(ctx) - if err != nil { - return errors.Wrap(err, "waiting for rate limit") + if c.apiKey != "" { + err := c.apirl.Wait(ctx) + if err != nil { + return errors.Wrap(err, "waiting for rate limit") + } + } else { + err := c.rl.Wait(ctx) + if err != nil { + return errors.Wrap(err, "waiting for rate limit") + } } c.lock.Lock() defer c.lock.Unlock() @@ -86,9 +103,16 @@ func (c *Client) QueryRaw( variables interface{}, options ...graphql.Option, ) ([]byte, error) { - err := c.rl.Wait(ctx) - if err != nil { - return nil, errors.Wrap(err, "waiting for rate limit") + if c.apiKey != "" { + err := c.apirl.Wait(ctx) + if err != nil { + return nil, errors.Wrap(err, "waiting for rate limit") + } + } else { + err := c.rl.Wait(ctx) + if err != nil { + return nil, errors.Wrap(err, "waiting for rate limit") + } } c.lock.Lock() defer c.lock.Unlock() @@ -101,9 +125,16 @@ func (c *Client) Mutate( variables interface{}, options ...graphql.Option, ) error { - err := c.rl.Wait(ctx) - if err != nil { - return errors.Wrap(err, "waiting for rate limit") + if c.apiKey != "" { + err := c.apirl.Wait(ctx) + if err != nil { + return errors.Wrap(err, "waiting for rate limit") + } + } else { + err := c.rl.Wait(ctx) + if err != nil { + return errors.Wrap(err, "waiting for rate limit") + } } c.lock.Lock() defer c.lock.Unlock() diff --git a/user.go b/user.go index 76a0203..174e9a3 100644 --- a/user.go +++ b/user.go @@ -12,8 +12,8 @@ import ( ) type baseUser struct { - Active bool `graphql:"active"` - CardCounts struct { + Active bool `graphql:"active"` + FootballCardCounts struct { Common int `graphql:"common"` CustomSeries int `graphql:"customSeries"` Limited int `graphql:"limited"` @@ -21,7 +21,7 @@ type baseUser struct { SuperRare int `graphql:"superRare"` Unique int `graphql:"unique"` Total int `graphql:"total"` - } `graphql:"cardCounts"` + } `graphql:"footballCardCounts"` CreatedAt time.Time `graphql:"createdAt"` EthVaultId int `graphql:"ethVaultId"` EthereumAddress string `graphql:"ethereumAddress"`