amfora/subscriptions/structs.go
makeworld 1a2fba92c2 Add subscription manager, fix corrupt read/write & short URI panic
More info on corrupt reads and writes:
https://github.com/makeworld-the-better-one/amfora/issues/61#issuecomment-735042805

The panic was occuring due to lines like:

    if u[:6] == "about:"

These would cause panics for URIs that were shorter than 6, like "docs/".
strings.HasPrefix was used instead to fix this.
2020-12-05 20:35:15 -05:00

109 lines
2.2 KiB
Go

package subscriptions
import (
"sync"
"time"
"github.com/mmcdole/gofeed"
)
/*
Example stored JSON.
{
"feeds": {
"url1": <gofeed.Feed>,
"url2": <gofeed.Feed>,
},
"pages": {
"url1": {
"hash": <hash>,
"changed": <time>
},
"url2": {
"hash": <hash>,
"changed": <time>
}
}
}
"pages" are the pages tracked for changes that aren't feeds.
The hash used is SHA-256.
The time is in RFC 3339 format, preferably in the UTC timezone.
*/
// Decoded JSON
type jsonData struct {
feedMu *sync.RWMutex
pageMu *sync.RWMutex
Feeds map[string]*gofeed.Feed `json:"feeds,omitempty"`
Pages map[string]*pageJSON `json:"pages,omitempty"`
}
// Lock locks both feed and page mutexes.
func (j *jsonData) Lock() {
j.feedMu.Lock()
j.pageMu.Lock()
}
// Unlock unlocks both feed and page mutexes.
func (j *jsonData) Unlock() {
j.feedMu.Unlock()
j.pageMu.Unlock()
}
// RLock read-locks both feed and page mutexes.
func (j *jsonData) RLock() {
j.feedMu.RLock()
j.pageMu.RLock()
}
// RUnlock read-unlocks both feed and page mutexes.
func (j *jsonData) RUnlock() {
j.feedMu.RUnlock()
j.pageMu.RUnlock()
}
type pageJSON struct {
Hash string `json:"hash"`
Changed time.Time `json:"changed"` // When the latest change happened
}
// Global instance of jsonData - loaded from JSON and used
var data = jsonData{
feedMu: &sync.RWMutex{},
pageMu: &sync.RWMutex{},
// Maps are created in Init()
}
// PageEntry is a single item on a subscriptions page.
// It is used for both feeds and pages.
type PageEntry struct {
Prefix string // Feed/log title, author, etc - something before the post title
Title string
URL string
Published time.Time
}
// PageEntries is new-to-old list of Entry structs, used to create a
// subscriptions page.
// It should always be assumed to be sorted when used in other packages,
// by post time, from newest to oldest.
type PageEntries struct {
Entries []*PageEntry
}
// Implement sort.Interface
func (e *PageEntries) Len() int {
return len(e.Entries)
}
func (e *PageEntries) Less(i, j int) bool {
return e.Entries[i].Published.After(e.Entries[j].Published)
}
func (e *PageEntries) Swap(i, j int) {
e.Entries[i], e.Entries[j] = e.Entries[j], e.Entries[i]
}