142 lines
2.9 KiB
Go
142 lines
2.9 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 int64 `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).Unix(),
|
|
Data: make(map[string]any),
|
|
}
|
|
}
|
|
|
|
// IsExpired checks if the session has expired
|
|
func (s *Session) IsExpired() bool {
|
|
return time.Now().Unix() > s.ExpiresAt
|
|
}
|
|
|
|
// Touch extends the session expiration
|
|
func (s *Session) Touch() {
|
|
s.ExpiresAt = time.Now().Add(DefaultExpiration).Unix()
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// GetFlashMessage retrieves and removes a flash message as string or empty string
|
|
func (s *Session) GetFlashMessage(key string) string {
|
|
if flash, exists := s.GetFlash(key); exists {
|
|
if msg, ok := flash.(string); ok {
|
|
return msg
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// RegenerateID creates a new session ID and updates storage
|
|
func (s *Session) RegenerateID() {
|
|
oldID := s.ID
|
|
s.ID = generateID()
|
|
|
|
if Manager != nil {
|
|
Manager.mu.Lock()
|
|
delete(Manager.sessions, oldID)
|
|
Manager.sessions[s.ID] = s
|
|
Manager.mu.Unlock()
|
|
}
|
|
}
|
|
|
|
// SetUserID updates the session's user ID (for login/logout)
|
|
func (s *Session) SetUserID(userID int) {
|
|
s.UserID = userID
|
|
}
|
|
|
|
// 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()
|
|
}
|
|
|
|
// RegenerateID regenerates the session ID for security (package-level convenience)
|
|
func RegenerateID(sess *Session) {
|
|
sess.RegenerateID()
|
|
}
|