From 96725ec63e12e76d6d93345d35d42b141180f4e1 Mon Sep 17 00:00:00 2001 From: René 'Necoro' Neumann Date: Sat, 25 Apr 2020 17:20:19 +0200 Subject: Split cache file --- internal/feed/cache.go | 131 ++++------------------------------------------ internal/feed/cache_v1.go | 116 ++++++++++++++++++++++++++++++++++++++++ internal/feed/feed.go | 5 ++ 3 files changed, 131 insertions(+), 121 deletions(-) create mode 100644 internal/feed/cache_v1.go (limited to 'internal') diff --git a/internal/feed/cache.go b/internal/feed/cache.go index 411ed47..4a0bfe7 100644 --- a/internal/feed/cache.go +++ b/internal/feed/cache.go @@ -2,151 +2,40 @@ package feed import ( "bufio" - "crypto/sha256" "encoding/gob" "errors" "fmt" "os" - "time" "github.com/Necoro/feed2imap-go/pkg/log" ) +type Version byte + const ( - currentVersion byte = 1 - startFeedId uint64 = 1 + currentVersion Version = 1 ) type Cache interface { findItem(*Feed) CachedFeed - Version() byte + Version() Version transformToCurrent() (Cache, error) } -type feedId uint64 - -type feedDescriptor struct { - Name string - Url string -} - type CachedFeed interface { Checked(withFailure bool) Failures() uint } -type cachedFeed struct { - LastCheck time.Time - NumFailures uint // can't be named `Failures` b/c it'll collide with the interface - Items []cachedItem -} - -func (cf *cachedFeed) Checked(withFailure bool) { - cf.LastCheck = time.Now() - if withFailure { - cf.NumFailures++ - } else { - cf.NumFailures = 0 - } -} - -func (cf *cachedFeed) Failures() uint { - return cf.NumFailures -} - -type itemHash [sha256.Size]byte - -type cachedItem struct { - Uid string - Title string - Link string - Date time.Time - Updated time.Time - Creator string - Hash itemHash -} - -type v1Cache struct { - version byte - Ids map[feedDescriptor]feedId - NextId uint64 - Feeds map[feedId]*cachedFeed -} - -func (cache *v1Cache) Version() byte { - return cache.version -} - -func newCache() Cache { - cache := v1Cache{ - Ids: map[feedDescriptor]feedId{}, - Feeds: map[feedId]*cachedFeed{}, - NextId: startFeedId, - } - cache.version = currentVersion - return &cache -} - -func cacheForVersion(version byte) (Cache, error) { +func cacheForVersion(version Version) (Cache, error) { switch version { - case 1: - return newCache(), nil + case v1Version: + return newV1Cache(), nil default: return nil, fmt.Errorf("unknown cache version '%d'", version) } } -func (cache *v1Cache) transformToCurrent() (Cache, error) { - return cache, nil -} - -func (cache *v1Cache) getItem(id feedId) CachedFeed { - feed, ok := cache.Feeds[id] - if !ok { - feed = &cachedFeed{} - cache.Feeds[id] = feed - } - return feed -} - -func (cache *v1Cache) findItem(feed *Feed) CachedFeed { - if feed.cached != nil { - return feed.cached.(*cachedFeed) - } - - fDescr := feed.descriptor() - id, ok := cache.Ids[fDescr] - if !ok { - var otherId feedDescriptor - changed := false - for otherId, id = range cache.Ids { - if otherId.Name == fDescr.Name { - log.Warnf("Feed %s seems to have changed URLs: newCache '%s', old '%s'. Updating.", - fDescr.Name, fDescr.Url, otherId.Url) - changed = true - break - } else if otherId.Url == fDescr.Url { - log.Warnf("Feed with URL '%s' seems to have changed its name: newCache '%s', old '%s'. Updating", - fDescr.Url, fDescr.Name, otherId.Name) - changed = true - break - } - } - if changed { - delete(cache.Ids, otherId) - } else { - id = feedId(cache.NextId) - cache.NextId++ - } - - cache.Ids[fDescr] = id - } - - item := cache.getItem(id) - feed.cached = item - return item -} - func storeCache(cache Cache, fileName string) error { if cache == nil { return fmt.Errorf("trying to store nil cache") @@ -162,7 +51,7 @@ func storeCache(cache Cache, fileName string) error { defer f.Close() writer := bufio.NewWriter(f) - if err = writer.WriteByte(currentVersion); err != nil { + if err = writer.WriteByte(byte(currentVersion)); err != nil { return fmt.Errorf("writing to '%s': %w", fileName, err) } @@ -182,7 +71,7 @@ func loadCache(fileName string) (Cache, error) { if err != nil { if errors.Is(err, os.ErrNotExist) { // no cache there yet -- make new - return newCache(), nil + return cacheForVersion(currentVersion) } return nil, fmt.Errorf("opening cache at '%s': %w", fileName, err) } @@ -196,7 +85,7 @@ func loadCache(fileName string) (Cache, error) { return nil, fmt.Errorf("reading from '%s': %w", fileName, err) } - cache, err := cacheForVersion(version) + cache, err := cacheForVersion(Version(version)) if err != nil { return nil, err } diff --git a/internal/feed/cache_v1.go b/internal/feed/cache_v1.go new file mode 100644 index 0000000..3d46084 --- /dev/null +++ b/internal/feed/cache_v1.go @@ -0,0 +1,116 @@ +package feed + +import ( + "crypto/sha256" + "time" + + "github.com/Necoro/feed2imap-go/pkg/log" +) + +const ( + v1Version Version = 1 + startFeedId uint64 = 1 +) + +type feedId uint64 + +type v1Cache struct { + Ids map[feedDescriptor]feedId + NextId uint64 + Feeds map[feedId]*cachedFeed +} + +type cachedFeed struct { + LastCheck time.Time + NumFailures uint // can't be named `Failures` b/c it'll collide with the interface + Items []cachedItem +} + +type itemHash [sha256.Size]byte + +type cachedItem struct { + Uid string + Title string + Link string + Date time.Time + Updated time.Time + Creator string + Hash itemHash +} + +func (cf *cachedFeed) Checked(withFailure bool) { + cf.LastCheck = time.Now() + if withFailure { + cf.NumFailures++ + } else { + cf.NumFailures = 0 + } +} + +func (cf *cachedFeed) Failures() uint { + return cf.NumFailures +} + +func (cache *v1Cache) Version() Version { + return v1Version +} + +func newV1Cache() *v1Cache { + cache := v1Cache{ + Ids: map[feedDescriptor]feedId{}, + Feeds: map[feedId]*cachedFeed{}, + NextId: startFeedId, + } + return &cache +} + +func (cache *v1Cache) transformToCurrent() (Cache, error) { + return cache, nil +} + +func (cache *v1Cache) getItem(id feedId) CachedFeed { + feed, ok := cache.Feeds[id] + if !ok { + feed = &cachedFeed{} + cache.Feeds[id] = feed + } + return feed +} + +func (cache *v1Cache) findItem(feed *Feed) CachedFeed { + if feed.cached != nil { + return feed.cached.(*cachedFeed) + } + + fDescr := feed.descriptor() + id, ok := cache.Ids[fDescr] + if !ok { + var otherId feedDescriptor + changed := false + for otherId, id = range cache.Ids { + if otherId.Name == fDescr.Name { + log.Warnf("Feed %s seems to have changed URLs: newCache '%s', old '%s'. Updating.", + fDescr.Name, fDescr.Url, otherId.Url) + changed = true + break + } else if otherId.Url == fDescr.Url { + log.Warnf("Feed with URL '%s' seems to have changed its name: newCache '%s', old '%s'. Updating", + fDescr.Url, fDescr.Name, otherId.Name) + changed = true + break + } + } + if changed { + delete(cache.Ids, otherId) + } else { + id = feedId(cache.NextId) + cache.NextId++ + } + + cache.Ids[fDescr] = id + } + + item := cache.getItem(id) + feed.cached = item + return item +} diff --git a/internal/feed/feed.go b/internal/feed/feed.go index c7fdd5f..686de4c 100644 --- a/internal/feed/feed.go +++ b/internal/feed/feed.go @@ -16,6 +16,11 @@ type Feed struct { cached CachedFeed } +type feedDescriptor struct { + Name string + Url string +} + type feeditem struct { *gofeed.Feed *gofeed.Item -- cgit v1.2.3-54-g00ecf