First implementation of channels for safe access

This commit is contained in:
Jason Streifling 2024-03-05 15:00:09 +01:00
parent d1f684d63b
commit a59d3f1128
4 changed files with 233 additions and 108 deletions

104
channel.go Normal file
View File

@ -0,0 +1,104 @@
package rss
import (
"encoding/xml"
"fmt"
"sync"
"time"
)
type Channel struct {
addCategory chan string
addItem chan *Item
XMLName xml.Name `xml:"channel"`
Title string `xml:"title"`
Link string `xml:"link"`
Description string `xml:"description"`
Language string `xml:"language,omitempty"`
Copyright string `xml:"copyright,omitempty"`
ManagingEditor string `xml:"managingEditor,omitempty"`
WebMaster string `xml:"webMaster,omitempty"`
PubDate string `xml:"pubDate,omitempty"`
LastBuildDate string `xml:"lastBuildDate,omitempty"`
Categories []string `xml:"category,omitempty"`
Generator string `xml:"generator,omitempty"`
Docs string `xml:"docs,omitempty"`
Cloud string `xml:"cloud,omitempty"`
Image *Image
Rating string `xml:"rating,omitempty"`
TextInput *TextInput
SkipHours []int `xml:"skipHours,omitempty"`
SkipDays []int `xml:"skipDays,omitempty"`
Items []*Item
Ttl int `xml:"ttl,omitempty"`
wg sync.WaitGroup
}
func (c *Channel) start() {
c.wg.Done()
for {
select {
case category := <-c.addCategory:
c.Categories = append(c.Categories, category)
case item := <-c.addItem:
c.Items = append(c.Items, item)
}
c.LastBuildDate = time.Now().Format(time.RFC1123Z)
}
}
func initChannel() *Channel {
now := time.Now().Format(time.RFC1123Z)
channel := &Channel{
PubDate: now,
LastBuildDate: now,
}
channel.wg.Add(1)
go channel.start()
channel.wg.Wait()
return channel
}
func (c *Channel) check() error {
if len(c.Title) == 0 {
return fmt.Errorf("error: title not set")
}
if len(c.Link) == 0 {
return fmt.Errorf("error: link not set")
}
if len(c.Description) == 0 {
return fmt.Errorf("error: description not set")
}
if err := c.Image.check(); err != nil {
return fmt.Errorf("error checking image: %v", err)
}
if err := c.TextInput.check(); err != nil {
return fmt.Errorf("error checking textInput: %v", err)
}
for _, item := range c.Items {
if err := item.check(); err != nil {
return fmt.Errorf("error checking item: %v", err)
}
}
return nil
}
func NewChannel() *Channel {
return initChannel()
}
func (c *Channel) AddCategory(category string) {
c.addCategory <- category
}
func (c *Channel) AddItem(i *Item) {
c.addItem <- i
}

60
feed.go Normal file
View File

@ -0,0 +1,60 @@
package rss
import (
"encoding/xml"
"fmt"
"sync"
)
type Feed struct {
addChannel chan *Channel
XMLName xml.Name `xml:"rss"`
Version string `xml:"version,attr"`
ContentNamespace string `xml:"xmlns:content,attr"`
Channels []*Channel
wg sync.WaitGroup
}
func (f *Feed) start() {
f.wg.Done()
for channel := range f.addChannel {
f.Channels = append(f.Channels, channel)
}
}
func initFeed() *Feed {
feed := &Feed{
addChannel: make(chan *Channel),
Version: "2.0",
ContentNamespace: "http://purl.org/rss/1.0/modules/content/",
}
feed.wg.Add(1)
go feed.start()
feed.wg.Wait()
return feed
}
func (f *Feed) check() error {
if f.Channels == nil {
return fmt.Errorf("error: feed has no channels")
}
for _, channel := range f.Channels {
if err := channel.check(); err != nil {
return fmt.Errorf("error checking channel: %v", err)
}
}
return nil
}
func NewFeed() *Feed {
return initFeed()
}
func (f *Feed) AddChannel(c *Channel) {
f.addChannel <- c
}

68
item.go Normal file
View File

@ -0,0 +1,68 @@
package rss
import (
"encoding/xml"
"fmt"
"sync"
"time"
)
type Item struct {
addCategory chan string
XMLName xml.Name `xml:"item"`
Title string `xml:"title,omitempty"`
Link string `xml:"link,omitempty"`
Description string `xml:"description,omitempty"`
Author string `xml:"author,omitempty"`
Comments string `xml:"comments,omitempty"`
Enclosure *Enclosure
Guid string `xml:"guid,omitempty"`
PubDate string `xml:"pubDate,omitempty"`
Source *Source
Categories []string `xml:"category,omitempty"`
wg sync.WaitGroup
}
func (i *Item) start() {
i.wg.Done()
for category := range i.addCategory {
i.Categories = append(i.Categories, category)
}
}
func initItem() *Item {
item := &Item{
addCategory: make(chan string),
PubDate: time.Now().Format(time.RFC1123Z),
}
item.wg.Add(1)
go item.start()
item.wg.Wait()
return item
}
func (i *Item) check() error {
if len(i.Title) == 0 && len(i.Description) == 0 {
return fmt.Errorf("error: neither title nor description set")
}
if err := i.Enclosure.check(); err != nil {
return fmt.Errorf("error checking enclosure: %v", err)
}
if err := i.Source.check(); err != nil {
return fmt.Errorf("error checking source: %v", err)
}
return nil
}
func NewItem() *Item {
return initItem()
}
func (i *Item) AddCategory(category string) {
i.addCategory <- category
}

