mirror of
https://github.com/fankes/beszel.git
synced 2025-10-19 01:39:34 +08:00
105 lines
2.2 KiB
Go
105 lines
2.2 KiB
Go
package expirymap
|
|
|
|
import (
|
|
"reflect"
|
|
"time"
|
|
|
|
"github.com/pocketbase/pocketbase/tools/store"
|
|
)
|
|
|
|
type val[T any] struct {
|
|
value T
|
|
expires time.Time
|
|
}
|
|
|
|
type ExpiryMap[T any] struct {
|
|
store *store.Store[string, *val[T]]
|
|
cleanupInterval time.Duration
|
|
}
|
|
|
|
// New creates a new expiry map with custom cleanup interval
|
|
func New[T any](cleanupInterval time.Duration) *ExpiryMap[T] {
|
|
m := &ExpiryMap[T]{
|
|
store: store.New(map[string]*val[T]{}),
|
|
cleanupInterval: cleanupInterval,
|
|
}
|
|
m.startCleaner()
|
|
return m
|
|
}
|
|
|
|
// Set stores a value with the given TTL
|
|
func (m *ExpiryMap[T]) Set(key string, value T, ttl time.Duration) {
|
|
m.store.Set(key, &val[T]{
|
|
value: value,
|
|
expires: time.Now().Add(ttl),
|
|
})
|
|
}
|
|
|
|
// GetOk retrieves a value and checks if it exists and hasn't expired
|
|
// Performs lazy cleanup of expired entries on access
|
|
func (m *ExpiryMap[T]) GetOk(key string) (T, bool) {
|
|
value, ok := m.store.GetOk(key)
|
|
if !ok {
|
|
return *new(T), false
|
|
}
|
|
|
|
// Check if expired and perform lazy cleanup
|
|
if value.expires.Before(time.Now()) {
|
|
m.store.Remove(key)
|
|
return *new(T), false
|
|
}
|
|
|
|
return value.value, true
|
|
}
|
|
|
|
// GetByValue retrieves a value by value
|
|
func (m *ExpiryMap[T]) GetByValue(val T) (key string, value T, ok bool) {
|
|
for key, v := range m.store.GetAll() {
|
|
if reflect.DeepEqual(v.value, val) {
|
|
// check if expired
|
|
if v.expires.Before(time.Now()) {
|
|
m.store.Remove(key)
|
|
break
|
|
}
|
|
return key, v.value, true
|
|
}
|
|
}
|
|
return "", *new(T), false
|
|
}
|
|
|
|
// Remove explicitly removes a key
|
|
func (m *ExpiryMap[T]) Remove(key string) {
|
|
m.store.Remove(key)
|
|
}
|
|
|
|
// RemovebyValue removes a value by value
|
|
func (m *ExpiryMap[T]) RemovebyValue(value T) (T, bool) {
|
|
for key, val := range m.store.GetAll() {
|
|
if reflect.DeepEqual(val.value, value) {
|
|
m.store.Remove(key)
|
|
return val.value, true
|
|
}
|
|
}
|
|
return *new(T), false
|
|
}
|
|
|
|
// startCleaner runs the background cleanup process
|
|
func (m *ExpiryMap[T]) startCleaner() {
|
|
go func() {
|
|
tick := time.Tick(m.cleanupInterval)
|
|
for range tick {
|
|
m.cleanup()
|
|
}
|
|
}()
|
|
}
|
|
|
|
// cleanup removes all expired entries
|
|
func (m *ExpiryMap[T]) cleanup() {
|
|
now := time.Now()
|
|
for key, val := range m.store.GetAll() {
|
|
if val.expires.Before(now) {
|
|
m.store.Remove(key)
|
|
}
|
|
}
|
|
}
|