package handlers import ( "context" "errors" "fmt" "golias/models" "html/template" "net/http" ) func HandleCreateRoom(w http.ResponseWriter, r *http.Request) { // parse payload payload := &models.RoomReq{ RoomPass: r.PostFormValue("room_pass"), RoomName: r.PostFormValue("room_name"), } // create a room room, err := createRoom(r.Context(), payload) if err != nil { msg := "failed to create a room" log.Error(msg, "error", err) abortWithError(w, msg) return } ctx := context.WithValue(r.Context(), "current_room", room.ID) fi, err := getFullInfoByCtx(ctx) if err != nil { msg := "failed to get full info from ctx" log.Error(msg, "error", err) abortWithError(w, msg) return } fi.State.RoomID = room.ID fi.Room = room fi.Room.IsPublic = true // hardcode for local test; move to form if err := saveFullInfo(fi); err != nil { msg := "failed to set current room to session" log.Error(msg, "error", err) abortWithError(w, msg) return } notify(models.NotifyRoomListUpdate, "") tmpl, err := template.ParseGlob("components/*.html") if err != nil { abortWithError(w, err.Error()) return } tmpl.ExecuteTemplate(w, "base", fi) } // DEPRACATED: duplication of HandleJoinRoom // func HandleRoomEnter(w http.ResponseWriter, r *http.Request) { // // parse payload // roomID := r.URL.Query().Get("id") // if roomID == "" { // msg := "room id not provided" // log.Error(msg) // abortWithError(w, msg) // return // } // tmpl, err := template.ParseGlob("components/*.html") // if err != nil { // abortWithError(w, err.Error()) // return // } // // create a room // room, err := getRoomByID(roomID) // if err != nil { // msg := "failed to find the room" // log.Error(msg, "error", err, "room_id", roomID) // abortWithError(w, msg) // return // } // state, err := getStateByCtx(r.Context()) // // INFO: if non-loggined user join: prompt to login // if err != nil { // log.Error("failed to get state", "error", err) // // abortWithError(w, err.Error()) // tmpl.ExecuteTemplate(w, "login", nil) // return // } // state.RoomID = room.ID // // update state // if err := saveStateByCtx(r.Context(), state); err != nil { // log.Error("failed to update state", "error", err) // abortWithError(w, err.Error()) // return // } // // send msg of created room // // h.Broker.Notifier <- broker.NotificationEvent{ // // EventName: models.MsgRoomListUpdate, // // Payload: fmt.Sprintf("%s created a room named %s", r.CreatorName, r.RoomName), // // } // // return html // tmpl.ExecuteTemplate(w, "base", room) // } func HandleJoinTeam(w http.ResponseWriter, r *http.Request) { r.ParseForm() team := r.PostFormValue("team") role := r.PostFormValue("role") if team == "" || role == "" { msg := "missing team or role" log.Error(msg) abortWithError(w, msg) return } // get username fi, err := getFullInfoByCtx(r.Context()) if err != nil { abortWithError(w, err.Error()) return } if fi.Room.IsRunning && role == "mime" { err = errors.New("cannot join as mime when game is running") abortWithError(w, err.Error()) return } fi, err = joinTeam(r.Context(), role, team) if err != nil { abortWithError(w, err.Error()) return } // reveal all cards if role == "mime" { fi.Room.RevealAllCards() } // return html tmpl, err := template.ParseGlob("components/*.html") if err != nil { abortWithError(w, err.Error()) return } notify(models.NotifyRoomUpdatePrefix+fi.Room.ID, "") tmpl.ExecuteTemplate(w, "base", fi) } func HandleEndTurn(w http.ResponseWriter, r *http.Request) { // get username fi, err := getFullInfoByCtx(r.Context()) if err != nil { abortWithError(w, err.Error()) return } // check if one who pressed it is from the team who has the turn if fi.Room.TeamTurn != fi.State.Team { msg := fmt.Sprintln("unexpected team turn:" + fi.Room.TeamTurn) abortWithError(w, msg) return } fi.Room.ChangeTurn() if err := saveFullInfo(fi); err != nil { abortWithError(w, err.Error()) return } // return html tmpl, err := template.ParseGlob("components/*.html") if err != nil { abortWithError(w, err.Error()) return } if botName := fi.Room.WhichBotToMove(); botName != "" { // get bot from memcache bot, err := loadBot(botName, fi.Room.ID) if err != nil { log.Error("failed to load bot", "bot_name", botName, "room_id", fi.Room.ID) abortWithError(w, err.Error()) return } // send signal to bot bot.SignalsCh <- true } notify(models.NotifyRoomUpdatePrefix+fi.Room.ID, "") tmpl.ExecuteTemplate(w, "base", fi) } func HandleStartGame(w http.ResponseWriter, r *http.Request) { fi, err := getFullInfoByCtx(r.Context()) if err != nil { abortWithError(w, err.Error()) return } // TODO: check if enough players; also button should be hidden if already running fi.Room.IsRunning = true fi.Room.IsOver = false fi.Room.TeamTurn = "blue" // fi.Room.LoadTestCards() loadCards(fi.Room) fi.Room.UpdateCounter() fi.Room.TeamWon = "" action := models.Action{ Actor: fi.State.Username, ActorColor: string(fi.State.Team), WordColor: string(fi.State.Team), Action: "game started", // Word: clue, // Number: num, } fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) if err := saveFullInfo(fi); err != nil { abortWithError(w, err.Error()) return } // reveal all cards if fi.State.Role == "mime" { fi.Room.RevealAllCards() } // return html tmpl, err := template.ParseGlob("components/*.html") if err != nil { abortWithError(w, err.Error()) return } if botName := fi.Room.WhichBotToMove(); botName != "" { // get bot from memcache bot, err := loadBot(botName, fi.Room.ID) if err != nil { log.Error("failed to load bot", "bot_name", botName, "room_id", fi.Room.ID) abortWithError(w, err.Error()) return } // send signal to bot bot.SignalsCh <- true } // to update only the room that should be updated notify(models.NotifyRoomUpdatePrefix+fi.Room.ID, "") // notify(models.NotifyBacklogPrefix+fi.Room.ID, "game started") tmpl.ExecuteTemplate(w, "room", fi) } func HandleJoinRoom(w http.ResponseWriter, r *http.Request) { roomID := r.URL.Query().Get("id") room, err := getRoomByID(roomID) if err != nil { abortWithError(w, err.Error()) return } tmpl, err := template.ParseGlob("components/*.html") if err != nil { abortWithError(w, err.Error()) return } fi, err := getFullInfoByCtx(r.Context()) if err != nil { // INFO: if non-loggined user join: prompt to login fi = &models.FullInfo{} fi.LinkLogin = roomID tmpl.ExecuteTemplate(w, "base", fi) // abortWithError(w, err.Error()) return } room.PlayerList = append(room.PlayerList, fi.State.Username) fi.State.RoomID = room.ID fi.Room = room fi.List = nil if err := saveFullInfo(fi); err != nil { abortWithError(w, err.Error()) return } tmpl.ExecuteTemplate(w, "room", fi) } func HandleGiveClue(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { abortWithError(w, err.Error()) return } clue := r.PostFormValue("clue") num := r.PostFormValue("number") fi, err := getFullInfoByCtx(r.Context()) if err != nil { abortWithError(w, err.Error()) return } // validations === if fi.State.Team != models.UserTeam(fi.Room.TeamTurn) { err = errors.New("not your team's move") abortWithError(w, err.Error()) return } if fi.State.Role != "mime" { err = errors.New("need to be mime to open the card") abortWithError(w, err.Error()) return } if fi.Room.MimeDone { // team already have a clue abortWithError(w, "your team already has a clue") return } // === action := models.Action{ Actor: fi.State.Username, ActorColor: string(fi.State.Team), WordColor: string(fi.State.Team), Action: "gave clue", Word: clue, Number: num, } fi.Room.ActionHistory = append(fi.Room.ActionHistory, action) fi.Room.MimeDone = true notify(models.NotifyBacklogPrefix+fi.Room.ID, clue+num) if err := saveFullInfo(fi); err != nil { abortWithError(w, err.Error()) return } }