2020-11-28 01:01:29 +03:00
|
|
|
package subscriptions
|
2020-08-17 00:42:45 +03:00
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/mmcdole/gofeed"
|
|
|
|
)
|
|
|
|
|
|
|
|
/*
|
2020-11-23 04:04:09 +03:00
|
|
|
Example stored JSON.
|
2020-11-17 19:26:49 +03:00
|
|
|
|
2020-08-17 00:42:45 +03:00
|
|
|
{
|
|
|
|
"feeds": {
|
|
|
|
"url1": <gofeed.Feed>,
|
|
|
|
"url2": <gofeed.Feed>,
|
|
|
|
},
|
|
|
|
"pages": {
|
|
|
|
"url1": {
|
|
|
|
"hash": <hash>,
|
2020-08-17 20:31:45 +03:00
|
|
|
"changed": <time>
|
2020-08-17 00:42:45 +03:00
|
|
|
},
|
|
|
|
"url2": {
|
|
|
|
"hash": <hash>,
|
2020-08-17 20:31:45 +03:00
|
|
|
"changed": <time>
|
2020-08-17 00:42:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
"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 {
|
2020-11-18 04:56:15 +03:00
|
|
|
feedMu *sync.RWMutex
|
|
|
|
pageMu *sync.RWMutex
|
2020-08-17 00:42:45 +03:00
|
|
|
Feeds map[string]*gofeed.Feed `json:"feeds,omitempty"`
|
2020-08-28 19:18:30 +03:00
|
|
|
Pages map[string]*pageJSON `json:"pages,omitempty"`
|
2020-08-17 00:42:45 +03:00
|
|
|
}
|
|
|
|
|
2020-08-17 20:31:45 +03:00
|
|
|
// 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()
|
|
|
|
}
|
|
|
|
|
2020-08-28 19:18:30 +03:00
|
|
|
type pageJSON struct {
|
2020-08-17 00:42:45 +03:00
|
|
|
Hash string `json:"hash"`
|
2020-08-17 20:31:45 +03:00
|
|
|
Changed time.Time `json:"changed"` // When the latest change happened
|
2020-08-17 00:42:45 +03:00
|
|
|
}
|
|
|
|
|
2020-11-18 04:56:15 +03:00
|
|
|
// Global instance of jsonData - loaded from JSON and used
|
|
|
|
var data = jsonData{
|
|
|
|
feedMu: &sync.RWMutex{},
|
|
|
|
pageMu: &sync.RWMutex{},
|
2020-12-06 04:35:15 +03:00
|
|
|
// Maps are created in Init()
|
2020-11-18 04:56:15 +03:00
|
|
|
}
|
2020-08-17 00:42:45 +03:00
|
|
|
|
2020-11-28 01:01:29 +03:00
|
|
|
// PageEntry is a single item on a subscriptions page.
|
|
|
|
// It is used for both feeds and pages.
|
2020-08-17 00:42:45 +03:00
|
|
|
type PageEntry struct {
|
2020-11-19 20:50:49 +03:00
|
|
|
Prefix string // Feed/log title, author, etc - something before the post title
|
2020-08-17 00:42:45 +03:00
|
|
|
Title string
|
|
|
|
URL string
|
|
|
|
Published time.Time
|
|
|
|
}
|
|
|
|
|
2020-11-28 01:01:29 +03:00
|
|
|
// 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.
|
2020-08-17 00:42:45 +03:00
|
|
|
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 {
|
2020-08-29 02:33:37 +03:00
|
|
|
return e.Entries[i].Published.After(e.Entries[j].Published)
|
2020-08-17 00:42:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (e *PageEntries) Swap(i, j int) {
|
|
|
|
e.Entries[i], e.Entries[j] = e.Entries[j], e.Entries[i]
|
|
|
|
}
|