118 lines
2.1 KiB
Go
118 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()
|
|
|
|
//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,
|
|
}
|
|
}
|