96 lines
1.6 KiB
Go
96 lines
1.6 KiB
Go
package session
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"sync"
|
|
"time"
|
|
|
|
"kubeviz/internal/model"
|
|
)
|
|
|
|
type sessionData struct {
|
|
Dataset *model.Dataset
|
|
LastAccess time.Time
|
|
}
|
|
|
|
type Store struct {
|
|
mu sync.RWMutex
|
|
sessions map[string]*sessionData
|
|
ttl time.Duration
|
|
stopCh chan struct{}
|
|
}
|
|
|
|
func NewStore(ttl time.Duration) *Store {
|
|
s := &Store{
|
|
sessions: make(map[string]*sessionData),
|
|
ttl: ttl,
|
|
stopCh: make(chan struct{}),
|
|
}
|
|
go s.cleanupLoop()
|
|
return s
|
|
}
|
|
|
|
func (s *Store) Stop() {
|
|
close(s.stopCh)
|
|
}
|
|
|
|
func (s *Store) NewSessionID() (string, error) {
|
|
buf := make([]byte, 16)
|
|
if _, err := rand.Read(buf); err != nil {
|
|
return "", err
|
|
}
|
|
return hex.EncodeToString(buf), nil
|
|
}
|
|
|
|
func (s *Store) GetDataset(sessionID string) *model.Dataset {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
entry, ok := s.sessions[sessionID]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
entry.LastAccess = time.Now()
|
|
return entry.Dataset
|
|
}
|
|
|
|
func (s *Store) SetDataset(sessionID string, ds *model.Dataset) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
s.sessions[sessionID] = &sessionData{Dataset: ds, LastAccess: time.Now()}
|
|
}
|
|
|
|
func (s *Store) Clear(sessionID string) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
delete(s.sessions, sessionID)
|
|
}
|
|
|
|
func (s *Store) cleanupLoop() {
|
|
ticker := time.NewTicker(1 * time.Minute)
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
select {
|
|
case <-s.stopCh:
|
|
return
|
|
case <-ticker.C:
|
|
s.cleanupExpired()
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Store) cleanupExpired() {
|
|
if s.ttl <= 0 {
|
|
return
|
|
}
|
|
cutoff := time.Now().Add(-s.ttl)
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
for id, sess := range s.sessions {
|
|
if sess.LastAccess.Before(cutoff) {
|
|
delete(s.sessions, id)
|
|
}
|
|
}
|
|
}
|