96 lines
1.7 KiB
Go
96 lines
1.7 KiB
Go
package admin
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type snapshotCacheEntry struct {
|
|
ETag string
|
|
Payload any
|
|
ExpiresAt time.Time
|
|
}
|
|
|
|
type snapshotCache struct {
|
|
mu sync.RWMutex
|
|
ttl time.Duration
|
|
items map[string]snapshotCacheEntry
|
|
}
|
|
|
|
func newSnapshotCache(ttl time.Duration) *snapshotCache {
|
|
if ttl <= 0 {
|
|
ttl = 30 * time.Second
|
|
}
|
|
return &snapshotCache{
|
|
ttl: ttl,
|
|
items: make(map[string]snapshotCacheEntry),
|
|
}
|
|
}
|
|
|
|
func (c *snapshotCache) Get(key string) (snapshotCacheEntry, bool) {
|
|
if c == nil || key == "" {
|
|
return snapshotCacheEntry{}, false
|
|
}
|
|
now := time.Now()
|
|
|
|
c.mu.RLock()
|
|
entry, ok := c.items[key]
|
|
c.mu.RUnlock()
|
|
if !ok {
|
|
return snapshotCacheEntry{}, false
|
|
}
|
|
if now.After(entry.ExpiresAt) {
|
|
c.mu.Lock()
|
|
delete(c.items, key)
|
|
c.mu.Unlock()
|
|
return snapshotCacheEntry{}, false
|
|
}
|
|
return entry, true
|
|
}
|
|
|
|
func (c *snapshotCache) Set(key string, payload any) snapshotCacheEntry {
|
|
if c == nil {
|
|
return snapshotCacheEntry{}
|
|
}
|
|
entry := snapshotCacheEntry{
|
|
ETag: buildETagFromAny(payload),
|
|
Payload: payload,
|
|
ExpiresAt: time.Now().Add(c.ttl),
|
|
}
|
|
if key == "" {
|
|
return entry
|
|
}
|
|
c.mu.Lock()
|
|
c.items[key] = entry
|
|
c.mu.Unlock()
|
|
return entry
|
|
}
|
|
|
|
func buildETagFromAny(payload any) string {
|
|
raw, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
sum := sha256.Sum256(raw)
|
|
return "\"" + hex.EncodeToString(sum[:]) + "\""
|
|
}
|
|
|
|
func parseBoolQueryWithDefault(raw string, def bool) bool {
|
|
value := strings.TrimSpace(strings.ToLower(raw))
|
|
if value == "" {
|
|
return def
|
|
}
|
|
switch value {
|
|
case "1", "true", "yes", "on":
|
|
return true
|
|
case "0", "false", "no", "off":
|
|
return false
|
|
default:
|
|
return def
|
|
}
|
|
}
|