Files
2026-02-26 17:52:48 +09:00

91 lines
1.8 KiB
Go

package player
import (
"crypto/rand"
"encoding/hex"
"sync"
"time"
)
// Session holds an authenticated player's session state.
type Session struct {
Token string
PlayerID uint64
PlayerName string
CreatedAt time.Time
LastActive time.Time
}
// SessionManager manages active sessions.
type SessionManager struct {
mu sync.RWMutex
sessions map[string]*Session // token -> session
}
// NewSessionManager creates a new session manager.
func NewSessionManager() *SessionManager {
return &SessionManager{
sessions: make(map[string]*Session),
}
}
// Create generates a new session for the given player.
func (sm *SessionManager) Create(playerID uint64, playerName string) *Session {
token := generateToken()
now := time.Now()
s := &Session{
Token: token,
PlayerID: playerID,
PlayerName: playerName,
CreatedAt: now,
LastActive: now,
}
sm.mu.Lock()
sm.sessions[token] = s
sm.mu.Unlock()
return s
}
// Get retrieves a session by token. Returns nil if not found.
func (sm *SessionManager) Get(token string) *Session {
sm.mu.RLock()
defer sm.mu.RUnlock()
s := sm.sessions[token]
if s != nil {
s.LastActive = time.Now()
}
return s
}
// Remove deletes a session.
func (sm *SessionManager) Remove(token string) {
sm.mu.Lock()
delete(sm.sessions, token)
sm.mu.Unlock()
}
// CleanupExpired removes sessions inactive for longer than the given duration.
func (sm *SessionManager) CleanupExpired(maxIdle time.Duration) int {
sm.mu.Lock()
defer sm.mu.Unlock()
cutoff := time.Now().Add(-maxIdle)
removed := 0
for token, s := range sm.sessions {
if s.LastActive.Before(cutoff) {
delete(sm.sessions, token)
removed++
}
}
return removed
}
func generateToken() string {
b := make([]byte, 32)
_, _ = rand.Read(b)
return hex.EncodeToString(b)
}