Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 56 additions & 58 deletions be-jeopardy/internal/handlers/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ var (
return r.Header.Get("Origin") == os.Getenv("ALLOW_ORIGIN")
},
}

jwtCookie = "jeopardy_access_token"
)

const (
Expand All @@ -115,7 +117,12 @@ const (
func GetPlayerGame(c *gin.Context) {
log.Infof("Received get player game request")

token := c.Request.Header.Get("Access-Token")
token, err := c.Cookie(jwtCookie)
if err != nil {
log.Errorf("Error getting token from cookie: %s", err.Error())
respondWithError(c, http.StatusForbidden, ErrInvalidAuthCredMsg)
}

playerId, err := auth.GetJWTSubject(token)
if err != nil {
log.Errorf(ErrGettingPlayerIdMsg, err.Error())
Expand Down Expand Up @@ -165,9 +172,10 @@ func CreatePrivateGame(c *gin.Context) {
return
}

setJwtCookie(c, jwt)

c.JSON(http.StatusOK, jeopardy.Response{
Code: http.StatusOK,
Token: jwt,
Message: "Authorized to create private game",
Game: game,
})
Expand Down Expand Up @@ -197,9 +205,10 @@ func JoinGameByCode(c *gin.Context) {
return
}

setJwtCookie(c, jwt)

c.JSON(http.StatusOK, jeopardy.Response{
Code: http.StatusOK,
Token: jwt,
Message: "Authorized to join game by code",
Game: game,
})
Expand Down Expand Up @@ -233,9 +242,10 @@ func JoinPublicGame(c *gin.Context) {
return
}

setJwtCookie(c, jwt)

c.JSON(http.StatusOK, jeopardy.Response{
Code: http.StatusOK,
Token: jwt,
Message: "Authorized to join public game",
Game: game,
})
Expand All @@ -244,47 +254,39 @@ func JoinPublicGame(c *gin.Context) {
func JoinGameChat(c *gin.Context) {
log.Infof("Received request to join game chat")

ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
log.Errorf("Error upgrading connection to WebSocket: %s", err.Error())
respondWithError(c, http.StatusInternalServerError, ErrJoiningChatMsg)
return
}

_, msg, err := ws.ReadMessage()
token, err := c.Cookie(jwtCookie)
if err != nil {
log.Errorf("Error reading message from WebSocket: %s", err.Error())
closeConnWithMsg(ws, socket.ServerError, ErrJoiningChatMsg)
return
}

var req TokenRequest
if err := json.Unmarshal(msg, &req); err != nil {
log.Errorf("Error parsing chat request: %s", err.Error())
closeConnWithMsg(ws, socket.BadRequest, ErrMalformedReqMsg)
log.Errorf("Error getting token from cookie: %s", err.Error())
respondWithError(c, http.StatusForbidden, ErrInvalidAuthCredMsg)
return
}

playerId, err := auth.GetJWTSubject(req.Token)
playerId, err := auth.GetJWTSubject(token)
if err != nil {
log.Errorf(ErrGettingPlayerIdMsg, err.Error())
closeConnWithMsg(ws, socket.Unauthorized, ErrInvalidAuthCredMsg)
respondWithError(c, http.StatusUnauthorized, ErrInvalidAuthCredMsg)
return
}

conn := socket.NewSafeConn(ws)
err = jeopardy.JoinGameChat(playerId, conn)
ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
log.Errorf("Error joining chat: %s", err.Error())
closeConnWithMsg(ws, socket.BadRequest, "Unable to join chat: %s", err.Error())
log.Errorf("Error upgrading connection to WebSocket: %s", err.Error())
respondWithError(c, http.StatusInternalServerError, ErrJoiningChatMsg)
return
}

jeopardy.JoinGameChat(playerId, ws)
}

func AddBot(c *gin.Context) {
log.Infof("Received add bot request")

token := c.Request.Header.Get("Access-Token")
token, err := c.Cookie(jwtCookie)
if err != nil {
log.Errorf("Error getting token from cookie: %s", err.Error())
respondWithError(c, http.StatusForbidden, ErrInvalidAuthCredMsg)
}

playerId, err := auth.GetJWTSubject(token)
if err != nil {
log.Errorf(ErrGettingPlayerIdMsg, err.Error())
Expand All @@ -303,47 +305,39 @@ func AddBot(c *gin.Context) {
func PlayGame(c *gin.Context) {
log.Infof("Received play request")

ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
log.Errorf("Error upgrading connection to WebSocket: %s", err.Error())
respondWithError(c, http.StatusInternalServerError, UnexpectedServerErrMsg)
return
}

_, msg, err := ws.ReadMessage()
token, err := c.Cookie(jwtCookie)
if err != nil {
log.Errorf("Error reading message from WebSocket: %s", err.Error())
closeConnWithMsg(ws, socket.ServerError, UnexpectedServerErrMsg)
return
}

var req TokenRequest
if err := json.Unmarshal(msg, &req); err != nil {
log.Errorf("Error parsing play request: %s", err.Error())
closeConnWithMsg(ws, socket.BadRequest, ErrMalformedReqMsg)
log.Errorf("Error getting token from cookie: %s", err.Error())
respondWithError(c, http.StatusForbidden, ErrInvalidAuthCredMsg)
return
}

playerId, err := auth.GetJWTSubject(req.Token)
playerId, err := auth.GetJWTSubject(token)
if err != nil {
log.Errorf(ErrGettingPlayerIdMsg, err.Error())
closeConnWithMsg(ws, socket.Unauthorized, ErrInvalidAuthCredMsg)
respondWithError(c, http.StatusUnauthorized, ErrInvalidAuthCredMsg)
return
}

conn := socket.NewSafeConn(ws)
err = jeopardy.PlayGame(playerId, conn)
ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
log.Errorf("Error playing game: %s", err.Error())
closeConnWithMsg(ws, socket.BadRequest, "Unable to play game: %s", err.Error())
log.Errorf("Error upgrading connection to WebSocket: %s", err.Error())
respondWithError(c, http.StatusInternalServerError, UnexpectedServerErrMsg)
return
}

jeopardy.PlayGame(playerId, ws)
}

func PlayAgain(c *gin.Context) {
log.Infof("Received play again request")

token := c.Request.Header.Get("Access-Token")
token, err := c.Cookie(jwtCookie)
if err != nil {
log.Errorf("Error getting token from cookie: %s", err.Error())
respondWithError(c, http.StatusForbidden, ErrInvalidAuthCredMsg)
}

playerId, err := auth.GetJWTSubject(token)
if err != nil {
log.Errorf(ErrGettingPlayerIdMsg, err.Error())
Expand All @@ -366,7 +360,12 @@ func PlayAgain(c *gin.Context) {
func LeaveGame(c *gin.Context) {
log.Infof("Received leave request")

token := c.Request.Header.Get("Access-Token")
token, err := c.Cookie(jwtCookie)
if err != nil {
log.Errorf("Error getting token from cookie: %s", err.Error())
respondWithError(c, http.StatusForbidden, ErrInvalidAuthCredMsg)
}

playerId, err := auth.GetJWTSubject(token)
if err != nil {
log.Errorf(ErrGettingPlayerIdMsg, err.Error())
Expand Down Expand Up @@ -416,11 +415,10 @@ func parseBody(body io.ReadCloser, v any) error {
return json.Unmarshal(msg, v)
}

func closeConnWithMsg(conn *websocket.Conn, code int, msg string, args ...any) {
_ = conn.WriteJSON(jeopardy.Response{Code: code, Message: fmt.Sprintf(msg, args...)})
_ = conn.Close()
}

func respondWithError(c *gin.Context, code int, msg string, args ...any) {
c.JSON(code, jeopardy.Response{Code: code, Message: fmt.Sprintf(msg, args...)})
}

func setJwtCookie(c *gin.Context, jwt string) {
c.SetCookie(jwtCookie, jwt, 24*3600, "/", "", false, true)
}
19 changes: 13 additions & 6 deletions be-jeopardy/internal/jeopardy/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/gorilla/websocket"
"github.com/rileythomp/jeopardy/be-jeopardy/internal/log"
"github.com/rileythomp/jeopardy/be-jeopardy/internal/socket"
)

type ChatMessage struct {
Expand All @@ -15,25 +16,31 @@ type ChatMessage struct {
TimeStamp int64 `json:"timeStamp"`
}

func JoinGameChat(playerId string, conn SafeConn) error {
func JoinGameChat(playerId string, ws *websocket.Conn) {
conn := socket.NewSafeConn(ws)

game, err := GetPlayerGame(playerId)
if err != nil {
return err
log.Errorf("Error getting game for player %s: %s", playerId, err.Error())
closeConnWithMsg(conn, socket.BadRequest, "Unable to join chat: %s", err.Error())
return
}

player, err := game.getPlayerById(playerId)
if err != nil {
return err
log.Errorf("Error getting player by id: %s", err.Error())
closeConnWithMsg(conn, socket.BadRequest, "Unable to join chat: %s", err.Error())
return
}
if player.chatConn() != nil {
return fmt.Errorf("Player already in chat")
log.Errorf("Error joining chat: Player already in chat")
closeConnWithMsg(conn, socket.BadRequest, "Unable to join chat: Player already in chat")
return
}
player.setChatConn(conn)

player.sendChatPings()
player.processChatMessages(game.chatChan)

return nil
}

func (p *Player) processChatMessages(chatChan chan ChatMessage) {
Expand Down
5 changes: 2 additions & 3 deletions be-jeopardy/internal/jeopardy/game.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ type (
FinalAnswers []string `json:"finalAnswers"`
Paused bool `json:"paused"`
PausedState GameState `json:"pausedState"`
PausedAt time.Time `json:"pausedAt"`
pausedAt time.Time

StartBuzzCountdown bool `json:"startBuzzCountdown"`
StartFinalAnswerCountdown bool `json:"startFinalAnswerCountdown"`
Expand Down Expand Up @@ -148,7 +148,6 @@ type (

Response struct {
Code int `json:"code"`
Token string `json:"token,omitempty"`
Message string `json:"message"`
Game *Game `json:"game,omitempty"`
CurPlayer GamePlayer `json:"curPlayer,omitempty"`
Expand Down Expand Up @@ -246,7 +245,7 @@ func (g *Game) restartGame() {
}

func (g *Game) pauseGame(player GamePlayer) {
g.PausedAt = time.Now()
g.pausedAt = time.Now()
g.Paused = true
g.PausedState = g.State
if g.State != PostGame {
Expand Down
28 changes: 20 additions & 8 deletions be-jeopardy/internal/jeopardy/jeopardy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"time"

"github.com/google/uuid"
"github.com/gorilla/websocket"
"github.com/rileythomp/jeopardy/be-jeopardy/internal/db"
"github.com/rileythomp/jeopardy/be-jeopardy/internal/log"
"github.com/rileythomp/jeopardy/be-jeopardy/internal/socket"
Expand Down Expand Up @@ -167,26 +168,32 @@ func AddBot(playerId string) error {
return nil
}

func PlayGame(playerId string, conn SafeConn) error {
func PlayGame(playerId string, ws *websocket.Conn) {
conn := socket.NewSafeConn(ws)

game, err := GetPlayerGame(playerId)
if err != nil {
return err
log.Errorf("Error getting game for player: %s", err.Error())
closeConnWithMsg(conn, socket.BadRequest, "Unable to play game: %s", err.Error())
return
}

player, err := game.getPlayerById(playerId)
if err != nil {
return err
log.Errorf("Error getting player by id: %s", err.Error())
closeConnWithMsg(conn, socket.BadRequest, "Unable to play game: %s", err.Error())
return
}
if player.conn() != nil {
return fmt.Errorf("Player already playing")
log.Errorf("Error playing game: Player already playing")
closeConnWithMsg(conn, socket.BadRequest, "Unable to play game: Player already playing")
return
}
player.setConn(conn)
player.sendPings()
player.readMessages(game.msgChan, game.pauseChan)

game.handlePlayerJoined(player)

return nil
}

func (g *Game) handlePlayerJoined(player GamePlayer) {
Expand Down Expand Up @@ -262,13 +269,13 @@ func PlayAgain(playerId string) error {
func CleanUpGames() {
log.Infof("Performing game cleanup")
for _, game := range publicGames {
if game.Paused && time.Since(game.PausedAt) > time.Hour {
if game.Paused && time.Since(game.pausedAt) > time.Hour {
log.Infof("Game %s has been paused for over an hour, removing it", game.Name)
removeGame(game)
}
}
for _, game := range privateGames {
if game.Paused && time.Since(game.PausedAt) > time.Hour {
if game.Paused && time.Since(game.pausedAt) > time.Hour {
log.Infof("Game %s has been paused for over an hour, removing it", game.Name)
removeGame(game)
}
Expand All @@ -285,3 +292,8 @@ func removeGame(g *Game) {
delete(playerGames, p.id())
}
}

func closeConnWithMsg(conn SafeConn, code int, msg string, args ...any) {
_ = conn.WriteJSON(Response{Code: code, Message: fmt.Sprintf(msg, args...)})
_ = conn.Close()
}
4 changes: 2 additions & 2 deletions be-jeopardy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ func main() {
log.Fatalf("Failed to set trusted proxies: %s", err)
}
corsConfig := cors.DefaultConfig()
corsConfig.AllowAllOrigins = true
corsConfig.AllowHeaders = append(corsConfig.AllowHeaders, "Access-Token")
corsConfig.AllowCredentials = true
corsConfig.AllowOrigins = []string{os.Getenv("ALLOW_ORIGIN")}
router.Use(cors.New(corsConfig))
for _, route := range handlers.Routes {
router.Handle(route.Method, route.Path, route.Handler)
Expand Down
Loading