Fix: notify bot

This commit is contained in:
Grail Finder
2025-05-22 16:47:49 +03:00
parent 31f721cd43
commit c155654d5f
7 changed files with 84 additions and 90 deletions

View File

@ -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 {

View File

@ -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, "")
}

View File

@ -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")

View File

@ -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
}

View File

@ -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 {

View File

@ -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 ""
}

View File

@ -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;