]> git.lizzy.rs Git - go-anidb.git/blob - usercache.go
Modernize
[go-anidb.git] / usercache.go
1 package anidb
2
3 import (
4         "github.com/EliasFleckenstein03/go-anidb/udp"
5         "github.com/EliasFleckenstein03/go-fscache"
6         "strconv"
7         "strings"
8         "sync"
9         "time"
10 )
11
12 type UID int
13
14 func (uid UID) User() *User {
15         var u User
16         if CacheGet(&u, "user", uid) == nil {
17                 return &u
18         }
19         return nil
20 }
21
22 func UserByName(name string) *User {
23         var uid UID
24         if CacheGet(&uid, "user", "by-name", name) == nil {
25                 return uid.User()
26         }
27         return nil
28 }
29
30 func (adb *AniDB) GetCurrentUser() <-chan *User {
31         ch := make(chan *User, 1)
32
33         if adb.udp.credentials == nil {
34                 ch <- nil
35                 close(ch)
36                 return ch
37         }
38
39         return adb.GetUserByName(decrypt(adb.udp.credentials.username))
40 }
41
42 // This is an (almost) entirely local representation.
43 func (adb *AniDB) GetUserByID(uid UID) <-chan *User {
44         key := []fscache.CacheKey{"user", uid}
45         ch := make(chan *User, 1)
46
47         if uid < 1 {
48                 ch <- nil
49                 close(ch)
50                 return ch
51         }
52
53         ic := make(chan notification, 1)
54         go func() { ch <- (<-ic).(*User); close(ch) }()
55         if intentMap.Intent(ic, key...) {
56                 return ch
57         }
58
59         if !Cache.IsValid(InvalidKeyCacheDuration, key...) {
60                 intentMap.NotifyClose((*User)(nil), key...)
61                 return ch
62         }
63
64         go func() {
65                 var user *User
66                 if CacheGet(&user, key...) == nil {
67                         intentMap.NotifyClose(user, key...)
68                         return
69                 }
70                 <-adb.GetUserName(uid)
71
72                 CacheGet(&user, key...)
73                 intentMap.NotifyClose(user)
74         }()
75         return ch
76 }
77
78 func (adb *AniDB) GetUserByName(username string) <-chan *User {
79         ch := make(chan *User, 1)
80
81         if username == "" {
82                 ch <- nil
83                 close(ch)
84                 return ch
85         }
86
87         go func() {
88                 ch <- <-adb.GetUserByID(<-adb.GetUserUID(username))
89                 close(ch)
90         }()
91         return ch
92 }
93
94 func (adb *AniDB) GetUserUID(username string) <-chan UID {
95         key := []fscache.CacheKey{"user", "by-name", username}
96         ch := make(chan UID, 1)
97
98         if username == "" {
99                 ch <- 0
100                 close(ch)
101                 return ch
102         }
103
104         ic := make(chan notification, 1)
105         go func() { ch <- (<-ic).(UID); close(ch) }()
106         if intentMap.Intent(ic, key...) {
107                 return ch
108         }
109
110         if !Cache.IsValid(InvalidKeyCacheDuration, key...) {
111                 intentMap.NotifyClose((UID)(0), key...)
112                 return ch
113         }
114
115         uid := UID(0)
116         switch ts, err := Cache.Get(&uid, key...); {
117         case err == nil && time.Now().Sub(ts) < UIDCacheDuration:
118                 intentMap.NotifyClose(uid, key...)
119                 return ch
120         }
121
122         go func() {
123                 reply := <-adb.udp.SendRecv("USER",
124                         paramMap{"user": username})
125
126                 switch reply.Code() {
127                 case 295:
128                         uid, _ = parseUserReply(reply) // caches
129                 case 394:
130                         Cache.SetInvalid(key...)
131                 }
132
133                 intentMap.NotifyClose(uid, key...)
134         }()
135         return ch
136 }
137
138 func (adb *AniDB) GetUserName(uid UID) <-chan string {
139         key := []fscache.CacheKey{"user", "by-uid", uid}
140         ch := make(chan string, 1)
141
142         if uid < 1 {
143                 ch <- ""
144                 close(ch)
145                 return ch
146         }
147
148         ic := make(chan notification, 1)
149         go func() { ch <- (<-ic).(string); close(ch) }()
150         if intentMap.Intent(ic, key...) {
151                 return ch
152         }
153
154         if !Cache.IsValid(InvalidKeyCacheDuration, key...) {
155                 intentMap.NotifyClose("", key...)
156                 return ch
157         }
158
159         name := ""
160         switch ts, err := Cache.Get(&name, key...); {
161         case err == nil && time.Now().Sub(ts) < UIDCacheDuration:
162                 intentMap.NotifyClose(name, key...)
163                 return ch
164         }
165
166         go func() {
167                 reply := <-adb.udp.SendRecv("USER",
168                         paramMap{"uid": uid})
169
170                 switch reply.Code() {
171                 case 295:
172                         _, name = parseUserReply(reply) // caches
173                 case 394:
174                         Cache.SetInvalid(key...)
175                 }
176
177                 intentMap.NotifyClose(name, key...)
178         }()
179         return ch
180 }
181
182 var userReplyMutex sync.Mutex
183
184 func parseUserReply(reply udpapi.APIReply) (UID, string) {
185         userReplyMutex.Lock()
186         defer userReplyMutex.Unlock()
187
188         if reply.Error() == nil {
189                 parts := strings.Split(reply.Lines()[1], "|")
190                 id, _ := strconv.ParseInt(parts[0], 10, 32)
191
192                 CacheSet(UID(id), "user", "by-name", parts[1])
193                 CacheSet(parts[1], "user", "by-uid", id)
194
195                 if _, err := Cache.Stat("user", id); err != nil {
196                         CacheSet(&User{
197                                 UID:      UID(id),
198                                 Username: parts[1],
199                         }, "user", id)
200                 }
201
202                 return UID(id), parts[1]
203         }
204         return 0, ""
205 }