92 lines · 1.9 KB · Go
RawDownload
package helps import (	"crypto/sha256"	"encoding/hex"	"sync"	"time" 	"github.com/google/uuid") type sessionIDCacheEntry struct {	value  string	expire time.Time} var (	sessionIDCache            = make(map[string]sessionIDCacheEntry)	sessionIDCacheMu          sync.RWMutex	sessionIDCacheCleanupOnce sync.Once) const (	sessionIDTTL                = time.Hour	sessionIDCacheCleanupPeriod = 15 * time.Minute) func startSessionIDCacheCleanup() {	go func() {		ticker := time.NewTicker(sessionIDCacheCleanupPeriod)		defer ticker.Stop()		for range ticker.C {			purgeExpiredSessionIDs()		}	}()} func purgeExpiredSessionIDs() {	now := time.Now()	sessionIDCacheMu.Lock()	for key, entry := range sessionIDCache {		if !entry.expire.After(now) {			delete(sessionIDCache, key)		}	}	sessionIDCacheMu.Unlock()} func sessionIDCacheKey(apiKey string) string {	sum := sha256.Sum256([]byte(apiKey))	return hex.EncodeToString(sum[:])} // CachedSessionID returns a stable session UUID per apiKey, refreshing the TTL on each access.func CachedSessionID(apiKey string) string {	if apiKey == "" {		return uuid.New().String()	} 	sessionIDCacheCleanupOnce.Do(startSessionIDCacheCleanup) 	key := sessionIDCacheKey(apiKey)	now := time.Now() 	sessionIDCacheMu.RLock()	entry, ok := sessionIDCache[key]	valid := ok && entry.value != "" && entry.expire.After(now)	sessionIDCacheMu.RUnlock()	if valid {		sessionIDCacheMu.Lock()		entry = sessionIDCache[key]		if entry.value != "" && entry.expire.After(now) {			entry.expire = now.Add(sessionIDTTL)			sessionIDCache[key] = entry			sessionIDCacheMu.Unlock()			return entry.value		}		sessionIDCacheMu.Unlock()	} 	newID := uuid.New().String() 	sessionIDCacheMu.Lock()	entry, ok = sessionIDCache[key]	if !ok || entry.value == "" || !entry.expire.After(now) {		entry.value = newID	}	entry.expire = now.Add(sessionIDTTL)	sessionIDCache[key] = entry	sessionIDCacheMu.Unlock()	return entry.value}