]> git.lizzy.rs Git - go-anidb.git/blob - fileepcache.go
Modernize
[go-anidb.git] / fileepcache.go
1 package anidb
2
3 import (
4         "github.com/EliasFleckenstein03/go-fscache"
5         "strconv"
6         "strings"
7         "time"
8 )
9
10 // Gets the Files that the given Group has released for the given
11 // Episode. Convenience method that calls FilesByGID.
12 func (adb *AniDB) FilesByGroup(ep *Episode, g *Group) <-chan *File {
13         ch := make(chan *File, 1)
14         if ep == nil || g == nil {
15                 ch <- nil
16                 close(ch)
17                 return ch
18         }
19         return adb.FilesByGID(ep, g.GID)
20 }
21
22 // Gets the Files that the Group (given by its ID) has released
23 // for the given Episode. The returned channel may return multiple
24 // (or no) Files. Uses the UDP API.
25 //
26 // On API error (offline, etc), the first *File returned is nil,
27 // followed by cached files (which may also be nil).
28 func (adb *AniDB) FilesByGID(ep *Episode, gid GID) <-chan *File {
29         ch := make(chan *File, 10)
30
31         fidChan := adb.FIDsByGID(ep, gid)
32
33         go func() {
34                 chs := []<-chan *File{}
35                 for fid := range fidChan {
36                         chs = append(chs, adb.FileByID(fid))
37                 }
38                 for _, c := range chs {
39                         for f := range c {
40                                 ch <- f
41                         }
42                 }
43                 close(ch)
44         }()
45         return ch
46 }
47
48 // Gets the FIDs that the Group (given by its ID) has released
49 // for the given Episode. The returned channel may return multiple
50 // (or no) FIDs. Uses the UDP API.
51 //
52 // On API error (offline, etc), the first *File returned is nil,
53 // followed by cached files (which may also be nil).
54 func (adb *AniDB) FIDsByGID(ep *Episode, gid GID) <-chan FID {
55         key := []fscache.CacheKey{"fid", "by-eid-gid", ep.EID, gid}
56
57         ch := make(chan FID, 10)
58
59         if ep == nil || gid < 1 {
60                 ch <- 0
61                 close(ch)
62                 return ch
63         }
64
65         ic := make(chan notification, 1)
66         go func() {
67                 for c := range ic {
68                         ch <- c.(FID)
69                 }
70                 close(ch)
71         }()
72         if intentMap.Intent(ic, key...) {
73                 return ch
74         }
75
76         if !Cache.IsValid(InvalidKeyCacheDuration, key...) {
77                 intentMap.Close(key...)
78                 return ch
79         }
80
81         var fids []FID
82         switch ts, err := Cache.Get(&fids, key...); {
83         case err == nil && time.Now().Sub(ts) < FileCacheDuration:
84                 is := intentMap.LockIntent(key...)
85                 go func() {
86                         defer intentMap.Free(is, key...)
87                         defer is.Close()
88
89                         for _, fid := range fids {
90                                 is.Notify(fid)
91                         }
92                 }()
93                 return ch
94         }
95
96         go func() {
97                 reply := <-adb.udp.SendRecv("FILE",
98                         paramMap{
99                                 "aid":   ep.AID,
100                                 "gid":   gid,
101                                 "epno":  ep.Episode.String(),
102                                 "fmask": fileFmask,
103                                 "amask": fileAmask,
104                         })
105
106                 is := intentMap.LockIntent(key...)
107                 defer intentMap.Free(is, key...)
108
109                 switch reply.Code() {
110                 case 220:
111                         var f *File
112                         if adb.parseFileResponse(&f, reply, true) {
113                                 fids = []FID{f.FID}
114                                 CacheSet(&fids, key...)
115
116                                 cacheFile(f)
117
118                                 is.NotifyClose(f.FID)
119                         } else {
120                                 is.NotifyClose(FID(0))
121                         }
122                         return
123                 case 322:
124                         parts := strings.Split(reply.Lines()[1], "|")
125                         fids = make([]FID, len(parts))
126                         for i := range parts {
127                                 id, _ := strconv.ParseInt(parts[i], 10, 32)
128                                 fids[i] = FID(id)
129                         }
130
131                         CacheSet(&fids, key...)
132                 case 320:
133                         Cache.SetInvalid(key...)
134                         is.Close()
135                         return
136                 default:
137                         is.Notify(FID(0))
138                 }
139
140                 defer is.Close()
141                 for _, fid := range fids {
142                         is.Notify(fid)
143                 }
144         }()
145         return ch
146 }