add api key support + misc corrections

This commit is contained in:
Laurent Le Houerou 2024-08-03 21:36:25 +04:00
parent 2e1b00f306
commit cf28f6c8df
6 changed files with 68 additions and 20 deletions

4
api.go
View File

@ -97,6 +97,10 @@ func (s *Sorare) Debug() *Sorare {
return s return s
} }
func (s *Sorare) SetApiKey(apiKey string) {
s.Client.SetApiKey(apiKey)
}
func (s *Sorare) SetJWTToken(token graphql.JwtToken, audience string) { func (s *Sorare) SetJWTToken(token graphql.JwtToken, audience string) {
s.Client.SetJWTToken(token, audience) s.Client.SetJWTToken(token, audience)
} }

View File

@ -26,7 +26,8 @@ type Football struct {
Players *graphql.Query[[]Player, graphql.SlugsParams] Players *graphql.Query[[]Player, graphql.SlugsParams]
Season *graphql.Query[Season, SeasonParams] Season *graphql.Query[Season, SeasonParams]
So5 *So5 So5 *So5
Rivals *Rivals
} }
func NewFootball(c *graphql.Client) *Football { func NewFootball(c *graphql.Client) *Football {
@ -116,6 +117,7 @@ func NewFootball(c *graphql.Client) *Football {
[]string{"football"}, []string{"football"},
), ),
So5: NewSo5(c), So5: NewSo5(c),
Rivals: NewRivals(c),
} }
} }

11
football/rivals.go Normal file
View File

@ -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}
}

View File

@ -57,10 +57,10 @@ type JwtToken struct {
type SignIn struct { type SignIn struct {
CurrentUser struct { CurrentUser struct {
Slug string Slug string
JwtToken JwtToken `graphql:"jwtToken(aud: $aud)"`
} `graphql:"currentUser"` } `graphql:"currentUser"`
OtpSessionChallenge string OtpSessionChallenge string
JwtToken JwtToken `graphql:"jwtToken(aud: $aud)"`
Errors []struct { Errors []struct {
Message string Message string
} `graphql:"errors"` } `graphql:"errors"`
@ -116,12 +116,12 @@ func (c *Client) getNewToken(
} }
if len(res.Errors) == 0 { if len(res.Errors) == 0 {
if res.CurrentUser.JwtToken.Token == "" { if res.JwtToken.Token == "" {
return JwtToken{}, errors.New( return JwtToken{}, errors.New(
"no errors & no jwt token returned on email/password mutation", "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" { if res.Errors[0].Message == "invalid" {
@ -146,10 +146,10 @@ func (c *Client) getNewToken(
} }
if len(resOtp.Errors) == 0 { 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 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) return JwtToken{}, errors.Errorf("validating otp: %s", resOtp.Errors[0].Message)
} }

View File

@ -22,9 +22,11 @@ type Client struct {
httpClient *http.Client httpClient *http.Client
gql *graphql.Client gql *graphql.Client
rl *rate.Limiter rl *rate.Limiter
apirl *rate.Limiter
lock *sync.Mutex lock *sync.Mutex
authenticated bool authenticated bool
token JwtToken token JwtToken
apiKey string
} }
func NewClient(httpclient *http.Client, baseUrl string) *Client { func NewClient(httpclient *http.Client, baseUrl string) *Client {
@ -32,6 +34,7 @@ func NewClient(httpclient *http.Client, baseUrl string) *Client {
httpClient: httpclient, httpClient: httpclient,
gql: graphql.NewClient(baseUrl, httpclient), gql: graphql.NewClient(baseUrl, httpclient),
rl: rate.NewLimiter(rate.Every(rateLimitPeriod), rateLimitBurst), rl: rate.NewLimiter(rate.Every(rateLimitPeriod), rateLimitBurst),
apirl: rate.NewLimiter(rate.Every(rateLimitPeriod/10), rateLimitBurst*10),
lock: &sync.Mutex{}, lock: &sync.Mutex{},
authenticated: false, authenticated: false,
} }
@ -50,6 +53,13 @@ func (c *Client) SetJWTToken(token JwtToken, audience string) {
c.authenticated = true 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 { func (c *Client) MaxComplexity() int {
if c.authenticated { if c.authenticated {
return MaxAuthenticatedQueryComplexity return MaxAuthenticatedQueryComplexity
@ -71,9 +81,16 @@ func (c *Client) Query(
variables interface{}, variables interface{},
options ...graphql.Option, options ...graphql.Option,
) error { ) error {
err := c.rl.Wait(ctx) if c.apiKey != "" {
if err != nil { err := c.apirl.Wait(ctx)
return errors.Wrap(err, "waiting for rate limit") 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() c.lock.Lock()
defer c.lock.Unlock() defer c.lock.Unlock()
@ -86,9 +103,16 @@ func (c *Client) QueryRaw(
variables interface{}, variables interface{},
options ...graphql.Option, options ...graphql.Option,
) ([]byte, error) { ) ([]byte, error) {
err := c.rl.Wait(ctx) if c.apiKey != "" {
if err != nil { err := c.apirl.Wait(ctx)
return nil, errors.Wrap(err, "waiting for rate limit") 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() c.lock.Lock()
defer c.lock.Unlock() defer c.lock.Unlock()
@ -101,9 +125,16 @@ func (c *Client) Mutate(
variables interface{}, variables interface{},
options ...graphql.Option, options ...graphql.Option,
) error { ) error {
err := c.rl.Wait(ctx) if c.apiKey != "" {
if err != nil { err := c.apirl.Wait(ctx)
return errors.Wrap(err, "waiting for rate limit") 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() c.lock.Lock()
defer c.lock.Unlock() defer c.lock.Unlock()

View File

@ -12,8 +12,8 @@ import (
) )
type baseUser struct { type baseUser struct {
Active bool `graphql:"active"` Active bool `graphql:"active"`
CardCounts struct { FootballCardCounts struct {
Common int `graphql:"common"` Common int `graphql:"common"`
CustomSeries int `graphql:"customSeries"` CustomSeries int `graphql:"customSeries"`
Limited int `graphql:"limited"` Limited int `graphql:"limited"`
@ -21,7 +21,7 @@ type baseUser struct {
SuperRare int `graphql:"superRare"` SuperRare int `graphql:"superRare"`
Unique int `graphql:"unique"` Unique int `graphql:"unique"`
Total int `graphql:"total"` Total int `graphql:"total"`
} `graphql:"cardCounts"` } `graphql:"footballCardCounts"`
CreatedAt time.Time `graphql:"createdAt"` CreatedAt time.Time `graphql:"createdAt"`
EthVaultId int `graphql:"ethVaultId"` EthVaultId int `graphql:"ethVaultId"`
EthereumAddress string `graphql:"ethereumAddress"` EthereumAddress string `graphql:"ethereumAddress"`