X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=animecache.go;h=eff4df677e73928339bfee4caccd81bdafda0bcb;hb=fbcc6296ee6547aa88c6e6b4491a617a916ee107;hp=f185867ca384017826b20b6b4670820cb35a5950;hpb=822e77c37cc5aecbba5ef99f4beb9eaf54bfd612;p=go-anidb.git diff --git a/animecache.go b/animecache.go index f185867..eff4df6 100644 --- a/animecache.go +++ b/animecache.go @@ -1,48 +1,47 @@ package anidb import ( - "encoding/gob" "fmt" "github.com/Kovensky/go-anidb/http" "github.com/Kovensky/go-anidb/misc" "github.com/Kovensky/go-anidb/udp" + "github.com/Kovensky/go-fscache" "sort" "strconv" "strings" "time" ) -func init() { - gob.RegisterName("*github.com/Kovensky/go-anidb.Anime", &Anime{}) - gob.RegisterName("github.com/Kovensky/go-anidb.AID", AID(0)) -} +var _ cacheable = &Anime{} -func (a *Anime) Touch() { - a.Cached = time.Now() +func (a *Anime) setCachedTS(ts time.Time) { + a.Cached = ts } func (a *Anime) IsStale() bool { if a == nil { return true } + now := time.Now() + diff := now.Sub(a.Cached) if a.Incomplete { - return time.Now().Sub(a.Cached) > AnimeIncompleteCacheDuration + return diff > AnimeIncompleteCacheDuration + } + + // If the anime ended, and more than AnimeCacheDuration time ago at that + if !a.EndDate.IsZero() && now.After(a.EndDate.Add(AnimeCacheDuration)) { + return diff > FinishedAnimeCacheDuration } - return time.Now().Sub(a.Cached) > AnimeCacheDuration + return diff > AnimeCacheDuration } // Unique Anime IDentifier. type AID int -// make AID Cacheable - -func (e AID) Touch() {} -func (e AID) IsStale() bool { return false } - // Returns a cached Anime. Returns nil if there is no cached Anime with this AID. func (aid AID) Anime() *Anime { var a Anime - if cache.Get(&a, "aid", aid) == nil { + if CacheGet(&a, "aid", aid) == nil { return &a } return nil @@ -53,32 +52,38 @@ type httpAnimeResponse struct { err error } -// Retrieves an Anime by its AID. Uses both HTTP and UDP APIs, +// Retrieves an Anime by its AID. Uses both the HTTP and UDP APIs, // but can work without the UDP API. func (adb *AniDB) AnimeByID(aid AID) <-chan *Anime { - keys := []cacheKey{"aid", aid} + key := []fscache.CacheKey{"aid", aid} ch := make(chan *Anime, 1) - ic := make(chan Cacheable, 1) + if aid < 1 { + ch <- nil + close(ch) + } + + ic := make(chan notification, 1) go func() { ch <- (<-ic).(*Anime); close(ch) }() - if intentMap.Intent(ic, keys...) { + if intentMap.Intent(ic, key...) { return ch } - if !cache.CheckValid(keys...) { - intentMap.Notify((*Anime)(nil), keys...) + if !Cache.IsValid(InvalidKeyCacheDuration, key...) { + intentMap.NotifyClose((*Anime)(nil), key...) return ch } anime := aid.Anime() if !anime.IsStale() { - intentMap.Notify(anime, keys...) + intentMap.NotifyClose(anime, key...) return ch } go func() { httpChan := make(chan httpAnimeResponse, 1) go func() { + adb.Logger.Printf("HTTP>>> Anime %d", aid) a, err := httpapi.GetAnime(int(aid)) httpChan <- httpAnimeResponse{anime: a, err: err} }() @@ -101,16 +106,34 @@ func (adb *AniDB) AnimeByID(aid AID) <-chan *Anime { for i := 0; i < 2; i++ { select { case <-timeout: - ok = false + // HTTP API timeout + if httpChan != nil { + adb.Logger.Printf("HTTP<<< Timeout") + close(httpChan) + } case resp := <-httpChan: if resp.err != nil { + adb.Logger.Printf("HTTP<<< %v", resp.err) ok = false break Loop } - if !anime.populateFromHTTP(resp.anime) { + + if resp.anime.Error != "" { + adb.Logger.Printf("HTTP<<< Error %q", resp.anime.Error) + } + + if anime.populateFromHTTP(resp.anime) { + adb.Logger.Printf("HTTP<<< Anime %q", anime.PrimaryTitle) + } else { // HTTP ok but parsing not ok if anime.PrimaryTitle == "" { - cache.MarkInvalid(keys...) + Cache.SetInvalid(key...) + } + + switch resp.anime.Error { + case "Anime not found", "aid Missing or Invalid": + // deleted AID? + Cache.Delete(key...) } ok = false @@ -120,7 +143,9 @@ func (adb *AniDB) AnimeByID(aid AID) <-chan *Anime { httpChan = nil case reply := <-udpChan: if reply.Code() == 330 { - cache.MarkInvalid(keys...) + Cache.SetInvalid(key...) + // deleted AID? + Cache.Delete(key...) ok = false break Loop @@ -132,11 +157,11 @@ func (adb *AniDB) AnimeByID(aid AID) <-chan *Anime { } if anime.PrimaryTitle != "" { if ok { - cache.Set(anime, keys...) + CacheSet(anime, key...) } - intentMap.Notify(anime, keys...) + intentMap.NotifyClose(anime, key...) } else { - intentMap.Notify((*Anime)(nil), keys...) + intentMap.NotifyClose((*Anime)(nil), key...) } }() return ch @@ -220,7 +245,7 @@ func (a *Anime) populateFromHTTP(reply httpapi.Anime) bool { titles[Language(title.Lang)] = title.Title } - e := Episode{ + e := &Episode{ EID: EID(ep.ID), AID: a.AID, @@ -236,12 +261,12 @@ func (a *Anime) populateFromHTTP(reply httpapi.Anime) bool { Titles: titles, } counts[e.Type]++ - cacheEpisode(&e) + cacheEpisode(e) a.Episodes = append(a.Episodes, e) } - a.EpisodeCount = EpisodeCount{ + a.EpisodeCount = misc.EpisodeCount{ RegularCount: counts[misc.EpisodeTypeRegular], SpecialCount: counts[misc.EpisodeTypeSpecial], CreditsCount: counts[misc.EpisodeTypeCredits],