From 9f794c86224e61407715d17c5b1459032c077825 Mon Sep 17 00:00:00 2001 From: nobe4 Date: Sat, 28 Sep 2024 18:53:33 +0200 Subject: [PATCH] feat(cache): store RefreshedAt information in the Wrapper (#178) --- internal/cache/cache.go | 51 ++++++++++++++++++------------------- internal/manager/manager.go | 3 +++ 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/internal/cache/cache.go b/internal/cache/cache.go index c800195..d885883 100644 --- a/internal/cache/cache.go +++ b/internal/cache/cache.go @@ -14,15 +14,18 @@ type ExpiringReadWriter interface { Write(any) error Expired() bool RefreshedAt() time.Time + SetRefreshedAt(time.Time) } type FileCache struct { path string ttl time.Duration + wrap *CacheWrap } type CacheWrap struct { - Data any `json:"data"` + Data any `json:"data"` + RefreshedAt time.Time `json:"refreshed_at"` } func NewFileCache(ttlInHours int, path string) *FileCache { @@ -43,36 +46,49 @@ func (c *FileCache) Read(out any) error { return err } - wrap := &CacheWrap{Data: out} + c.wrap = &CacheWrap{Data: out} - err = json.Unmarshal(content, wrap) + err = json.Unmarshal(content, c.wrap) if err == nil { return nil } var jsonErr *json.UnmarshalTypeError if errors.As(err, &jsonErr) { - return c.deprecatedRead(content, out) + return c.deprecatedRead(content) } return err } -func (c *FileCache) deprecatedRead(content []byte, out any) error { +func (c *FileCache) RefreshedAt() time.Time { + return c.wrap.RefreshedAt +} + +func (c *FileCache) SetRefreshedAt(t time.Time) { + c.wrap.RefreshedAt = t +} + +func (c *FileCache) Expired() bool { + return time.Now().After(c.RefreshedAt().Add(c.ttl)) +} + +func (c *FileCache) deprecatedRead(content []byte) error { slog.Warn("Cache is in an deprecated format. Attempting to read from the old format.") - if err := json.Unmarshal(content, out); err != nil { + if err := json.Unmarshal(content, c.wrap.Data); err != nil { return err } - // TODO: here infer the other information in the CacheWrap + c.wrap.RefreshedAt = time.Unix(0, 0) + return nil } func (c *FileCache) Write(in any) error { - wrap := &CacheWrap{Data: in} + c.wrap.Data = in - marshalled, err := json.Marshal(wrap) + marshalled, err := json.Marshal(c.wrap) if err != nil { return err } @@ -83,20 +99,3 @@ func (c *FileCache) Write(in any) error { return os.WriteFile(c.path, marshalled, 0644) } - -func (c *FileCache) Expired() bool { - return time.Now().After(c.RefreshedAt().Add(c.ttl)) -} - -func (c *FileCache) RefreshedAt() time.Time { - info, err := os.Stat(c.path) - - if err != nil { - // Returning a valid time.Time that's the 0 epoch allows to not return - // an error but still process the Expiration date logic correctly. - slog.Warn("Could not read file info", "file", c.path, "error", err) - return time.Unix(0, 0) - } - - return info.ModTime() -} diff --git a/internal/manager/manager.go b/internal/manager/manager.go index cf60647..8d1dd21 100644 --- a/internal/manager/manager.go +++ b/internal/manager/manager.go @@ -4,6 +4,7 @@ import ( "fmt" "log/slog" "os" + "time" "github.com/nobe4/gh-not/internal/actions" "github.com/nobe4/gh-not/internal/api" @@ -74,6 +75,8 @@ func (m *Manager) refreshNotifications() error { m.Notifications = m.Notifications.Uniq() m.Notifications, err = m.Enrich(m.Notifications) + m.Cache.SetRefreshedAt(time.Now()) + return err }