53 lines
1.2 KiB
Go
53 lines
1.2 KiB
Go
|
package util
|
||
|
|
||
|
import (
|
||
|
"sync"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// LookupCache is a single-value cache with a time-to-live (TTL). The cache has a lookup function
|
||
|
// to retrieve the value and stores it until TTL is reached.
|
||
|
//
|
||
|
// Example:
|
||
|
//
|
||
|
// lookup := func() (string, error) {
|
||
|
// r, _ := http.Get("...")
|
||
|
// s, _ := io.ReadAll(r.Body)
|
||
|
// return string(s), nil
|
||
|
// }
|
||
|
// c := NewLookupCache[string](lookup, time.Hour)
|
||
|
// fmt.Println(c.Get()) // Fetches the string via HTTP
|
||
|
// fmt.Println(c.Get()) // Uses cached value
|
||
|
type LookupCache[T any] struct {
|
||
|
value *T
|
||
|
lookup func() (T, error)
|
||
|
ttl time.Duration
|
||
|
updated time.Time
|
||
|
mu sync.Mutex
|
||
|
}
|
||
|
|
||
|
// NewLookupCache creates a new LookupCache with a given time-to-live (TTL)
|
||
|
func NewLookupCache[T any](lookup func() (T, error), ttl time.Duration) *LookupCache[T] {
|
||
|
return &LookupCache[T]{
|
||
|
value: nil,
|
||
|
lookup: lookup,
|
||
|
ttl: ttl,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Value returns the cached value, or retrieves it via the lookup function
|
||
|
func (c *LookupCache[T]) Value() (T, error) {
|
||
|
c.mu.Lock()
|
||
|
defer c.mu.Unlock()
|
||
|
if c.value == nil || (c.ttl > 0 && time.Since(c.updated) > c.ttl) {
|
||
|
value, err := c.lookup()
|
||
|
if err != nil {
|
||
|
var t T
|
||
|
return t, err
|
||
|
}
|
||
|
c.value = &value
|
||
|
c.updated = time.Now()
|
||
|
}
|
||
|
return *c.value, nil
|
||
|
}
|