From 44f4c2df6a56746942051741c82bbd6b03228376 Mon Sep 17 00:00:00 2001 From: highperfocused Date: Sun, 23 Feb 2025 22:41:21 +0100 Subject: [PATCH] implement caching (#1) Co-authored-by: mr0x50 <24775431+mroxso@users.noreply.github.com> Reviewed-on: https://git.highperfocused.tech/highperfocused/lumina-relay/pulls/1 --- relay/cache/cache.go | 64 +++++++++++++++++++++++++++++++++++++++++ relay/trending/kinds.go | 12 ++++++++ 2 files changed, 76 insertions(+) create mode 100644 relay/cache/cache.go diff --git a/relay/cache/cache.go b/relay/cache/cache.go new file mode 100644 index 0000000..90bc653 --- /dev/null +++ b/relay/cache/cache.go @@ -0,0 +1,64 @@ +package cache + +import ( + "sync" + "time" +) + +type item struct { + value interface{} + expiration int64 +} + +type Cache struct { + items map[string]item + mu sync.RWMutex +} + +func New() *Cache { + cache := &Cache{ + items: make(map[string]item), + } + go cache.startCleanup() + return cache +} + +func (c *Cache) Set(key string, value interface{}, duration time.Duration) { + c.mu.Lock() + defer c.mu.Unlock() + + c.items[key] = item{ + value: value, + expiration: time.Now().Add(duration).UnixNano(), + } +} + +func (c *Cache) Get(key string) (interface{}, bool) { + c.mu.RLock() + defer c.mu.RUnlock() + + item, exists := c.items[key] + if !exists { + return nil, false + } + + if time.Now().UnixNano() > item.expiration { + return nil, false + } + + return item.value, true +} + +func (c *Cache) startCleanup() { + ticker := time.NewTicker(time.Minute) + for range ticker.C { + c.mu.Lock() + now := time.Now().UnixNano() + for k, v := range c.items { + if now > v.expiration { + delete(c.items, k) + } + } + c.mu.Unlock() + } +} diff --git a/relay/trending/kinds.go b/relay/trending/kinds.go index dbbefe9..ca394f9 100644 --- a/relay/trending/kinds.go +++ b/relay/trending/kinds.go @@ -4,6 +4,8 @@ import ( "database/sql" "encoding/json" "time" + + "git.highperfocused.tech/highperfocused/lumina-relay/relay/cache" ) type Post struct { @@ -16,8 +18,17 @@ type Post struct { ReactionCount int `json:"reaction_count"` } +var ( + trendingCache = cache.New() + cacheDuration = 5 * time.Minute +) + // GetTrendingKind20 returns the top 20 trending posts of kind 20 from the last 24 hours func GetTrendingKind20(db *sql.DB) ([]Post, error) { + if cached, ok := trendingCache.Get("trending_kind_20"); ok { + return cached.([]Post), nil + } + query := ` WITH reactions AS ( SELECT @@ -65,5 +76,6 @@ func GetTrendingKind20(db *sql.DB) ([]Post, error) { trendingPosts = append(trendingPosts, post) } + trendingCache.Set("trending_kind_20", trendingPosts, cacheDuration) return trendingPosts, nil }