fix player/session id distinction and add /user/me api endpoint

This commit is contained in:
Branden J Brown 2024-02-01 21:38:44 -06:00
parent 61db7de4cb
commit a044844d8b
3 changed files with 36 additions and 15 deletions

View File

@ -38,6 +38,7 @@ func main() {
r := chi.NewRouter() r := chi.NewRouter()
r.Post("/user/register", s.Register) r.Post("/user/register", s.Register)
r.Post("/user/login", s.Login) r.Post("/user/login", s.Login)
r.With(serve.WithPlayerID(sessions)).Get("/queue", s.Queue) r.With(serve.WithSession(sessions)).Get("/user/me", s.Me)
r.With(serve.WithSession(sessions)).Get("/queue", s.Queue)
http.ListenAndServe(":8080", r) http.ListenAndServe(":8080", r)
} }

View File

@ -34,25 +34,25 @@ func SetSession(w http.ResponseWriter, s player.Session) {
}) })
} }
// WithPlayerID is a middleware that adds a player ID to the request context // WithSession is a middleware that adds a player ID to the request context
// based on the session cookie content. If there is no such cookie, or its // based on the session cookie content. If there is no such cookie, or its
// value is invalid, the request fails with a 403 error. // value is invalid, the request fails with a 401 error.
func WithPlayerID(sessions player.RowQuerier) func(http.Handler) http.Handler { func WithSession(sessions player.RowQuerier) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
c, err := r.Cookie(sessionCookie) c, err := r.Cookie(sessionCookie)
if err != nil { if err != nil {
http.Error(w, "Forbidden", http.StatusForbidden) http.Error(w, "unauthorized", http.StatusUnauthorized)
return return
} }
id, err := player.ParseSession(c.Value) id, err := player.ParseSession(c.Value)
if err != nil { if err != nil {
http.Error(w, "Forbidden", http.StatusForbidden) http.Error(w, "unauthorized", http.StatusUnauthorized)
return return
} }
p, err := player.FromSession(r.Context(), sessions, id, time.Now()) p, err := player.FromSession(r.Context(), sessions, id, time.Now())
if err != nil { if err != nil {
http.Error(w, "Forbidden", http.StatusForbidden) http.Error(w, "unauthorized", http.StatusUnauthorized)
return return
} }
ctx := with(r.Context(), p) ctx := with(r.Context(), p)
@ -61,7 +61,7 @@ func WithPlayerID(sessions player.RowQuerier) func(http.Handler) http.Handler {
} }
} }
// Player returns the player ID set by WithPlayerID in the request context. // Session returns the session ID set by WithSession in the request context.
func PlayerID(ctx context.Context) player.ID { func Session(ctx context.Context) player.Session {
return value[player.ID](ctx) return value[player.Session](ctx)
} }

View File

@ -2,6 +2,7 @@ package main
import ( import (
"context" "context"
"encoding/json"
"errors" "errors"
"log/slog" "log/slog"
"net/http" "net/http"
@ -20,14 +21,14 @@ import (
type Server struct { type Server struct {
l *lobby.Lobby l *lobby.Lobby
creds credsDB creds db
sessions player.Execer sessions db
mu sync.Mutex mu sync.Mutex
pp map[player.ID]*websocket.Conn pp map[player.ID]*websocket.Conn
} }
type credsDB interface { type db interface {
player.RowQuerier player.RowQuerier
player.Execer player.Execer
} }
@ -133,13 +134,32 @@ func (s *Server) Login(w http.ResponseWriter, r *http.Request) {
slog.InfoContext(ctx, "logged in", "player", p, "id", id) slog.InfoContext(ctx, "logged in", "player", p, "id", id)
} }
func (s *Server) Me(w http.ResponseWriter, r *http.Request) {
id := serve.Session(r.Context())
if id == (player.Session{}) {
panic("missing player ID")
}
p, err := player.FromSession(r.Context(), s.sessions, id, time.Now())
if err != nil {
panic("session with no player id: " + err.Error())
}
q := struct {
ID player.ID `json:"id"`
}{p}
json.NewEncoder(w).Encode(q)
}
// Queue connects players to games. The connection immediately upgrades. // Queue connects players to games. The connection immediately upgrades.
// This handler MUST be wrapped in [serve.WithPlayerID]. // This handler MUST be wrapped in [serve.WithPlayerID].
func (s *Server) Queue(w http.ResponseWriter, r *http.Request) { func (s *Server) Queue(w http.ResponseWriter, r *http.Request) {
p := serve.PlayerID(r.Context()) id := serve.Session(r.Context())
if p == (player.ID{}) { if id == (player.Session{}) {
panic("missing player ID") panic("missing player ID")
} }
p, err := player.FromSession(r.Context(), s.sessions, id, time.Now())
if p == (player.ID{}) {
panic("session with no player id: " + err.Error())
}
person, err := s.accept(w, r, p) person, err := s.accept(w, r, p)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)