anilist/api.go
2023-10-09 13:48:09 +02:00

122 lines
2.1 KiB
Go

package anilist
import (
"bytes"
"context"
"encoding/json"
"net/http"
)
type Api struct {
AccessToken string
}
func NewApi(accessToken string) *Api {
return &Api{AccessToken: accessToken}
}
type queryObj struct {
Query string `json:"query"`
Vars interface{} `json:"variables"`
}
type responseObj[T any] struct {
Data T `json:"data"`
}
func request[T any](api *Api, query string, vars map[string]interface{}, respObj *responseObj[T]) error {
q := &queryObj{
Query: query,
Vars: vars,
}
queryData, err := json.Marshal(q)
if err != nil {
return err
}
req, err := http.NewRequest("POST", "https://graphql.anilist.co/", bytes.NewReader(queryData))
if err != nil {
return err
}
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Authorization", "Bearer "+api.AccessToken)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return handleError(resp)
}
//data, _ := ioutil.ReadAll(resp.Body)
//fmt.Println(string(data))
dec := json.NewDecoder(resp.Body)
err = dec.Decode(respObj)
if err != nil {
return err
}
return nil
}
func requestPaged[R any](api *Api, ctx context.Context, query string, vars map[string]interface{}, respObj *responseObj[*page[R]], onError func(error)) *Cursor[R] {
resp := responseObj[struct {
Page *page[R] `json:"Page"`
}]{}
var cancelFunc context.CancelFunc
ctx, cancelFunc = context.WithCancel(ctx)
out := make(chan *R, 50)
go func() {
defer close(out)
defer cancelFunc()
vars["page"] = 0
for {
if p, ok := vars["page"].(int); ok {
vars["page"] = p + 1
}
err := request(api, query, vars, &resp)
if err != nil {
if onError != nil {
onError(err)
}
return
}
if resp.Data.Page == nil {
return
}
for _, value := range resp.Data.Page.Data() {
value := value
select {
case out <- &value:
case <-ctx.Done():
return
}
}
if resp.Data.Page.PageInfo.CurrentPage == resp.Data.Page.PageInfo.LastPage {
return
}
}
}()
return &Cursor[R]{
Chan: out,
ctx: ctx,
cancelFunc: cancelFunc,
}
}