185 lines
5.9 KiB
Go
185 lines
5.9 KiB
Go
package db
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
)
|
|
|
|
// ============================================
|
|
// SESSION REDIS - GESTION UTILISATEUR
|
|
// ============================================
|
|
|
|
// SessionData représente une session client en Redis
|
|
type SessionData struct {
|
|
ClientID int `json:"client_id"`
|
|
Username string `json:"username"`
|
|
SessionID string `json:"session_id"`
|
|
Role string `json:"role"`
|
|
CreatedAt int64 `json:"created_at"`
|
|
LastActivity int64 `json:"last_activity"`
|
|
ExpiresAt int64 `json:"expires_at"`
|
|
BasketVersion int `json:"basket_version"`
|
|
PointsCache int `json:"points_cache"`
|
|
PenaltyCache float64 `json:"penalty_cache"`
|
|
Tags []string `json:"tags,omitempty"`
|
|
}
|
|
|
|
// ============================================
|
|
// CRÉER UNE SESSION CLIENT
|
|
// ============================================
|
|
|
|
// CreateClientSession crée une session Redis pour un client authentifié
|
|
// Appelé depuis handlers/auth.go après LoginClient réussi
|
|
//
|
|
// Exemple d'utilisation:
|
|
//
|
|
// sessionID := uuid.New().String()
|
|
// database.CreateClientSession(clientID, username, sessionID)
|
|
func (d *Database) CreateClientSession(clientID int, username string, sessionID string) error {
|
|
log.Printf("📝 [SESSION] Création session pour client: %s (ID: %d)", username, clientID)
|
|
|
|
sessionKey := fmt.Sprintf("session:client:%d", clientID)
|
|
now := time.Now().Unix()
|
|
expiresAt := now + (5 * 3600) // 5 heures
|
|
|
|
sessionData := SessionData{
|
|
ClientID: clientID,
|
|
Username: username,
|
|
SessionID: sessionID,
|
|
Role: "client",
|
|
CreatedAt: now,
|
|
LastActivity: now,
|
|
ExpiresAt: expiresAt,
|
|
BasketVersion: 0,
|
|
PointsCache: 0,
|
|
PenaltyCache: 0,
|
|
}
|
|
|
|
// Sérialiser et sauvegarder
|
|
sessionJSON, err := json.Marshal(sessionData)
|
|
if err != nil {
|
|
log.Printf("❌ [SESSION] Erreur sérialisation: %v", err)
|
|
return fmt.Errorf("erreur sérialisation session: %w", err)
|
|
}
|
|
|
|
ttl := time.Duration(expiresAt-now) * time.Second
|
|
if err := Redis.Set(RedisCtx, sessionKey, sessionJSON, ttl).Err(); err != nil {
|
|
log.Printf("❌ [SESSION] Erreur sauvegarde Redis: %v", err)
|
|
return fmt.Errorf("erreur sauvegarde session Redis: %w", err)
|
|
}
|
|
|
|
// Ajouter à l'index des sessions actives
|
|
if err := Redis.SAdd(RedisCtx, "session:active:clients", clientID).Err(); err != nil {
|
|
log.Printf("⚠️ [SESSION] Erreur ajout index: %v", err)
|
|
}
|
|
|
|
// Charger les infos du client (points, penalty) dans le cache
|
|
if client, err := d.GetClientByUsername(username); err == nil {
|
|
sessionData.PenaltyCache = float64(client.Amende)
|
|
sessionJSON, _ := json.Marshal(sessionData)
|
|
Redis.Set(RedisCtx, sessionKey, sessionJSON, ttl)
|
|
}
|
|
|
|
log.Printf("✅ [SESSION] Session créée pour %s - TTL: 5h", username)
|
|
return nil
|
|
}
|
|
|
|
// ============================================
|
|
// RÉCUPÉRER UNE SESSION CLIENT
|
|
// ============================================
|
|
|
|
// GetClientSession récupère la session Redis d'un client
|
|
// Retourne nil si session expirée ou inexistante
|
|
func (d *Database) GetClientSession(clientID int) (*SessionData, error) {
|
|
sessionKey := fmt.Sprintf("session:client:%d", clientID)
|
|
|
|
data, err := Redis.Get(RedisCtx, sessionKey).Result()
|
|
if err != nil {
|
|
log.Printf("⚠️ [SESSION] Pas de session trouvée pour client %d", clientID)
|
|
return nil, fmt.Errorf("session non trouvée")
|
|
}
|
|
|
|
var session SessionData
|
|
if err := json.Unmarshal([]byte(data), &session); err != nil {
|
|
log.Printf("❌ [SESSION] Erreur désérialisation: %v", err)
|
|
return nil, fmt.Errorf("erreur désérialisation: %w", err)
|
|
}
|
|
|
|
// Vérifier si session expirée
|
|
if time.Now().Unix() > session.ExpiresAt {
|
|
log.Printf("⚠️ [SESSION] Session expirée pour client %d", clientID)
|
|
Redis.Del(RedisCtx, sessionKey)
|
|
return nil, fmt.Errorf("session expirée")
|
|
}
|
|
|
|
return &session, nil
|
|
}
|
|
|
|
// ============================================
|
|
// METTRE À JOUR L'ACTIVITÉ DE SESSION
|
|
// ============================================
|
|
|
|
// RefreshSessionTimeout prolonge la durée de vie de la session
|
|
// Appelé régulièrement par SessionMiddleware (chaque requête client)
|
|
func (d *Database) RefreshSessionTimeout(clientID int) error {
|
|
sessionKey := fmt.Sprintf("session:client:%d", clientID)
|
|
|
|
// Récupérer la session
|
|
data, err := Redis.Get(RedisCtx, sessionKey).Result()
|
|
if err != nil {
|
|
return fmt.Errorf("session non trouvée")
|
|
}
|
|
|
|
var session SessionData
|
|
if err := json.Unmarshal([]byte(data), &session); err != nil {
|
|
return fmt.Errorf("erreur désérialisation: %w", err)
|
|
}
|
|
|
|
// Mettre à jour lastActivity et expiresAt
|
|
now := time.Now().Unix()
|
|
session.LastActivity = now
|
|
session.ExpiresAt = now + (5 * 3600) // Prolonger de 5 heures
|
|
|
|
// Resauvegarder
|
|
sessionJSON, _ := json.Marshal(session)
|
|
ttl := time.Duration(session.ExpiresAt-now) * time.Second
|
|
|
|
if err := Redis.Set(RedisCtx, sessionKey, sessionJSON, ttl).Err(); err != nil {
|
|
log.Printf("⚠️ [SESSION] Erreur refresh: %v", err)
|
|
return nil // Pas critique
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ============================================
|
|
// INVALIDER UNE SESSION (LOGOUT)
|
|
// ============================================
|
|
|
|
// InvalidateSession supprime la session Redis (logout)
|
|
// Appelé depuis handlers/auth.go dans LogoutClient
|
|
func (d *Database) InvalidateSession(clientID int) error {
|
|
sessionKey := fmt.Sprintf("session:client:%d", clientID)
|
|
basketKey := fmt.Sprintf("session:basket:%d", clientID)
|
|
|
|
// Supprimer la session
|
|
if err := Redis.Del(RedisCtx, sessionKey).Err(); err != nil {
|
|
log.Printf("⚠️ [SESSION] Erreur suppression: %v", err)
|
|
}
|
|
|
|
// Vider le panier Redis
|
|
if err := Redis.Del(RedisCtx, basketKey).Err(); err != nil {
|
|
log.Printf("⚠️ [SESSION] Erreur suppression panier: %v", err)
|
|
}
|
|
|
|
// Retirer de l'index
|
|
if err := Redis.SRem(RedisCtx, "session:active:clients", clientID).Err(); err != nil {
|
|
log.Printf("⚠️ [SESSION] Erreur retrait index: %v", err)
|
|
}
|
|
|
|
log.Printf("✅ [SESSION] Session invalidée pour client %d", clientID)
|
|
return nil
|
|
}
|