]> git.lizzy.rs Git - go-anidb.git/commitdiff
anidb: Implement GroupByName
authorDiogo Franco (Kovensky) <diogomfranco@gmail.com>
Mon, 15 Jul 2013 03:26:29 +0000 (00:26 -0300)
committerDiogo Franco (Kovensky) <diogomfranco@gmail.com>
Mon, 15 Jul 2013 03:26:29 +0000 (00:26 -0300)
Also add the invalid key guard to GroupByID.

groupcache.go

index e67cd59943640e4e4ad098871bbc748fc59b03c6..dbf30371ad8c08daa95980b4955820aba83b86bd 100644 (file)
@@ -3,6 +3,7 @@ package anidb
 import (
        "encoding/gob"
        "github.com/Kovensky/go-anidb/http"
+       "github.com/Kovensky/go-anidb/udp"
        "strconv"
        "strings"
        "time"
@@ -10,6 +11,8 @@ import (
 
 func init() {
        gob.RegisterName("*github.com/Kovensky/go-anidb.Group", &Group{})
+       gob.RegisterName("github.com/Kovensky/go-anidb.GID", GID(0))
+       gob.RegisterName("*github.com/Kovensky/go-anidb.gidCache", &gidCache{})
 }
 
 func (g *Group) Touch() {
@@ -26,6 +29,11 @@ func (g *Group) IsStale() bool {
 // Unique Group IDentifier
 type GID int
 
+// make GID cacheable
+
+func (e GID) Touch()        {}
+func (e GID) IsStale() bool { return false }
+
 // Retrieves the Group from the cache.
 func (gid GID) Group() *Group {
        var g Group
@@ -35,6 +43,19 @@ func (gid GID) Group() *Group {
        return nil
 }
 
+type gidCache struct {
+       GID
+       Time time.Time
+}
+
+func (c *gidCache) Touch() { c.Time = time.Now() }
+func (c *gidCache) IsStale() bool {
+       if c != nil && time.Now().Sub(c.Time) < GroupCacheDuration {
+               return false
+       }
+       return true
+}
+
 // Returns a Group from the cache if possible.
 //
 // If the Group is stale, then retrieves the Group
@@ -49,6 +70,11 @@ func (adb *AniDB) GroupByID(gid GID) <-chan *Group {
                return ch
        }
 
+       if !cache.CheckValid(keys...) {
+               intentMap.Notify((*Group)(nil), keys...)
+               return ch
+       }
+
        if g := gid.Group(); !g.IsStale() {
                intentMap.Notify(g, keys...)
                return ch
@@ -60,79 +86,150 @@ func (adb *AniDB) GroupByID(gid GID) <-chan *Group {
 
                var g *Group
                if reply.Error() == nil {
-                       parts := strings.Split(reply.Lines()[1], "|")
-                       ints := make([]int64, len(parts))
-                       for i := range parts {
-                               ints[i], _ = strconv.ParseInt(parts[i], 10, 32)
-                       }
-
-                       irc := ""
-                       if parts[7] != "" {
-                               irc = "irc://" + parts[8] + "/" + parts[7][1:]
-                       }
-
-                       pic := ""
-                       if parts[10] != "" {
-                               pic = httpapi.AniDBImageBaseURL + parts[10]
-                       }
-
-                       rellist := strings.Split(parts[16], "'")
-                       relations := make(map[GID]GroupRelationType, len(rellist))
-                       for _, rel := range rellist {
-                               r := strings.Split(rel, ",")
-                               gid, _ := strconv.ParseInt(r[0], 10, 32)
-                               typ, _ := strconv.ParseInt(r[1], 10, 32)
-
-                               relations[GID(gid)] = GroupRelationType(typ)
-                       }
-
-                       ft := time.Unix(ints[11], 0)
-                       if ints[11] == 0 {
-                               ft = time.Time{}
-                       }
-                       dt := time.Unix(ints[12], 0)
-                       if ints[12] == 0 {
-                               dt = time.Time{}
-                       }
-                       lr := time.Unix(ints[14], 0)
-                       if ints[14] == 0 {
-                               lr = time.Time{}
-                       }
-                       la := time.Unix(ints[15], 0)
-                       if ints[15] == 0 {
-                               la = time.Time{}
-                       }
-
-                       g = &Group{
-                               GID: GID(ints[0]),
-
-                               Name:      parts[5],
-                               ShortName: parts[6],
-
-                               IRC:     irc,
-                               URL:     parts[9],
-                               Picture: pic,
-
-                               Founded:   ft,
-                               Disbanded: dt,
-                               // ignore ints[13]
-                               LastRelease:  lr,
-                               LastActivity: la,
-
-                               Rating: Rating{
-                                       Rating:    float32(ints[1]) / 100,
-                                       VoteCount: int(ints[2]),
-                               },
-                               AnimeCount: int(ints[3]),
-                               FileCount:  int(ints[4]),
-
-                               RelatedGroups: relations,
-
-                               Cached: time.Now(),
-                       }
+                       g = parseGroupReply(reply)
+               } else if reply.Code() == 350 {
+                       cache.MarkInvalid(keys...)
+               }
+               if g != nil {
+                       cache.Set(&gidCache{GID: g.GID}, "gid", "by-name", g.Name)
+                       cache.Set(&gidCache{GID: g.GID}, "gid", "by-shortname", g.ShortName)
+                       cache.Set(g, keys...)
                }
-               cache.Set(g, keys...)
+
                intentMap.Notify(g, keys...)
        }()
        return ch
 }
+
+func (adb *AniDB) GroupByName(gname string) <-chan *Group {
+       keys := []cacheKey{"gid", "by-name", gname}
+       altKeys := []cacheKey{"gid", "by-shortname", gname}
+       ch := make(chan *Group, 1)
+
+       ic := make(chan Cacheable, 1)
+       go func() {
+               gid := (<-ic).(GID)
+               if gid > 0 {
+                       ch <- <-adb.GroupByID(gid)
+               }
+               close(ch)
+       }()
+       if intentMap.Intent(ic, keys...) {
+               return ch
+       }
+
+       if !cache.CheckValid(keys...) {
+               intentMap.Notify(GID(0), keys...)
+               return ch
+       }
+
+       var gc gidCache
+       if cache.Get(&gc, keys...) == nil {
+               intentMap.Notify(gc.GID, keys...)
+               return ch
+       }
+
+       if cache.Get(&gc, altKeys...) == nil {
+               intentMap.Notify(gc.GID, keys...)
+               return ch
+       }
+
+       go func() {
+               reply := <-adb.udp.SendRecv("GROUP",
+                       paramMap{"gname": gname})
+
+               var g *Group
+               if reply.Error() == nil {
+                       g = parseGroupReply(reply)
+               } else if reply.Code() == 350 {
+                       cache.MarkInvalid(keys...)
+               }
+
+               gid := GID(0)
+               if g != nil {
+                       gid = g.GID
+
+                       cache.Set(&gidCache{GID: gid}, keys...)
+                       cache.Set(&gidCache{GID: gid}, altKeys...)
+                       cache.Set(g, "gid", gid)
+               }
+               intentMap.Notify(gid, keys...)
+       }()
+       return ch
+}
+
+func parseGroupReply(reply udpapi.APIReply) *Group {
+       parts := strings.Split(reply.Lines()[1], "|")
+       ints := make([]int64, len(parts))
+       for i := range parts {
+               ints[i], _ = strconv.ParseInt(parts[i], 10, 32)
+       }
+
+       irc := ""
+       if parts[7] != "" {
+               irc = "irc://" + parts[8] + "/" + parts[7][1:]
+       }
+
+       pic := ""
+       if parts[10] != "" {
+               pic = httpapi.AniDBImageBaseURL + parts[10]
+       }
+
+       rellist := strings.Split(parts[16], "'")
+       relations := make(map[GID]GroupRelationType, len(rellist))
+       for _, rel := range rellist {
+               r := strings.Split(rel, ",")
+               if len(r) < 2 {
+                       continue
+               }
+               gid, _ := strconv.ParseInt(r[0], 10, 32)
+               typ, _ := strconv.ParseInt(r[1], 10, 32)
+
+               relations[GID(gid)] = GroupRelationType(typ)
+       }
+
+       ft := time.Unix(ints[11], 0)
+       if ints[11] == 0 {
+               ft = time.Time{}
+       }
+       dt := time.Unix(ints[12], 0)
+       if ints[12] == 0 {
+               dt = time.Time{}
+       }
+       lr := time.Unix(ints[14], 0)
+       if ints[14] == 0 {
+               lr = time.Time{}
+       }
+       la := time.Unix(ints[15], 0)
+       if ints[15] == 0 {
+               la = time.Time{}
+       }
+
+       return &Group{
+               GID: GID(ints[0]),
+
+               Name:      parts[5],
+               ShortName: parts[6],
+
+               IRC:     irc,
+               URL:     parts[9],
+               Picture: pic,
+
+               Founded:   ft,
+               Disbanded: dt,
+               // ignore ints[13]
+               LastRelease:  lr,
+               LastActivity: la,
+
+               Rating: Rating{
+                       Rating:    float32(ints[1]) / 100,
+                       VoteCount: int(ints[2]),
+               },
+               AnimeCount: int(ints[3]),
+               FileCount:  int(ints[4]),
+
+               RelatedGroups: relations,
+
+               Cached: time.Now(),
+       }
+}