Fix: notify bot
This commit is contained in:
@ -33,8 +33,7 @@ func saveRoom(room *models.Room) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
memcache.Set(models.CacheRoomPrefix+room.ID, data)
|
||||
log.Debug("saved room", "room", room, "key", key)
|
||||
memcache.Set(key, data)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -84,6 +83,21 @@ func saveFullInfo(fi *models.FullInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func notifyBotIfNeeded(fi *models.FullInfo) {
|
||||
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
|
||||
llmapi.SignalChanMap[botName] <- true
|
||||
}
|
||||
log.Debug("no bot", "room_id", fi.Room.ID)
|
||||
}
|
||||
|
||||
// cache
|
||||
|
||||
func saveState(username string, state *models.UserState) error {
|
||||
@ -110,7 +124,16 @@ func loadState(username string) (*models.UserState, error) {
|
||||
}
|
||||
|
||||
func loadBot(botName, roomID string) (*llmapi.Bot, error) {
|
||||
return nil, nil
|
||||
key := "botkey_" + roomID + botName
|
||||
data, err := memcache.Get(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp := &llmapi.Bot{}
|
||||
if err := json.Unmarshal(data, &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func getAllNames() []string {
|
||||
|
@ -92,6 +92,7 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) {
|
||||
case "white", string(oppositeColor):
|
||||
// end turn
|
||||
fi.Room.TeamTurn = oppositeColor
|
||||
fi.Room.MimeDone = false
|
||||
}
|
||||
// check if no cards left => game over
|
||||
if fi.Room.BlueCounter == 0 {
|
||||
@ -110,6 +111,8 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) {
|
||||
abortWithError(w, err.Error())
|
||||
return
|
||||
}
|
||||
// get mime bot for opp team and notify it
|
||||
notifyBotIfNeeded(fi)
|
||||
notify(models.NotifyRoomUpdatePrefix+fi.Room.ID, "")
|
||||
if err := tmpl.ExecuteTemplate(w, "cardword", cardword); err != nil {
|
||||
log.Error("failed to execute cardword template", "error", err)
|
||||
@ -136,16 +139,19 @@ func HandleAddBot(w http.ResponseWriter, r *http.Request) {
|
||||
// get team; // get role; make up a name
|
||||
team := r.URL.Query().Get("team")
|
||||
role := r.URL.Query().Get("role")
|
||||
log.Debug("got add-bot request", "team", team, "role", role)
|
||||
fi, err := getFullInfoByCtx(r.Context())
|
||||
if err != nil {
|
||||
abortWithError(w, err.Error())
|
||||
return
|
||||
}
|
||||
// TODO: what if bot exists already?
|
||||
// control number and names of bots
|
||||
bot, err := llmapi.NewBot(role, team, "bot1", fi.Room.ID, cfg)
|
||||
if err != nil {
|
||||
abortWithError(w, err.Error())
|
||||
return
|
||||
}
|
||||
bot.StartBot()
|
||||
go bot.StartBot()
|
||||
notify(models.NotifyRoomUpdatePrefix+fi.Room.ID, "")
|
||||
}
|
||||
|
@ -51,53 +51,6 @@ func HandleCreateRoom(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
log.Error("failed to parse form", "error", err)
|
||||
@ -158,6 +111,7 @@ func HandleEndTurn(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
fi.Room.ChangeTurn()
|
||||
fi.Room.MimeDone = false
|
||||
if err := saveFullInfo(fi); err != nil {
|
||||
abortWithError(w, err.Error())
|
||||
return
|
||||
@ -168,17 +122,7 @@ func HandleEndTurn(w http.ResponseWriter, r *http.Request) {
|
||||
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
|
||||
}
|
||||
notifyBotIfNeeded(fi)
|
||||
notify(models.NotifyRoomUpdatePrefix+fi.Room.ID, "")
|
||||
if err := tmpl.ExecuteTemplate(w, "base", fi); err != nil {
|
||||
log.Error("failed to execute base template", "error", err)
|
||||
@ -222,17 +166,7 @@ func HandleStartGame(w http.ResponseWriter, r *http.Request) {
|
||||
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
|
||||
}
|
||||
notifyBotIfNeeded(fi)
|
||||
// to update only the room that should be updated
|
||||
notify(models.NotifyRoomUpdatePrefix+fi.Room.ID, "")
|
||||
// notify(models.NotifyBacklogPrefix+fi.Room.ID, "game started")
|
||||
|
@ -5,24 +5,22 @@ import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"golias/models"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// LogRequests logs all HTTP requests with method, path and duration
|
||||
func LogRequests(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
// start := time.Now()
|
||||
// Wrap response writer to capture status code
|
||||
next.ServeHTTP(w, r)
|
||||
duration := time.Since(start)
|
||||
log.Debug("request completed",
|
||||
"method", r.Method,
|
||||
"path", r.URL.RequestURI(),
|
||||
"duration", duration.String(),
|
||||
)
|
||||
// duration := time.Since(start)
|
||||
// log.Debug("request completed",
|
||||
// "method", r.Method,
|
||||
// "path", r.URL.RequestURI(),
|
||||
// "duration", duration.String(),
|
||||
// )
|
||||
})
|
||||
}
|
||||
|
||||
@ -65,11 +63,11 @@ func GetSession(next http.Handler) http.Handler {
|
||||
return
|
||||
}
|
||||
userSession, err := cacheGetSession(sessionToken)
|
||||
log.Debug("userSession from cache", "us", userSession)
|
||||
// log.Debug("userSession from cache", "us", userSession)
|
||||
if err != nil {
|
||||
msg := "auth failed; session does not exists"
|
||||
err = errors.New(msg)
|
||||
log.Debug(msg, "error", err)
|
||||
// msg := "auth failed; session does not exists"
|
||||
// err = errors.New(msg)
|
||||
// log.Debug(msg, "error", err)
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -18,6 +19,14 @@ import (
|
||||
// MIME: llm needs to know all the cards, colors and previous actions
|
||||
// GUESSER: llm needs to know all the cards and previous actions
|
||||
|
||||
// channels are not serializable
|
||||
|
||||
var (
|
||||
// botname -> channel
|
||||
SignalChanMap = make(map[string]chan bool)
|
||||
DoneChanMap = make(map[string]chan bool)
|
||||
)
|
||||
|
||||
type Bot struct {
|
||||
Role string // gueeser | mime
|
||||
Team string
|
||||
@ -26,15 +35,17 @@ type Bot struct {
|
||||
BotName string
|
||||
log *slog.Logger
|
||||
// channels for communicaton
|
||||
SignalsCh chan bool
|
||||
DoneCh chan bool
|
||||
// channels are not serializable
|
||||
// SignalsCh chan bool
|
||||
// DoneCh chan bool
|
||||
}
|
||||
|
||||
// StartBot
|
||||
func (b *Bot) StartBot() {
|
||||
for {
|
||||
select {
|
||||
case <-b.SignalsCh:
|
||||
case <-SignalChanMap[b.BotName]:
|
||||
b.log.Debug("got signal", "bot-team", b.Team, "bot-role", b.Role)
|
||||
// get room cards and actions
|
||||
room, err := getRoomByID(b.RoomID)
|
||||
if err != nil {
|
||||
@ -53,7 +64,7 @@ func (b *Bot) StartBot() {
|
||||
// if mime -> give clue
|
||||
// if guesser -> open card (does opening one card prompting new loop?)
|
||||
// send notification to sse broker
|
||||
case <-b.DoneCh:
|
||||
case <-DoneChanMap[b.BotName]:
|
||||
b.log.Debug("got done signal", "bot-name", b.BotName)
|
||||
return
|
||||
}
|
||||
@ -69,6 +80,10 @@ func NewBot(role, team, name, roomID string, cfg *config.Config) (*Bot, error) {
|
||||
BotName: name,
|
||||
Team: team,
|
||||
cfg: cfg,
|
||||
log: slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{
|
||||
Level: slog.LevelDebug,
|
||||
AddSource: true,
|
||||
})),
|
||||
}
|
||||
// add to room
|
||||
room, err := getRoomByID(bot.RoomID)
|
||||
@ -108,10 +123,25 @@ func NewBot(role, team, name, roomID string, cfg *config.Config) (*Bot, error) {
|
||||
if err := saveRoom(room); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := saveBot(bot); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
SignalChanMap[bot.BotName] = make(chan bool)
|
||||
DoneChanMap[bot.BotName] = make(chan bool)
|
||||
go bot.StartBot() // run bot routine
|
||||
return bot, nil
|
||||
}
|
||||
|
||||
func saveBot(bot *Bot) error {
|
||||
key := "botkey_" + bot.RoomID + bot.BotName
|
||||
data, err := json.Marshal(bot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cache.MemCache.Set(key, data)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getRoomByID(roomID string) (*models.Room, error) {
|
||||
roomBytes, err := cache.MemCache.Get(models.CacheRoomPrefix + roomID)
|
||||
if err != nil {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golias/utils"
|
||||
"time"
|
||||
|
||||
@ -84,6 +85,7 @@ type Room struct {
|
||||
|
||||
// WhichBotToMove returns bot name that have to move or empty string
|
||||
func (r *Room) WhichBotToMove() string {
|
||||
fmt.Println("looking for bot to move", "team-turn", r.TeamTurn, "mime-done", r.MimeDone, "bot-map", r.BotMap, "is_running", r.IsRunning)
|
||||
if !r.IsRunning {
|
||||
return ""
|
||||
}
|
||||
|
1
todos.md
1
todos.md
@ -7,6 +7,7 @@
|
||||
- login with invite link;
|
||||
- add html icons of whos turn it is (like an image of big ? when mime is thinking);
|
||||
- there two places for bot to check if its its move: start-game; end-turn;
|
||||
- remove bot button (if game is not running);
|
||||
|
||||
#### sse points
|
||||
- clue sse update;
|
||||
|
Reference in New Issue
Block a user