refactor: extract shared player, session, and chat packages #5

Merged
ryan merged 14 commits from refactor/shared-player-session-chat into main 2026-03-03 08:50:13 +00:00
5 changed files with 23 additions and 14 deletions
Showing only changes of commit dcf76bb773 - Show all commits

View File

@@ -11,6 +11,7 @@ import (
"github.com/ryanhamamura/games/auth" "github.com/ryanhamamura/games/auth"
"github.com/ryanhamamura/games/db/repository" "github.com/ryanhamamura/games/db/repository"
"github.com/ryanhamamura/games/features/auth/pages" "github.com/ryanhamamura/games/features/auth/pages"
appsessions "github.com/ryanhamamura/games/sessions"
) )
type LoginSignals struct { type LoginSignals struct {
@@ -65,9 +66,9 @@ func HandleLogin(queries *repository.Queries, sessions *scs.SessionManager) http
} }
sessions.RenewToken(r.Context()) //nolint:errcheck sessions.RenewToken(r.Context()) //nolint:errcheck
sessions.Put(r.Context(), "user_id", user.ID) sessions.Put(r.Context(), appsessions.KeyUserID, user.ID)
sessions.Put(r.Context(), "username", user.Username) sessions.Put(r.Context(), "username", user.Username)
sessions.Put(r.Context(), "nickname", user.Username) sessions.Put(r.Context(), appsessions.KeyNickname, user.Username)
redirectURL := "/" redirectURL := "/"
if returnURL := sessions.GetString(r.Context(), "return_url"); returnURL != "" { if returnURL := sessions.GetString(r.Context(), "return_url"); returnURL != "" {
@@ -119,9 +120,9 @@ func HandleRegister(queries *repository.Queries, sessions *scs.SessionManager) h
} }
sessions.RenewToken(r.Context()) //nolint:errcheck sessions.RenewToken(r.Context()) //nolint:errcheck
sessions.Put(r.Context(), "user_id", user.ID) sessions.Put(r.Context(), appsessions.KeyUserID, user.ID)
sessions.Put(r.Context(), "username", user.Username) sessions.Put(r.Context(), "username", user.Username)
sessions.Put(r.Context(), "nickname", user.Username) sessions.Put(r.Context(), appsessions.KeyNickname, user.Username)
redirectURL := "/" redirectURL := "/"
if returnURL := sessions.GetString(r.Context(), "return_url"); returnURL != "" { if returnURL := sessions.GetString(r.Context(), "return_url"); returnURL != "" {

View File

@@ -266,7 +266,7 @@ func HandleSetNickname(store *connect4.Store, sm *scs.SessionManager) http.Handl
return return
} }
sm.Put(r.Context(), "nickname", signals.Nickname) sm.Put(r.Context(), sessions.KeyNickname, signals.Nickname)
playerID := sessions.GetPlayerID(sm, r) playerID := sessions.GetPlayerID(sm, r)
userID := sessions.GetUserID(sm, r) userID := sessions.GetUserID(sm, r)

View File

