summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/structs.go144
1 files changed, 144 insertions, 0 deletions
diff --git a/core/structs.go b/core/structs.go
new file mode 100644
index 0000000..eec1473
--- /dev/null
+++ b/core/structs.go
@@ -0,0 +1,144 @@
+// Copyright (C) 2021 nytpu
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// For more license details, see LICENSE or <https://www.gnu.org/licenses/agpl-3.0.html>.
+
+// This file incorporates code from makeworlds's amfora:
+// https://github.com/makeworld-the-better-one/amfora/blob/master/subscriptions/structs.go
+// Original source is Copyright 2020 makeworld and is licensed under the
+// terms of the GNU General Public License Version 3.0.
+// https://www.gnu.org/licenses/gpl-3.0-standalone.html
+
+// package core implements the structs and other necessary resources for storing
+// and managing feeds and pages
+package core
+
+import (
+ "net/url"
+ "sync"
+ "time"
+
+ "github.com/mmcdole/gofeed"
+)
+
+// jsonData is used for both reading from json and for storing the global feeds
+// map. contains read mutexes so concurrency can be used.
+type jsonData struct {
+ Feeds map[url.URL]*Feed `json:"feeds,omitempty"`
+ Pages map[url.URL]*Page `json:"pages,omitempty"`
+
+ feedsMu *sync.RWMutex
+ pagesMu *sync.RWMutex
+}
+
+// Feed holds all the necessary fields when storing a feed
+type Feed struct {
+ Title string `json:"title,omitempty"`
+ Link *url.URL `json:"link,omitempty"` // link to the human-readable page for the feed. same as FeedLink for gemini feeds.
+ FeedLink *url.URL `json:"feedlink,omitempty"` // link to the feed itself. if empty, use Link instead.
+ Updated time.Time `json:"updated,omitempty"`
+ Items []*Item `json:"items,omitempty"`
+}
+
+// Item is a single item from a subscripton
+type Item struct {
+ Title string `json:"title,omitempty"` // if empty, use Link as title
+ Content string `json:"content,omitempty"`
+ Link *url.URL `json:"link,omitempty"`
+ Published time.Time `json:"updated,omitempty"`
+}
+
+// Page holds all the necessary fields when storing a page being watched for
+// changes.
+type Page struct {
+ Title string `json:"title,omitempty"`
+ Link *url.URL `json:"link,omitempty"`
+ Updated time.Time `json:"updated,omitempty"`
+ Hash string `json:"hash,omitempty"`
+}
+
+// gofeedConvert converts a gofeed.Feed into a Feed struct
+func GofeedConvert(f *gofeed.Feed, title string) (*Feed, error) {
+ new := &Feed{}
+
+ if title != "" {
+ new.Title = title
+ } else {
+ new.Title = f.Title
+ }
+ new.Updated = *f.UpdatedParsed
+ var err error
+ new.Link, err = url.ParseRequestURI(f.Link)
+ if err != nil {
+ return nil, err
+ }
+ new.FeedLink, err = url.ParseRequestURI(f.FeedLink)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, v := range f.Items {
+ item := &Item{}
+ item.Title = v.Title
+ item.Content = v.Content
+ item.Published = *v.PublishedParsed
+ item.Link, err = url.ParseRequestURI(f.FeedLink)
+ if err != nil {
+ return nil, err
+ }
+
+ new.Items = append(new.Items, item)
+ }
+
+ return new, nil
+}
+
+// Lock locks both feed and page mutexes.
+func (j *jsonData) Lock() {
+ j.feedsMu.Lock()
+ j.pagesMu.Lock()
+}
+
+// Unlock unlocks both feed and page mutexes.
+func (j *jsonData) Unlock() {
+ j.feedsMu.Unlock()
+ j.pagesMu.Unlock()
+}
+
+// RLock read-locks both feed and page mutexes.
+func (j *jsonData) RLock() {
+ j.feedsMu.RLock()
+ j.pagesMu.RLock()
+}
+
+// RUnlock read-unlocks both feed and page mutexes.
+func (j *jsonData) RUnlock() {
+ j.feedsMu.RUnlock()
+ j.pagesMu.RUnlock()
+}
+
+// PageEntry is a single item on a subscriptions page. It is used for both feeds
+// and pages.
+type PageEntry struct {
+ Prefix string // whatever goes before the post title to identify the feed.
+ Title string // article/entry title
+ URL string
+ Published time.Time
+}
+
+// PageEntries is reverse chronological list of entries used when generating subs.
+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]
+}