initial commit, general organization and likely broken atom implementation

This commit is contained in:
Jason Moiron
2013-01-15 17:27:35 -05:00
commit 4e6bcdd4bb
8 changed files with 227 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
Syndication (feed) generator library for golang.
Usage:
```golang
```
+93
View File
@@ -0,0 +1,93 @@
package syndicate
import (
"encoding/xml"
"fmt"
"net/url"
"time"
)
// Generates Atom feed as XML
const ns = "http://www.w3.org/2005/Atom"
type atomSummary struct {
S string `xml:",chardata"`
Type string `xml:"type,attr"`
}
type atomEntry struct {
XMLName xml.Name `xml:"entry"`
Title string `xml:"title"`
Link *atomLink
Updated string `xml:"updated"`
Id string `xml:"id"`
Summary *atomSummary `xml:"summary"`
}
type atomLink struct {
XMLName xml.Name `xml:"link"`
Href string `xml:"href,attr"`
Rel string `xml:"rel,attr"`
}
type atomFeed struct {
XMLName xml.Name `xml:"feed"`
Ns string `xml:"xmlns,attr"`
Title string `xml:"title"`
Link *atomLink
Id string `xml:"id"`
Updated string `xml:"updated"`
Entries []*atomEntry
}
type Atom struct {
*Feed
}
func newAtomEntry(i *Item) *atomEntry {
id := i.Id
// assume the description is html
s := &atomSummary{i.Description, "html"}
// try to get a single timestamp, since we only have one in atom
ts := i.Updated
if ts.IsZero() {
ts = i.Created
}
// <id>tag:blog.kowalczyk.info,2012-09-11:/item/1.html</id>
if len(id) == 0 {
// if there's no id set, try to create one, either from data or just a uuid
if len(i.Link.Href) > 0 && (!i.Created.IsZero() || !i.Updated.IsZero()) {
dateStr := ts.Format("2006-01-02")
host, path := i.Link.Href, "/invalid.html"
if url, err := url.Parse(i.Link.Href); err == nil {
host, path = url.Host, url.Path
}
id = fmt.Sprintf("tag:%s,%s:%s", host, dateStr, path)
} else {
id = "urn:uuid:" + NewUUID().String()
}
}
x := &atomEntry{
Title: i.Title,
Link: &atomLink{Href: i.Link.Href, Rel: i.Link.Rel},
Summary: s,
Id: id,
Updated: i.Updated.Format(time.RFC3339)}
return x
}
func (a *Atom) FeedXml() interface{} {
feed := &atomFeed{
Ns: ns,
Title: a.Title,
Link: &atomLink{Href: a.Link.Href, Rel: a.Link.Rel},
Id: a.Link.Href,
Updated: a.Updated.Format(time.RFC3339)}
for _, e := range a.Items {
feed.Entries = append(feed.Entries, newAtomEntry(e))
}
return feed
}
+5
View File
@@ -0,0 +1,5 @@
/*
Create feed output in RSS or Atom.
*/
package syndicate
+74
View File
@@ -0,0 +1,74 @@
package syndicate
import (
"encoding/xml"
"fmt"
"time"
)
type Link struct {
Href string
Rel string
}
type Author struct {
Name string
Email string
}
type Item struct {
Title string
Link *Link
Author *Author
Description string // used as description in rss, summary in atom
Id string // used as guid in rss, id in atom
Updated time.Time
Created time.Time
}
type Feed struct {
Title string
Link *Link
Author *Author
Created time.Time
Updated time.Time
Description string
Subtitle string
Id string
Items []*Item
}
func (f *Feed) Add(item *Item) {
f.Items = append(f.Items, item)
}
type XmlFeed interface {
FeedXml() interface{}
}
func ToXML(feed XmlFeed) (string, error) {
x := feed.FeedXml()
data, err := xml.MarshalIndent(x, " ", " ")
if err != nil {
return "", err
}
s := xml.Header[:len(xml.Header)-1] + string(data)
return s, nil
}
func (f *Feed) ToAtom() (string, error) {
a := &Atom{f}
return ToXML(a)
}
func (f *Feed) ToRss(version ...float64) (string, error) {
vers := 2.0
if len(version) > 0 {
vers = version[0]
}
/*
r := &RssFeed{f}
return ToXML(r)
*/
return fmt.Sprint(vers), nil
}
+1
View File
@@ -0,0 +1 @@
package syndicate
+1
View File
@@ -0,0 +1 @@
package syndicate
+26
View File
@@ -0,0 +1,26 @@
package syndicate
// relevant bits from https://github.com/abneptis/GoUUID/blob/master/uuid.go
import (
"crypto/rand"
"fmt"
)
type UUID [16]byte
func NewUUID() *UUID {
u := &UUID{}
_, err := rand.Read(u[:16])
if err != nil {
panic(err)
}
u[8] = (u[8] | 0x80) & 0xBf
u[6] = (u[6] | 0x40) & 0x4f
return u
}
func (u *UUID) String() string {
return fmt.Sprintf("%x-%x-%x-%x-%x", u[:4], u[4:6], u[6:8], u[8:10], u[10:])
}
+19
View File
@@ -0,0 +1,19 @@
package syndicate
import (
"testing"
)
func TestUUID(t *testing.T) {
s := NewUUID()
s2 := NewUUID()
if len(s) != 16 {
t.Errorf("Expecting len of 16, got %d\n", len(s))
}
if len(s.String()) != 36 {
t.Errorf("Expecting uuid hex string len of 36, got %d\n", len(s.String()))
}
if s == s2 {
t.Errorf("Expecting different UUIDs to be different, but they are the same.\n")
}
}