109
rss.go
View File

@ -3,7 +3,6 @@ package rss
import ( import (
"encoding/xml" "encoding/xml"
"fmt" "fmt"
"time"
) )
type Image struct { type Image struct {
@ -26,8 +25,8 @@ type TextInput struct {
type Enclosure struct { type Enclosure struct {
XMLName xml.Name `xml:"enclosure"` XMLName xml.Name `xml:"enclosure"`
Url string `xml:"url,attr"` Url string `xml:"url,attr"`
Lenght int `xml:"lenght,attr"`
Type string `xml:"type,attr"` Type string `xml:"type,attr"`
Lenght int `xml:"lenght,attr"`
} }
type Source struct { type Source struct {
@ -36,51 +35,6 @@ type Source struct {
Value string Value string
} }
type Item struct {
XMLName xml.Name `xml:"item"`
Title string `xml:"title,omitempty"`
Link string `xml:"link,omitempty"`
Description string `xml:"description,omitempty"`
Author string `xml:"author,omitempty"`
Categories []string `xml:"category,omitempty"`
Comments string `xml:"comments,omitempty"`
Enclosure *Enclosure
Guid string `xml:"guid,omitempty"`
PubDate time.Time `xml:"pubDate,omitempty"`
Source *Source
}
type Channel struct {
XMLName xml.Name `xml:"channel"`
Title string `xml:"title"`
Link string `xml:"link"`
Description string `xml:"description"`
Language string `xml:"language,omitempty"`
Copyright string `xml:"copyright,omitempty"`
ManagingEditor string `xml:"managingEditor,omitempty"`
WebMaster string `xml:"webMaster,omitempty"`
PubDate time.Time `xml:"pubDate,omitempty"`
LastBuildDate time.Time `xml:"lastBuildDate,omitempty"`
Categories []string `xml:"category,omitempty"`
Generator string `xml:"generator,omitempty"`
Docs string `xml:"docs,omitempty"`
Cloud string `xml:"cloud,omitempty"`
Ttl int `xml:"ttl,omitempty"`
Image *Image
Rating string `xml:"rating,omitempty"`
TextInput *TextInput
SkipHours []int `xml:"skipHours,omitempty"`
SkipDays []int `xml:"skipDays,omitempty"`
Items []*Item
}
type Feed struct {
XMLName xml.Name `xml:"rss"`
Version string `xml:"version,attr"`
ContentNamespace string `xml:"xmlns:content,attr"`
Channels []*Channel
}
func (i *Image) check() error { func (i *Image) check() error {
if len(i.Url) == 0 { if len(i.Url) == 0 {
return fmt.Errorf("error: url not set") return fmt.Errorf("error: url not set")
@ -137,67 +91,6 @@ func (s *Source) check() error {
return nil return nil
} }
func (i *Item) check() error {
if len(i.Title) == 0 && len(i.Description) == 0 {
return fmt.Errorf("error: neither title nor description set")
}
if err := i.Enclosure.check(); err != nil {
return fmt.Errorf("error checking enclosure: %v", err)
}
if err := i.Source.check(); err != nil {
return fmt.Errorf("error checking source: %v", err)
}
return nil
}
func (c *Channel) check() error {
if len(c.Title) == 0 {
return fmt.Errorf("error: title not set")
}
if len(c.Link) == 0 {
return fmt.Errorf("error: link not set")
}
if len(c.Description) == 0 {
return fmt.Errorf("error: description not set")
}
if err := c.Image.check(); err != nil {
return fmt.Errorf("error checking image: %v", err)
}
if err := c.TextInput.check(); err != nil {
return fmt.Errorf("error checking textInput: %v", err)
}
for _, item := range c.Items {
if err := item.check(); err != nil {
return fmt.Errorf("error checking item: %v", err)
}
}
return nil
}
func (f *Feed) check() error {
f = &Feed{
Version: "2.0",
ContentNamespace: "http://purl.org/rss/1.0/modules/content/",
}
if f.Channels == nil {
return fmt.Errorf("error: feed has no channels")
}
for _, channel := range f.Channels {
if err := channel.check(); err != nil {
return fmt.Errorf("error checking channel: %v", err)
}
}
return nil
}
func (f *Feed) ToXML() (string, error) { func (f *Feed) ToXML() (string, error) {
if err := f.check(); err != nil { if err := f.check(); err != nil {
return "", fmt.Errorf("error checking RSS feed: %v", err) return "", fmt.Errorf("error checking RSS feed: %v", err)