Made Feed.CanUpdate() public. This returns true if all cache timeout values have expired and a fresh remote update can be performed. Fixed bug where repeated calls to feed.Fetch() creates duplicate Channels instead of generating a fresh list. Did some minor code householding to replace manual slice appends with the builtin append() function.

This commit is contained in:
jim teeuwen 2010-12-17 21:57:48 +01:00
parent 24864b01f1
commit eb15b6a3ef
6 changed files with 29 additions and 81 deletions

View File

@ -29,16 +29,14 @@ func (this *Feed) readAtom(doc *xmlx.Document) (err os.Error) {
ch.SubTitle.Text = tn.Value ch.SubTitle.Text = tn.Value
} }
tn = node.SelectNode(ns, "generator") if tn = node.SelectNode(ns, "generator"); tn != nil {
if tn != nil {
ch.Generator = Generator{} ch.Generator = Generator{}
ch.Generator.Uri = tn.GetAttr("", "uri") ch.Generator.Uri = tn.GetAttr("", "uri")
ch.Generator.Version = tn.GetAttr("", "version") ch.Generator.Version = tn.GetAttr("", "version")
ch.Generator.Text = tn.Value ch.Generator.Text = tn.Value
} }
tn = node.SelectNode(ns, "author") if tn = node.SelectNode(ns, "author"); tn != nil {
if tn != nil {
ch.Author = Author{} ch.Author = Author{}
ch.Author.Name = tn.GetValue("", "name") ch.Author.Name = tn.GetValue("", "name")
ch.Author.Uri = tn.GetValue("", "uri") ch.Author.Uri = tn.GetValue("", "uri")
@ -61,14 +59,14 @@ func (this *Feed) readAtom(doc *xmlx.Document) (err os.Error) {
enc := Enclosure{} enc := Enclosure{}
enc.Url = lv.GetAttr("", "href") enc.Url = lv.GetAttr("", "href")
enc.Type = lv.GetAttr("", "type") enc.Type = lv.GetAttr("", "type")
item.addEnclosure(enc) item.Enclosures = append(item.Enclosures, enc)
} else { } else {
lnk := Link{} lnk := Link{}
lnk.Href = lv.GetAttr("", "href") lnk.Href = lv.GetAttr("", "href")
lnk.Rel = lv.GetAttr("", "rel") lnk.Rel = lv.GetAttr("", "rel")
lnk.Type = lv.GetAttr("", "type") lnk.Type = lv.GetAttr("", "type")
lnk.HrefLang = lv.GetAttr("", "hreflang") lnk.HrefLang = lv.GetAttr("", "hreflang")
item.addLink(lnk) item.Links = append(item.Links, lnk)
} }
} }
@ -78,18 +76,17 @@ func (this *Feed) readAtom(doc *xmlx.Document) (err os.Error) {
item.Contributors[ci] = cv.GetValue("", "name") item.Contributors[ci] = cv.GetValue("", "name")
} }
tn = v.SelectNode(ns, "content") if tn = v.SelectNode(ns, "content"); tn != nil {
if tn != nil {
item.Content = Content{} item.Content = Content{}
item.Content.Type = tn.GetAttr("", "type") item.Content.Type = tn.GetAttr("", "type")
item.Content.Lang = tn.GetValue("xml", "lang") item.Content.Lang = tn.GetValue("xml", "lang")
item.Content.Base = tn.GetValue("xml", "base") item.Content.Base = tn.GetValue("xml", "base")
item.Content.Text = tn.Value item.Content.Text = tn.Value
} }
ch.addItem(item) ch.Items = append(ch.Items, item)
} }
this.addChannel(ch) this.Channels = append(this.Channels, ch)
} }
return return
} }

View File

@ -28,17 +28,3 @@ type Channel struct {
Author Author Author Author
SubTitle SubTitle SubTitle SubTitle
} }
func (this *Channel) addItem(item Item) {
c := make([]Item, len(this.Items)+1)
copy(c, this.Items)
c[len(c)-1] = item
this.Items = c
}
func (this *Channel) addLink(l Link) {
c := make([]Link, len(this.Links)+1)
copy(c, this.Links)
c[len(c)-1] = l
this.Links = c
}

View File

