context and cursor introduced

This commit is contained in:
Tordarus 2022-02-06 10:39:04 +01:00
parent d1cec22dcd
commit 0915ab09fa
8 changed files with 64 additions and 14 deletions

View File

@ -1,8 +1,10 @@
package anilist package anilist
func (api *Api) GetAiringSchedule(vars AiringScheduleQuery, onError func(error)) <-chan *AiringSchedule { import "context"
func (api *Api) GetAiringSchedule(ctx context.Context, vars AiringScheduleQuery, onError func(error)) Cursor[AiringSchedule] {
resp := responseObj[*page[AiringSchedule]]{} resp := responseObj[*page[AiringSchedule]]{}
return requestPaged(api, getAiringScheduleQuery, vars.toMap(), &resp, onError) return requestPaged(api, ctx, getAiringScheduleQuery, vars.toMap(), &resp, onError)
} }
const ( const (

19
api.go
View File

@ -2,6 +2,7 @@ package anilist
import ( import (
"bytes" "bytes"
"context"
"encoding/json" "encoding/json"
"net/http" "net/http"
) )
@ -60,15 +61,19 @@ func request[T any](api *Api, query string, vars map[string]interface{}, respObj
return nil return nil
} }
func requestPaged[R any](api *Api, query string, vars map[string]interface{}, respObj *responseObj[*page[R]], onError func(error)) <-chan *R { 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 { resp := responseObj[struct {
Page *page[R] `json:"Page"` Page *page[R] `json:"Page"`
}]{} }]{}
var cancelFunc context.CancelFunc
ctx, cancelFunc = context.WithCancel(ctx)
out := make(chan *R, 50) out := make(chan *R, 50)
go func() { go func() {
defer close(out) defer close(out)
defer cancelFunc()
vars["page"] = 0 vars["page"] = 0
@ -87,7 +92,11 @@ func requestPaged[R any](api *Api, query string, vars map[string]interface{}, re
for _, value := range resp.Data.Page.Data() { for _, value := range resp.Data.Page.Data() {
value := value value := value
out <- &value select {
case out <- &value:
case <-ctx.Done():
return
}
} }
if resp.Data.Page.PageInfo.CurrentPage == resp.Data.Page.PageInfo.LastPage { if resp.Data.Page.PageInfo.CurrentPage == resp.Data.Page.PageInfo.LastPage {
@ -96,5 +105,9 @@ func requestPaged[R any](api *Api, query string, vars map[string]interface{}, re
} }
}() }()
return out return Cursor[R]{
Chan: out,
ctx: ctx,
cancelFunc: cancelFunc,
}
} }

31
cursor.go Normal file
View File

@ -0,0 +1,31 @@
package anilist
import "context"
type Cursor[T any] struct {
ctx context.Context
cancelFunc context.CancelFunc
Chan <-chan *T
}
func (c Cursor[T]) First() *T {
defer c.cancelFunc()
return <-c.Chan
}
func (c Cursor[T]) Next() (*T, bool) {
if c.ctx.Err() == nil {
value, ok := <-c.Chan
return value, ok
}
return nil, false
}
func (c Cursor[T]) Slice() []T {
s := make([]T, 0)
for value, ok := c.Next(); ok; value, ok = c.Next() {
s = append(s, *value)
}
return s
}

View File

@ -1,8 +1,10 @@
package anilist package anilist
func (api *Api) GetMedia(vars MediaQuery, onError func(error)) <-chan *Media { import "context"
func (api *Api) GetMedia(ctx context.Context, vars MediaQuery, onError func(error)) Cursor[Media] {
resp := responseObj[*page[Media]]{} resp := responseObj[*page[Media]]{}
return requestPaged(api, getMediaQuery, vars.toMap(), &resp, onError) return requestPaged(api, ctx, getMediaQuery, vars.toMap(), &resp, onError)
} }
const ( const (

View File

@ -1,8 +1,10 @@
package anilist package anilist
func (api *Api) GetMediaList(vars MediaListQuery, onError func(error)) <-chan *MediaList { import "context"
func (api *Api) GetMediaList(ctx context.Context, vars MediaListQuery, onError func(error)) Cursor[MediaList] {
resp := responseObj[*page[MediaList]]{} resp := responseObj[*page[MediaList]]{}
return requestPaged(api, getMediaListQuery, vars.toMap(), &resp, onError) return requestPaged(api, ctx, getMediaListQuery, vars.toMap(), &resp, onError)
} }
const ( const (

View File

@ -7,7 +7,6 @@ const (
airingAt airingAt
timeUntilAiring timeUntilAiring
episode episode
media ` + subSelectionMedia + `
}` }`
subSelectionMediaList = `{ subSelectionMediaList = `{
@ -93,7 +92,7 @@ const (
isAdult isAdult
userId userId
} }
nextAiringEpisode nextAiringEpisode ` + subSelectionAiringSchedule + `
}` }`
subSelectionFuzzyDate = `{ subSelectionFuzzyDate = `{

View File

@ -211,5 +211,4 @@ type AiringSchedule struct {
AiringAt UnixTime `json:"airingAt"` AiringAt UnixTime `json:"airingAt"`
TimeUntilAiring Seconds `json:"timeUntilAiring"` TimeUntilAiring Seconds `json:"timeUntilAiring"`
Episode int `json:"episode"` Episode int `json:"episode"`
Media *Media `json:"media"`
} }

View File

@ -1,5 +1,7 @@
package anilist package anilist
import "context"
func (api *Api) GetUserByName(name string) (*User, error) { func (api *Api) GetUserByName(name string) (*User, error) {
query := `query ($name: String) { query := `query ($name: String) {
User (name: $name) ` + subSelectionUser + ` User (name: $name) ` + subSelectionUser + `
@ -42,10 +44,10 @@ func (api *Api) GetUserByID(id int) (*User, error) {
return resp.Data.User, nil return resp.Data.User, nil
} }
func (api *Api) SearchUsers(search string, onError func(error)) <-chan *User { func (api *Api) SearchUsers(ctx context.Context, search string, onError func(error)) Cursor[User] {
vars := map[string]interface{}{"search": search} vars := map[string]interface{}{"search": search}
resp := responseObj[*page[User]]{} resp := responseObj[*page[User]]{}
return requestPaged(api, searchUsersQuery, vars, &resp, onError) return requestPaged(api, ctx, searchUsersQuery, vars, &resp, onError)
} }
const ( const (