ntfy/util/lookup_cache.go

57 lines
1.4 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
}
// LookupFunc is a function that is called by the LookupCache if the underlying
// value is out-of-date. It returns the new value, or an error.
type LookupFunc[T any] func() (T, error)
// NewLookupCache creates a new LookupCache with a given time-to-live (TTL)
func NewLookupCache[T any](lookup LookupFunc[T], 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
}