109 lines
2.1 KiB
Go

// session.go
package session
import (
"crypto/rand"
"encoding/hex"
"time"
)
const (
DefaultExpiration = 24 * time.Hour
IDLength = 32
)
// Session represents a user session
type Session struct {
ID string `json:"id"`
UserID int `json:"user_id"` // 0 for guest sessions
ExpiresAt time.Time `json:"expires_at"`
Data map[string]any `json:"data"`
}
// New creates a new session
func New(userID int) *Session {
return &Session{
ID: generateID(),
UserID: userID,
ExpiresAt: time.Now().Add(DefaultExpiration),
Data: make(map[string]any),
}
}
// IsExpired checks if the session has expired
func (s *Session) IsExpired() bool {
return time.Now().After(s.ExpiresAt)
}
// Touch extends the session expiration
func (s *Session) Touch() {
s.ExpiresAt = time.Now().Add(DefaultExpiration)
}
// Set stores a value in the session
func (s *Session) Set(key string, value any) {
s.Data[key] = value
}
// Get retrieves a value from the session
func (s *Session) Get(key string) (any, bool) {
value, exists := s.Data[key]
return value, exists
}
// Delete removes a value from the session
func (s *Session) Delete(key string) {
delete(s.Data, key)
}
// SetFlash stores a flash message (consumed on next Get)
func (s *Session) SetFlash(key string, value any) {
s.Set("flash_"+key, value)
}
// GetFlash retrieves and removes a flash message
func (s *Session) GetFlash(key string) (any, bool) {
flashKey := "flash_" + key
value, exists := s.Get(flashKey)
if exists {
s.Delete(flashKey)
}
return value, exists
}
// generateID creates a random session ID
func generateID() string {
bytes := make([]byte, IDLength)
rand.Read(bytes)
return hex.EncodeToString(bytes)
}
// Package-level convenience functions
func Create(userID int) *Session {
return Manager.Create(userID)
}
func Get(sessionID string) (*Session, bool) {
return Manager.Get(sessionID)
}
func Store(sess *Session) {
Manager.Store(sess)
}
func Delete(sessionID string) {
Manager.Delete(sessionID)
}
func Cleanup() {
Manager.Cleanup()
}
func Stats() (total, active int) {
return Manager.Stats()
}
func Close() error {
return Manager.Close()
}