2024-09-14 06:49:46 -03:00

68 lines
1.1 KiB
Go

package market
import (
"sync"
"time"
)
type cacheItem[V any] struct {
value V
expiration time.Time
}
type Cache[K comparable, V any] struct {
data map[K]cacheItem[V]
lock sync.RWMutex
ttl time.Duration
fetcher func(key K) (V, error)
}
func NewCache[K comparable, V any](ttl time.Duration, fetchFn func(key K) (V, error)) *Cache[K, V] {
return &Cache[K, V]{
data: make(map[K]cacheItem[V]),
ttl: ttl,
fetcher: fetchFn,
}
}
func (c *Cache[K, V]) Get(key K, fresh bool) (V, error) {
if fresh {
return c.refresh(key, fresh)
}
c.lock.RLock()
item, exists := c.data[key]
c.lock.RUnlock()
if exists && time.Now().Before(item.expiration) {
return item.value, nil
}
return c.refresh(key, fresh)
}
func (c *Cache[K, V]) refresh(key K, fresh bool) (V, error) {
c.lock.Lock()
defer c.lock.Unlock()
if !fresh {
item, exists := c.data[key]
if exists && time.Now().Before(item.expiration) {
return item.value, nil
}
}
value, err := c.fetcher(key)
if err != nil {
var zero V
return zero, err
}
c.data[key] = cacheItem[V]{
value: value,
expiration: time.Now().Add(c.ttl),
}
return value, nil
}