@@ -11,6 +11,7 @@ import (
"github.com/ryanhamamura/games/db/repository" "github.com/ryanhamamura/games/db/repository"
lobbycomponents "github.com/ryanhamamura/games/features/lobby/components" lobbycomponents "github.com/ryanhamamura/games/features/lobby/components"
"github.com/ryanhamamura/games/features/lobby/pages" "github.com/ryanhamamura/games/features/lobby/pages"
appsessions "github.com/ryanhamamura/games/sessions"
"github.com/ryanhamamura/games/snake" "github.com/ryanhamamura/games/snake"
"github.com/alexedwards/scs/v2" "github.com/alexedwards/scs/v2"
@@ -21,7 +22,7 @@ import (
// HandleLobbyPage renders the main lobby page with active games for logged-in users. // HandleLobbyPage renders the main lobby page with active games for logged-in users.
func HandleLobbyPage(queries *repository.Queries, sessions *scs.SessionManager, snakeStore *snake.SnakeStore) http.HandlerFunc { func HandleLobbyPage(queries *repository.Queries, sessions *scs.SessionManager, snakeStore *snake.SnakeStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
userID := sessions.GetString(r.Context(), "user_id") userID := sessions.GetString(r.Context(), appsessions.KeyUserID)
username := sessions.GetString(r.Context(), "username") username := sessions.GetString(r.Context(), "username")
isLoggedIn := userID != "" isLoggedIn := userID != ""
@@ -95,7 +96,7 @@ func HandleCreateGame(store *connect4.Store, sessions *scs.SessionManager) http.
return return
} }
sessions.Put(r.Context(), "nickname", signals.Nickname) sessions.Put(r.Context(), appsessions.KeyNickname, signals.Nickname)
gi := store.Create() gi := store.Create()
sse := datastar.NewSSE(w, r) sse := datastar.NewSSE(w, r)
@@ -137,7 +138,7 @@ func HandleCreateSnakeGame(snakeStore *snake.SnakeStore, sessions *scs.SessionMa
return return
} }
sessions.Put(r.Context(), "nickname", signals.Nickname) sessions.Put(r.Context(), appsessions.KeyNickname, signals.Nickname)
mode := snake.ModeMultiplayer mode := snake.ModeMultiplayer
if r.URL.Query().Get("mode") == "solo" { if r.URL.Query().Get("mode") == "solo" {

View File

@@ -277,7 +277,7 @@ func HandleSetNickname(snakeStore *snake.SnakeStore, sm *scs.SessionManager) htt
return return
} }
sm.Put(r.Context(), "nickname", signals.Nickname) sm.Put(r.Context(), sessions.KeyNickname, signals.Nickname)
playerID := sessions.GetPlayerID(sm, r) playerID := sessions.GetPlayerID(sm, r)
userID := sessions.GetUserID(sm, r) userID := sessions.GetUserID(sm, r)

View File

@@ -14,6 +14,13 @@ import (
"github.com/alexedwards/scs/v2" "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. // SetupSessionManager creates a configured session manager backed by SQLite.
// Returns the manager and a cleanup function the caller should defer. // Returns the manager and a cleanup function the caller should defer.
func SetupSessionManager(db *sql.DB) (*scs.SessionManager, func()) { func SetupSessionManager(db *sql.DB) (*scs.SessionManager, func()) {
@@ -38,12 +45,12 @@ func SetupSessionManager(db *sql.DB) (*scs.SessionManager, func()) {
// Authenticated users get their user UUID; guests get a random ID that // Authenticated users get their user UUID; guests get a random ID that
// is generated and persisted on first access. // is generated and persisted on first access.
func GetPlayerID(sm *scs.SessionManager, r *http.Request) player.ID { func GetPlayerID(sm *scs.SessionManager, r *http.Request) player.ID {
pid := sm.GetString(r.Context(), "player_id") pid := sm.GetString(r.Context(), KeyPlayerID)
if pid == "" { if pid == "" {
pid = player.GenerateID(8) pid = player.GenerateID(8)
sm.Put(r.Context(), "player_id", pid) sm.Put(r.Context(), KeyPlayerID, pid)
} }
if userID := sm.GetString(r.Context(), "user_id"); userID != "" { if userID := sm.GetString(r.Context(), KeyUserID); userID != "" {
return player.ID(userID) return player.ID(userID)
} }
return player.ID(pid) return player.ID(pid)
@@ -51,10 +58,10 @@ func GetPlayerID(sm *scs.SessionManager, r *http.Request) player.ID {
// GetUserID returns the authenticated user's UUID, or empty string for guests. // GetUserID returns the authenticated user's UUID, or empty string for guests.
func GetUserID(sm *scs.SessionManager, r *http.Request) string { func GetUserID(sm *scs.SessionManager, r *http.Request) string {
return sm.GetString(r.Context(), "user_id") return sm.GetString(r.Context(), KeyUserID)
} }
// GetNickname returns the player's display name from the session. // GetNickname returns the player's display name from the session.
func GetNickname(sm *scs.SessionManager, r *http.Request) string { func GetNickname(sm *scs.SessionManager, r *http.Request) string {
return sm.GetString(r.Context(), "nickname") return sm.GetString(r.Context(), KeyNickname)
} }