@ -26,13 +26,11 @@
package feeder package feeder
import "os" import "os"
import "http"
import "time" import "time"
import "xmlx" import "xmlx"
import "fmt" import "fmt"
import "strconv" import "strconv"
import "strings" import "strings"
import "io/ioutil"
type Feed struct { type Feed struct {
// Custom cache timeout in minutes. // Custom cache timeout in minutes.
@ -60,46 +58,25 @@ type Feed struct {
} }
func New(cachetimeout int, enforcecachelimit bool) *Feed { func New(cachetimeout int, enforcecachelimit bool) *Feed {
return &Feed{ v := new(Feed)
CacheTimeout: cachetimeout, v.CacheTimeout = cachetimeout
EnforceCacheLimit: enforcecachelimit, v.EnforceCacheLimit = enforcecachelimit
Type: "none", v.Type = "none"
Version: [2]int{0, 0}, return v
Channels: make([]Channel, 0),
}
}
func (this *Feed) addChannel(ch Channel) {
c := make([]Channel, len(this.Channels)+1)
copy(c, this.Channels)
c[len(c)-1] = ch
this.Channels = c
} }
func (this *Feed) Fetch(uri string) (err os.Error) { func (this *Feed) Fetch(uri string) (err os.Error) {
if !this.canUpdate() { if !this.CanUpdate() {
return
}
// Fetch data from remote location.
r, _, err := http.Get(uri)
if err != nil {
return
}
defer r.Body.Close()
var b []byte
if b, err = ioutil.ReadAll(r.Body); err != nil {
return return
} }
this.Url = uri this.Url = uri
this.Channels = nil
// Extract type and version of the feed so we can have the appropriate // Extract type and version of the feed so we can have the appropriate
// function parse it (rss 0.91, rss 0.92, rss 2, atom etc). // function parse it (rss 0.91, rss 0.92, rss 2, atom etc).
doc := xmlx.New() doc := xmlx.New()
if err = doc.LoadString(string(b)); err != nil { if err = doc.LoadUri(uri); err != nil {
return return
} }
this.Type, this.Version = this.GetVersionInfo(doc) this.Type, this.Version = this.GetVersionInfo(doc)
@ -120,7 +97,12 @@ func (this *Feed) Fetch(uri string) (err os.Error) {
return return
} }
func (this *Feed) canUpdate() bool { // This function returns true or false, depending on whether the CacheTimeout
// value has expired or not. Additionally, it will ensure that we adhere to the
// RSS spec's SkipDays and SkipHours values (if Feed.EnforceCacheLimit is set to
// true). If this function returns true, you can be sure that a fresh feed
// update will be performed.
func (this *Feed) CanUpdate() bool {
// Make sure we are not within the specified cache-limit. // Make sure we are not within the specified cache-limit.
// This ensures we don't request data too often. // This ensures we don't request data too often.
utc := time.UTC() utc := time.UTC()

View File

@ -1,6 +1,7 @@
package feeder package feeder
import "testing" import "testing"
import "os"
func TestFeed(t *testing.T) { func TestFeed(t *testing.T) {
urilist := []string{ urilist := []string{

View File

@ -19,17 +19,3 @@ type Item struct {
Contributors []string Contributors []string
Content Content Content Content
} }
func (this *Item) addEnclosure(e Enclosure) {
c := make([]Enclosure, len(this.Enclosures)+1)
copy(c, this.Enclosures)
c[len(c)-1] = e
this.Enclosures = c
}
func (this *Item) addLink(l Link) {
c := make([]Link, len(this.Links)+1)
copy(c, this.Links)
c[len(c)-1] = l
this.Links = c
}

View File

@ -52,8 +52,7 @@ func (this *Feed) readRss2(doc *xmlx.Document) (err os.Error) {
ch.SkipDays[i] = mapDay(v.Value) ch.SkipDays[i] = mapDay(v.Value)
} }
n = node.SelectNode("", "image") if n = node.SelectNode("", "image"); n != nil {
if n != nil {
ch.Image.Title = n.GetValue("", "title") ch.Image.Title = n.GetValue("", "title")
ch.Image.Url = n.GetValue("", "url") ch.Image.Url = n.GetValue("", "url")
ch.Image.Link = n.GetValue("", "link") ch.Image.Link = n.GetValue("", "link")
@ -62,8 +61,7 @@ func (this *Feed) readRss2(doc *xmlx.Document) (err os.Error) {
ch.Image.Description = n.GetValue("", "description") ch.Image.Description = n.GetValue("", "description")
} }
n = node.SelectNode("", "cloud") if n = node.SelectNode("", "cloud"); n != nil {
if n != nil {
ch.Cloud = Cloud{} ch.Cloud = Cloud{}
ch.Cloud.Domain = n.GetAttr("", "domain") ch.Cloud.Domain = n.GetAttr("", "domain")
ch.Cloud.Port = n.GetAttri("", "port") ch.Cloud.Port = n.GetAttri("", "port")
@ -72,8 +70,7 @@ func (this *Feed) readRss2(doc *xmlx.Document) (err os.Error) {
ch.Cloud.Protocol = n.GetAttr("", "protocol") ch.Cloud.Protocol = n.GetAttr("", "protocol")
} }
n = node.SelectNode("", "textInput") if n = node.SelectNode("", "textInput"); n != nil {
if n != nil {
ch.TextInput = Input{} ch.TextInput = Input{}
ch.TextInput.Title = n.GetValue("", "title") ch.TextInput.Title = n.GetValue("", "title")
ch.TextInput.Description = n.GetValue("", "description") ch.TextInput.Description = n.GetValue("", "description")
@ -92,11 +89,10 @@ func (this *Feed) readRss2(doc *xmlx.Document) (err os.Error) {
for _, v := range list { for _, v := range list {
lnk := Link{} lnk := Link{}
lnk.Href = v.Value lnk.Href = v.Value
i.addLink(lnk) i.Links = append(i.Links, lnk)
} }
n = item.SelectNode("", "author") if n = item.SelectNode("", "author"); n != nil {
if n != nil {
i.Author = Author{} i.Author = Author{}
i.Author.Name = n.Value i.Author.Name = n.Value
} }
@ -127,10 +123,10 @@ func (this *Feed) readRss2(doc *xmlx.Document) (err os.Error) {
i.Source.Text = src.Value i.Source.Text = src.Value
} }
ch.addItem(i) ch.Items = append(ch.Items, i)
} }
this.addChannel(ch) this.Channels = append(this.Channels, ch)
} }
return return
} }