2022-10-09 06:31:38 +00:00
|
|
|
package twhelp
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
2022-10-27 09:56:40 +00:00
|
|
|
"strconv"
|
2022-10-09 06:31:38 +00:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
defaultUserAgent = "TWHelpDCBot/development"
|
|
|
|
defaultTimeout = 10 * time.Second
|
|
|
|
|
2022-10-27 09:56:40 +00:00
|
|
|
endpointListVersions = "/api/v1/versions"
|
|
|
|
endpointGetServer = "/api/v1/versions/%s/servers/%s"
|
|
|
|
endpointGetTribeByTag = "/api/v1/versions/%s/servers/%s/tribes/tag/%s"
|
|
|
|
endpointListEnnoblements = "/api/v1/versions/%s/servers/%s/ennoblements"
|
2022-10-09 06:31:38 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Client struct {
|
|
|
|
userAgent string
|
|
|
|
client *http.Client
|
|
|
|
baseURL *url.URL
|
|
|
|
}
|
|
|
|
|
|
|
|
type ClientOption func(c *Client)
|
|
|
|
|
|
|
|
func WithHTTPClient(hc *http.Client) ClientOption {
|
|
|
|
return func(c *Client) {
|
|
|
|
c.client = hc
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func WithUserAgent(ua string) ClientOption {
|
|
|
|
return func(c *Client) {
|
|
|
|
c.userAgent = ua
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewClient(baseURL *url.URL, opts ...ClientOption) *Client {
|
|
|
|
c := &Client{
|
|
|
|
baseURL: baseURL,
|
|
|
|
userAgent: defaultUserAgent,
|
|
|
|
client: &http.Client{
|
|
|
|
Timeout: defaultTimeout,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, opt := range opts {
|
|
|
|
opt(c)
|
|
|
|
}
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) ListVersions(ctx context.Context) ([]Version, error) {
|
|
|
|
var resp listVersionsResp
|
|
|
|
if err := c.getJSON(ctx, endpointListVersions, &resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp.Data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) GetServer(ctx context.Context, version, server string) (Server, error) {
|
|
|
|
var resp getServerResp
|
|
|
|
if err := c.getJSON(ctx, fmt.Sprintf(endpointGetServer, version, server), &resp); err != nil {
|
|
|
|
return Server{}, err
|
|
|
|
}
|
|
|
|
return resp.Data, nil
|
|
|
|
}
|
|
|
|
|
2022-10-23 06:20:48 +00:00
|
|
|
func (c *Client) GetTribeByTag(ctx context.Context, version, server, tag string) (Tribe, error) {
|
|
|
|
var resp getTribeResp
|
|
|
|
if err := c.getJSON(ctx, fmt.Sprintf(endpointGetTribeByTag, version, server, tag), &resp); err != nil {
|
|
|
|
return Tribe{}, err
|
|
|
|
}
|
|
|
|
return resp.Data, nil
|
|
|
|
}
|
|
|
|
|
2022-10-27 09:56:40 +00:00
|
|
|
type ListEnnoblementsSort string
|
|
|
|
|
|
|
|
const (
|
|
|
|
ListEnnoblementsSortCreatedAtASC ListEnnoblementsSort = "createdAt:ASC"
|
|
|
|
)
|
|
|
|
|
|
|
|
func (s ListEnnoblementsSort) String() string {
|
|
|
|
return string(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
type ListEnnoblementsQueryParams struct {
|
|
|
|
Limit int32
|
|
|
|
Offset int32
|
|
|
|
Since time.Time
|
|
|
|
Sort []ListEnnoblementsSort
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) ListEnnoblements(ctx context.Context, version, server string, queryParams ListEnnoblementsQueryParams) ([]Ennoblement, error) {
|
|
|
|
q := url.Values{}
|
|
|
|
|
|
|
|
if queryParams.Limit > 0 {
|
|
|
|
q.Set("limit", strconv.Itoa(int(queryParams.Limit)))
|
|
|
|
}
|
|
|
|
|
|
|
|
if queryParams.Offset > 0 {
|
|
|
|
q.Set("offset", strconv.Itoa(int(queryParams.Offset)))
|
|
|
|
}
|
|
|
|
|
|
|
|
if !queryParams.Since.IsZero() {
|
|
|
|
q.Set("since", queryParams.Since.Format(time.RFC3339))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, s := range queryParams.Sort {
|
|
|
|
q.Add("sort", s.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
var resp listEnnoblementsResp
|
|
|
|
if err := c.getJSON(ctx, fmt.Sprintf(endpointListEnnoblements, version, server)+"?"+q.Encode(), &resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp.Data, nil
|
|
|
|
}
|
|
|
|
|
2022-10-09 06:31:38 +00:00
|
|
|
func (c *Client) getJSON(ctx context.Context, urlStr string, v any) error {
|
|
|
|
u, err := c.baseURL.Parse(urlStr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("c.baseURL.Parse: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("http.NewRequestWithContext: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// headers
|
|
|
|
req.Header.Set("User-Agent", c.userAgent)
|
|
|
|
|
|
|
|
resp, err := c.client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("client.Do: %w", err)
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
_ = resp.Body.Close()
|
|
|
|
}()
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
var errResp errorResp
|
|
|
|
if err = json.NewDecoder(resp.Body).Decode(&errResp); err != nil {
|
|
|
|
_, _ = io.Copy(io.Discard, resp.Body)
|
|
|
|
return fmt.Errorf("got non-ok HTTP status: %d", resp.StatusCode)
|
|
|
|
}
|
|
|
|
return errResp.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = json.NewDecoder(resp.Body).Decode(v); err != nil {
|
|
|
|
return fmt.Errorf("couldn't decode resp body: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|