// Package sessions configures the SCS session manager and provides // helpers for resolving player identity from the session. package sessions import ( "database/sql" "log/slog" "net/http" "time" "github.com/ryanhamamura/games/player" "github.com/alexedwards/scs/sqlite3store" "github.com/alexedwards/scs/v2" ) // Session key names. const ( KeyPlayerID = "player_id" KeyUserID = "user_id" KeyNickname = "nickname" ) // SetupSessionManager creates a configured session manager backed by SQLite. // Returns the manager and a cleanup function the caller should defer. func SetupSessionManager(db *sql.DB) (*scs.SessionManager, func()) { store := sqlite3store.New(db) cleanup := func() { store.StopCleanup() } sessionManager := scs.New() sessionManager.Store = store sessionManager.Lifetime = 30 * 24 * time.Hour sessionManager.Cookie.Name = "games_session" sessionManager.Cookie.Path = "/" sessionManager.Cookie.HttpOnly = true sessionManager.Cookie.Secure = true sessionManager.Cookie.SameSite = http.SameSiteLaxMode slog.Info("session manager configured") return sessionManager, cleanup } // GetPlayerID returns the current player's identity from the session. // Authenticated users get their user UUID; guests get a random ID that // is generated and persisted on first access. func GetPlayerID(sm *scs.SessionManager, r *http.Request) player.ID { pid := sm.GetString(r.Context(), KeyPlayerID) if pid == "" { pid = player.GenerateID(8) sm.Put(r.Context(), KeyPlayerID, pid) } if userID := sm.GetString(r.Context(), KeyUserID); userID != "" { return player.ID(userID) } return player.ID(pid) } // GetUserID returns the authenticated user's UUID, or empty string for guests. func GetUserID(sm *scs.SessionManager, r *http.Request) string { return sm.GetString(r.Context(), KeyUserID) } // GetNickname returns the player's display name from the session. func GetNickname(sm *scs.SessionManager, r *http.Request) string { return sm.GetString(r.Context(), KeyNickname) }