]> git.lizzy.rs Git - go-anidb.git/commitdiff
anidb: Implement USER
authorDiogo Franco (Kovensky) <diogomfranco@gmail.com>
Wed, 17 Jul 2013 20:58:06 +0000 (17:58 -0300)
committerDiogo Franco (Kovensky) <diogomfranco@gmail.com>
Wed, 17 Jul 2013 20:58:06 +0000 (17:58 -0300)
misc.go
user.go [new file with mode: 0644]
usercache.go [new file with mode: 0644]

diff --git a/misc.go b/misc.go
index b6d9db828c46e977d8ff0954b393f30fd6672275..8393a0fd7b489791263a3bde9b9f766b3ebc98c6 100644 (file)
--- a/misc.go
+++ b/misc.go
@@ -15,6 +15,8 @@ var (
        GroupCacheDuration   = 4 * DefaultCacheDuration // They don't change that often.
        FileCacheDuration    = 8 * DefaultCacheDuration // These change even less often.
 
+       UIDCacheDuration = 16 * DefaultCacheDuration // Can these even be changed?
+
        // Used for anime that have already finished airing.
        // It's unlikely that they get any important updates.
        FinishedAnimeCacheDuration = 4 * AnimeCacheDuration
diff --git a/user.go b/user.go
new file mode 100644 (file)
index 0000000..33625bd
--- /dev/null
+++ b/user.go
@@ -0,0 +1,9 @@
+package anidb
+
+type User struct {
+       UID UID
+
+       Username string
+
+       // MyList MyList
+}
diff --git a/usercache.go b/usercache.go
new file mode 100644 (file)
index 0000000..9ad8113
--- /dev/null
@@ -0,0 +1,189 @@
+package anidb
+
+import (
+       "github.com/Kovensky/go-anidb/udp"
+       "github.com/Kovensky/go-fscache"
+       "strconv"
+       "strings"
+       "sync"
+       "time"
+)
+
+type UID int
+
+func (adb *AniDB) GetCurrentUser() <-chan *User {
+       ch := make(chan *User, 1)
+
+       if adb.udp.credentials == nil {
+               ch <- nil
+               close(ch)
+               return ch
+       }
+
+       return adb.GetUserByName(decrypt(adb.udp.credentials.username))
+}
+
+// This is an (almost) entirely local representation.
+func (adb *AniDB) GetUserByID(uid UID) <-chan *User {
+       key := []fscache.CacheKey{"user", uid}
+       ch := make(chan *User, 1)
+
+       if uid < 1 {
+               ch <- nil
+               close(ch)
+               return ch
+       }
+
+       ic := make(chan notification, 1)
+       go func() { ch <- (<-ic).(*User); close(ch) }()
+       if intentMap.Intent(ic, key...) {
+               return ch
+       }
+
+       if !Cache.IsValid(InvalidKeyCacheDuration, key...) {
+               intentMap.NotifyClose((*User)(nil), key...)
+               return ch
+       }
+
+       go func() {
+               var user *User
+               if CacheGet(&user, key...) == nil {
+                       intentMap.NotifyClose(user, key...)
+                       return
+               }
+               <-adb.GetUserName(uid)
+
+               CacheGet(&user, key...)
+               intentMap.NotifyClose(user)
+       }()
+       return ch
+}
+
+func (adb *AniDB) GetUserByName(username string) <-chan *User {
+       ch := make(chan *User, 1)
+
+       if username == "" {
+               ch <- nil
+               close(ch)
+               return ch
+       }
+
+       go func() {
+               ch <- <-adb.GetUserByID(<-adb.GetUserUID(username))
+               close(ch)
+       }()
+       return ch
+}
+
+func (adb *AniDB) GetUserUID(username string) <-chan UID {
+       key := []fscache.CacheKey{"user", "by-name", username}
+       ch := make(chan UID, 1)
+
+       if username == "" {
+               ch <- 0
+               close(ch)
+               return ch
+       }
+
+       ic := make(chan notification, 1)
+       go func() { ch <- (<-ic).(UID); close(ch) }()
+       if intentMap.Intent(ic, key...) {
+               return ch
+       }
+
+       if !Cache.IsValid(InvalidKeyCacheDuration, key...) {
+               intentMap.NotifyClose((UID)(0), key...)
+               return ch
+       }
+
+       uid := UID(0)
+       switch ts, err := Cache.Get(&uid, key...); {
+       case err == nil && time.Now().Sub(ts) < UIDCacheDuration:
+               intentMap.NotifyClose(uid, key...)
+               return ch
+       }
+
+       go func() {
+               reply := <-adb.udp.SendRecv("USER",
+                       paramMap{"user": username})
+
+               switch reply.Code() {
+               case 295:
+                       uid, _ = parseUserReply(reply) // caches
+               case 394:
+                       Cache.SetInvalid(key...)
+               }
+
+               intentMap.NotifyClose(uid, key...)
+       }()
+       return ch
+}
+
+func (adb *AniDB) GetUserName(uid UID) <-chan string {
+       key := []fscache.CacheKey{"user", "by-uid", uid}
+       ch := make(chan string, 1)
+
+       if uid < 1 {
+               ch <- ""
+               close(ch)
+               return ch
+       }
+
+       ic := make(chan notification, 1)
+       go func() { ch <- (<-ic).(string); close(ch) }()
+       if intentMap.Intent(ic, key...) {
+               return ch
+       }
+
+       if !Cache.IsValid(InvalidKeyCacheDuration, key...) {
+               intentMap.NotifyClose("", key...)
+               return ch
+       }
+
+       name := ""
+       switch ts, err := Cache.Get(&name, key...); {
+       case err == nil && time.Now().Sub(ts) < UIDCacheDuration:
+               intentMap.NotifyClose(name, key...)
+               return ch
+       }
+
+       go func() {
+               reply := <-adb.udp.SendRecv("USER",
+                       paramMap{"uid": uid})
+
+               switch reply.Code() {
+               case 295:
+                       _, name = parseUserReply(reply) // caches
+               case 394:
+                       Cache.SetInvalid(key...)
+               }
+
+               intentMap.NotifyClose(name, key...)
+       }()
+       return ch
+}
+
+var userReplyMutex sync.Mutex
+
+func parseUserReply(reply udpapi.APIReply) (UID, string) {
+       userReplyMutex.Lock()
+       defer userReplyMutex.Unlock()
+
+       if reply.Error() == nil {
+               parts := strings.Split(reply.Lines()[1], "|")
+               id, _ := strconv.ParseInt(parts[0], 10, 32)
+
+               CacheSet(UID(id), "user", "by-name", parts[1])
+               CacheSet(parts[1], "user", "by-uid", id)
+
+               if _, err := Cache.Stat("user", id); err != nil {
+                       CacheSet(&User{
+                               UID:      UID(id),
+                               Username: parts[1],
+                       }, "user", id)
+               }
+
+               return UID(id), parts[1]
+       }
+       return 0, ""
+}