From 99d34b89b7ff13d6939e7d0f98271fe0e10929a2 Mon Sep 17 00:00:00 2001
From: man90 <man90@tuta.io>
Date: Tue, 19 May 2026 12:29:32 +0200
Subject: [PATCH] Remove in-memory cache option

---
 cache/cache.go      | 77 +++++----------------------------------------
 cache/cache_test.go | 34 ++++++++++++++------
 go.mod              |  4 +--
 go.sum              |  4 ---
 4 files changed, 33 insertions(+), 86 deletions(-)

diff --git a/cache/cache.go b/cache/cache.go
index 2d5c297..6e922c8 100644
--- a/cache/cache.go
+++ b/cache/cache.go
@@ -6,10 +6,8 @@ import (
 	"strings"
 	"time"
 
-	goCache "github.com/patrickmn/go-cache"
 	"github.com/redis/go-redis/v9"
 	"github.com/spf13/viper"
-	"golang.org/x/exp/maps"
 
 	"bdo-rest-api/models"
 	"bdo-rest-api/utils"
@@ -33,63 +31,6 @@ func joinKeys(keys []string) string {
 	return strings.Join(keys, ",")
 }
 
-type memoryCache[T any] struct {
-	internalCache *goCache.Cache
-	ttl           time.Duration
-}
-
-func newMemoryCache[T any]() *memoryCache[T] {
-	ttl := viper.GetDuration("cachettl")
-
-	return &memoryCache[T]{
-		internalCache: goCache.New(ttl, min(time.Hour, ttl)),
-		ttl:           ttl,
-	}
-}
-
-func (c *memoryCache[T]) AddRecord(keys []string, data T, status int, taskId string) (date, expires string) {
-	entry := CacheEntry[T]{
-		Data:   data,
-		Date:   time.Now(),
-		Status: status,
-	}
-
-	c.internalCache.Add(joinKeys(keys), entry, c.ttl)
-
-	return utils.FormatDateForHeaders(entry.Date), utils.FormatDateForHeaders(entry.Date.Add(c.ttl))
-}
-
-func (c *memoryCache[T]) GetRecord(keys []string) (data T, status int, date, expires string, found bool) {
-	anyEntry, exp, found := c.internalCache.GetWithExpiration(joinKeys(keys))
-
-	if !found {
-		return
-	}
-
-	entry := anyEntry.(CacheEntry[T])
-
-	return entry.Data, entry.Status, utils.FormatDateForHeaders(entry.Date), utils.FormatDateForHeaders(exp), true
-}
-
-func (c *memoryCache[T]) GetItemCount() int {
-	return c.internalCache.ItemCount()
-}
-
-func (c *memoryCache[T]) GetKeys() []string {
-	return maps.Keys(c.internalCache.Items())
-}
-
-func (c *memoryCache[T]) GetValues() []CacheEntry[T] {
-	items := c.internalCache.Items()
-	result := make([]CacheEntry[T], 0, len(items))
-
-	for _, item := range items {
-		result = append(result, item.Object.(CacheEntry[T]))
-	}
-
-	return result
-}
-
 type redisCache[T any] struct {
 	client    *redis.Client
 	ctx       context.Context
@@ -182,15 +123,13 @@ var (
 )
 
 func InitCache() {
-	if redisClient, err := newRedisClient(viper.GetString("redis")); err == nil {
-		GuildProfiles = newRedisCache[models.GuildProfile](redisClient, "gpc")
-		GuildSearch = newRedisCache[[]models.GuildProfile](redisClient, "gsc")
-		Profiles = newRedisCache[models.Profile](redisClient, "pc")
-		ProfileSearch = newRedisCache[[]models.Profile](redisClient, "psc")
-	} else {
-		GuildProfiles = newMemoryCache[models.GuildProfile]()
-		GuildSearch = newMemoryCache[[]models.GuildProfile]()
-		Profiles = newMemoryCache[models.Profile]()
-		ProfileSearch = newMemoryCache[[]models.Profile]()
+	redisClient, err := newRedisClient(viper.GetString("redis"))
+	if err != nil {
+		panic(err)
 	}
+
+	GuildProfiles = newRedisCache[models.GuildProfile](redisClient, "gpc")
+	GuildSearch = newRedisCache[[]models.GuildProfile](redisClient, "gsc")
+	Profiles = newRedisCache[models.Profile](redisClient, "pc")
+	ProfileSearch = newRedisCache[[]models.Profile](redisClient, "psc")
 }
diff --git a/cache/cache_test.go b/cache/cache_test.go
index 93fb995..ea44a91 100644
--- a/cache/cache_test.go
+++ b/cache/cache_test.go
@@ -1,6 +1,7 @@
 package cache
 
 import (
+	"context"
 	"testing"
 	"time"
 
@@ -15,6 +16,19 @@ type testStruct struct {
 func init() {
 	// Ensure TTL is something predictable
 	viper.Set("cachettl", time.Second*10)
+	viper.Set("redis", "redis://localhost:6379/0")
+}
+
+func getTestRedisCache[T any](t *testing.T, namespace string) *redisCache[T] {
+	client, err := newRedisClient(viper.GetString("redis"))
+	if err != nil {
+		t.Skip("Skipping test: Redis client could not be created")
+	}
+	if err := client.Ping(context.Background()).Err(); err != nil {
+		t.Skip("Skipping test: Redis server not reachable")
+	}
+	client.FlushDB(context.Background())
+	return newRedisCache[T](client, namespace)
 }
 
 func TestJoinKeys(t *testing.T) {
@@ -26,8 +40,8 @@ func TestJoinKeys(t *testing.T) {
 	}
 }
 
-func TestMemoryCacheAddAndGetRecord(t *testing.T) {
-	c := newMemoryCache[testStruct]()
+func TestRedisCacheAddAndGetRecord(t *testing.T) {
+	c := getTestRedisCache[testStruct](t, "test_add_get")
 
 	data := testStruct{Value: "hello"}
 	keys := []string{"key1", "key2"}
@@ -49,8 +63,8 @@ func TestMemoryCacheAddAndGetRecord(t *testing.T) {
 	}
 }
 
-func TestMemoryCacheMissingRecord(t *testing.T) {
-	c := newMemoryCache[testStruct]()
+func TestRedisCacheMissingRecord(t *testing.T) {
+	c := getTestRedisCache[testStruct](t, "test_missing")
 
 	_, _, _, _, found := c.GetRecord([]string{"does", "not", "exist"})
 	if found {
@@ -58,8 +72,8 @@ func TestMemoryCacheMissingRecord(t *testing.T) {
 	}
 }
 
-func TestMemoryCacheItemCount(t *testing.T) {
-	c := newMemoryCache[testStruct]()
+func TestRedisCacheItemCount(t *testing.T) {
+	c := getTestRedisCache[testStruct](t, "test_count")
 
 	if c.GetItemCount() != 0 {
 		t.Fatal("Expected empty cache")
@@ -73,8 +87,8 @@ func TestMemoryCacheItemCount(t *testing.T) {
 	}
 }
 
-func TestMemoryCacheGetKeys(t *testing.T) {
-	c := newMemoryCache[testStruct]()
+func TestRedisCacheGetKeys(t *testing.T) {
+	c := getTestRedisCache[testStruct](t, "test_keys")
 
 	c.AddRecord([]string{"k1"}, testStruct{"v1"}, 200, "task1")
 	c.AddRecord([]string{"k2"}, testStruct{"v2"}, 200, "task2")
@@ -101,8 +115,8 @@ func TestMemoryCacheGetKeys(t *testing.T) {
 	}
 }
 
-func TestMemoryCacheGetValues(t *testing.T) {
-	c := newMemoryCache[testStruct]()
+func TestRedisCacheGetValues(t *testing.T) {
+	c := getTestRedisCache[testStruct](t, "test_values")
 
 	c.AddRecord([]string{"a"}, testStruct{"aaa"}, 200, "task1")
 	c.AddRecord([]string{"b"}, testStruct{"bbb"}, 200, "task2")
diff --git a/go.mod b/go.mod
index ec3c14d..4fc917b 100644
--- a/go.mod
+++ b/go.mod
@@ -4,13 +4,12 @@ go 1.24.0
 
 require (
 	github.com/gocolly/colly/v2 v2.3.0
-	github.com/patrickmn/go-cache v2.1.0+incompatible
+	github.com/nzrsky/useragent-generator v1.0.0
 	github.com/redis/go-redis/v9 v9.17.2
 	github.com/sa-/slicefunk v0.1.4
 	github.com/spf13/viper v1.21.0
 	github.com/ulule/limiter/v3 v3.11.2
 	go.mongodb.org/mongo-driver/v2 v2.4.1
-	golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93
 )
 
 require (
@@ -34,7 +33,6 @@ require (
 	github.com/kennygrant/sanitize v1.2.4 // indirect
 	github.com/klauspost/compress v1.18.2 // indirect
 	github.com/nlnwa/whatwg-url v0.6.2 // indirect
-	github.com/nzrsky/useragent-generator v1.0.0 // indirect
 	github.com/pelletier/go-toml/v2 v2.2.4 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/sagikazarmark/locafero v0.12.0 // indirect
diff --git a/go.sum b/go.sum
index 76c5205..e3e22f4 100644
--- a/go.sum
+++ b/go.sum
@@ -57,8 +57,6 @@ github.com/nlnwa/whatwg-url v0.6.2 h1:jU61lU2ig4LANydbEJmA2nPrtCGiKdtgT0rmMd2VZ/
 github.com/nlnwa/whatwg-url v0.6.2/go.mod h1:x0FPXJzzOEieQtsBT/AKvbiBbQ46YlL6Xa7m02M1ECk=
 github.com/nzrsky/useragent-generator v1.0.0 h1:oEPrFZOmE5HxWXF4rA59asaaBiVtHu8GF0Vbm6tPHE0=
 github.com/nzrsky/useragent-generator v1.0.0/go.mod h1:KLwn9uNME0wlJP2KmYP5/EvojJFKbFKHBXSgiGeQoUg=
-github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
-github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
 github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
 github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -115,8 +113,6 @@ golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ss
 golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
 golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
 golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
-golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0=
-golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
