- Reorder HandleGameEvents to create NATS subscriptions before SSE - Use chi's middleware.NewWrapResponseWriter for proper http.Flusher support - Add slog-zerolog adapter for unified logging - Add ErrorLog to HTTP server for better error visibility - Change session Cookie.Secure to false for HTTP support - Change heartbeat from 15s to 10s - Remove ConnectionIndicator patching (was causing PatchElementsNoTargetsFound) The key fix was using chi's response writer wrapper which properly implements http.Flusher, allowing SSE data to be flushed immediately instead of being buffered.
68 lines
2.0 KiB
Go
68 lines
2.0 KiB
Go
// 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 = false
|
|
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)
|
|
}
|