mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-06-10 10:10:49 +00:00
6895e369f6
- Remove standalone mode code: file-based stores, standalone gateway, heartbeat service, SQLite memory, standalone docker-compose - Rename docker-compose.managed.yml → docker-compose.postgres.yml - Clean up ~130 Go comments referencing "managed mode" qualifier - Simplify docker-compose.yml env vars (providers/channels via web UI) - Update .env.example to essential vars only (token + encryption key) - Add setup wizard UI (provider → agent → channel bootstrap flow) - Add logs.tail WebSocket handler for live log streaming - Add cursor-pointer to interactive UI components - Clean up config page (remove standalone-only sections) - Update README and docs for managed-only architecture
72 lines
1.5 KiB
Go
72 lines
1.5 KiB
Go
package cache
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// entry wraps a cached value with expiration metadata.
|
|
type entry[V any] struct {
|
|
value V
|
|
expiresAt time.Time // zero means no expiry
|
|
}
|
|
|
|
func (e entry[V]) expired() bool {
|
|
return !e.expiresAt.IsZero() && time.Now().After(e.expiresAt)
|
|
}
|
|
|
|
// InMemoryCache is a thread-safe in-memory Cache implementation with TTL support.
|
|
type InMemoryCache[V any] struct {
|
|
data sync.Map
|
|
}
|
|
|
|
// NewInMemoryCache creates a new in-memory cache.
|
|
func NewInMemoryCache[V any]() *InMemoryCache[V] {
|
|
return &InMemoryCache[V]{}
|
|
}
|
|
|
|
func (c *InMemoryCache[V]) Get(_ context.Context, key string) (V, bool) {
|
|
raw, ok := c.data.Load(key)
|
|
if !ok {
|
|
var zero V
|
|
return zero, false
|
|
}
|
|
e := raw.(entry[V])
|
|
if e.expired() {
|
|
c.data.Delete(key)
|
|
var zero V
|
|
return zero, false
|
|
}
|
|
return e.value, true
|
|
}
|
|
|
|
func (c *InMemoryCache[V]) Set(_ context.Context, key string, value V, ttl time.Duration) {
|
|
e := entry[V]{value: value}
|
|
if ttl > 0 {
|
|
e.expiresAt = time.Now().Add(ttl)
|
|
}
|
|
c.data.Store(key, e)
|
|
}
|
|
|
|
func (c *InMemoryCache[V]) Delete(_ context.Context, key string) {
|
|
c.data.Delete(key)
|
|
}
|
|
|
|
func (c *InMemoryCache[V]) DeleteByPrefix(_ context.Context, prefix string) {
|
|
c.data.Range(func(key, _ any) bool {
|
|
if k, ok := key.(string); ok && strings.HasPrefix(k, prefix) {
|
|
c.data.Delete(key)
|
|
}
|
|
return true
|
|
})
|
|
}
|
|
|
|
func (c *InMemoryCache[V]) Clear(_ context.Context) {
|
|
c.data.Range(func(key, _ any) bool {
|
|
c.data.Delete(key)
|
|
return true
|
|
})
|
|
}
|