Enha: sse update on actions
This commit is contained in:
		| @@ -41,7 +41,7 @@ | |||||||
| 	</style> | 	</style> | ||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
| <div id=ancestor> | <div id="ancestor" hx-ext="sse" sse-connect="/sub/sse"> | ||||||
| 	{{template "main" .}} | 	{{template "main" .}} | ||||||
| </div> | </div> | ||||||
| </body> | </body> | ||||||
|   | |||||||
| @@ -22,7 +22,7 @@ | |||||||
|     color: white; |     color: white; | ||||||
|     text-shadow: 0 2px 4px rgba(0,0,0,0.8); |     text-shadow: 0 2px 4px rgba(0,0,0,0.8); | ||||||
|     cursor: pointer;" |     cursor: pointer;" | ||||||
|     hx-get="/word/show-color?word={{.Word}}" hx-trigger="click" hx-swap="outerHTML transition:true swap:.1s"> |     hx-get="/word/show-color?word={{.Word}}" hx-trigger="click" hx-swap="outerHTML transition:true swap:.05s"> | ||||||
|     {{.Word}} |     {{.Word}} | ||||||
| </div> | </div> | ||||||
| {{end}} | {{end}} | ||||||
|   | |||||||
| @@ -1,8 +1,4 @@ | |||||||
| {{define "main"}} | {{define "main"}} | ||||||
| 	<div hx-ext="sse" sse-connect="/sub/sse" sse-swap="test"> |  | ||||||
| 	    Contents of this box will be updated in real time |  | ||||||
| 	    with every SSE message received from the chatroom. |  | ||||||
| 	</div> |  | ||||||
| 	<!-- user has no username -> login form --> | 	<!-- user has no username -> login form --> | ||||||
| 	{{ if not . }} | 	{{ if not . }} | ||||||
| 	{{template "login"}} | 	{{template "login"}} | ||||||
|   | |||||||
| @@ -1,12 +1,12 @@ | |||||||
| {{define "teamlist"}} | {{define "teamlist"}} | ||||||
| <div class="playerlist border border-gray-300 rounded mb-2"> | <div class="playerlist border border-gray-300 text-{{.Color}}-500 rounded mb-2"> | ||||||
|     <p class=border>Guessers</p> |     <p class=border>Guessers</p> | ||||||
| {{range .Guessers}} | {{range .Guessers}} | ||||||
|     <p>{{.}}</p> |     <p>{{.}}</p> | ||||||
| {{end}} | {{end}} | ||||||
| </div> | </div> | ||||||
| <hr /> | <hr /> | ||||||
| <div class="playerlist border border-gray-300 rounded mb-2"> | <div class="playerlist border border-gray-300 rounded mb-2 text-{{.Color}}-700"> | ||||||
|     <p class=border>Mime</p> |     <p class=border>Mime</p> | ||||||
|     <p>{{.Mime}}</p> |     <p>{{.Mime}}</p> | ||||||
| </div> | </div> | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| {{define "room"}} | {{define "room"}} | ||||||
| <div id="hello-user"> | <div id="interier" hx-get="/" hx-trigger="sse:roomupdate_{{.State.RoomID}}"> | ||||||
|  |   <div id="meta"> | ||||||
|     <p>Hello {{.State.Username}};</p> |     <p>Hello {{.State.Username}};</p> | ||||||
|     <p>Room created by {{.Room.CreatorName}};</p> |     <p>Room created by {{.Room.CreatorName}};</p> | ||||||
|     <p>Game is running: {{.Room.IsRunning}}</p> |     <p>Game is running: {{.Room.IsRunning}}</p> | ||||||
| @@ -8,12 +9,12 @@ | |||||||
|         <button hx-get="/start-game" hx-target="#room" class="bg-amber-100 text-black px-4 py-2 rounded">Start Game</button> |         <button hx-get="/start-game" hx-target="#room" class="bg-amber-100 text-black px-4 py-2 rounded">Start Game</button> | ||||||
|       {{end}} |       {{end}} | ||||||
|     </p> |     </p> | ||||||
|   <p>Turn of the {{.Room.TeamTurn}} team</p> |     <p>Turn of the <span class="text-{{.Room.TeamTurn}}-500">{{.Room.TeamTurn}}</span> team</p> | ||||||
|     <p> |     <p> | ||||||
|       {{if eq .State.Team ""}} |       {{if eq .State.Team ""}} | ||||||
|       join the team! |       join the team! | ||||||
|       {{else}} |       {{else}} | ||||||
|     you're on the team {{.State.Team}}! |       you're on the team <span class="text-{{.State.Team}}-500">{{.State.Team}}</span>! | ||||||
|       {{end}} |       {{end}} | ||||||
|     </p> |     </p> | ||||||
|   </div> |   </div> | ||||||
| @@ -21,11 +22,11 @@ | |||||||
|   <div class="flex justify-center"> |   <div class="flex justify-center"> | ||||||
|     <!-- Left Panel --> |     <!-- Left Panel --> | ||||||
|     {{template "teamlist" .Room.BlueTeam}} |     {{template "teamlist" .Room.BlueTeam}} | ||||||
|   {{if ne .State.Team "blue"}} |     {{if and (ne .State.Team "blue") (not .Room.IsRunning)}} | ||||||
|     {{template "teampew" "blue"}} |     {{template "teampew" "blue"}} | ||||||
|     {{end}} |     {{end}} | ||||||
|     <!-- Right Panel --> |     <!-- Right Panel --> | ||||||
|   {{if ne .State.Team "red"}} |     {{if and (ne .State.Team "red") (not .Room.IsRunning)}} | ||||||
|     {{template "teampew" "red"}} |     {{template "teampew" "red"}} | ||||||
|     {{end}} |     {{end}} | ||||||
|     {{template "teamlist" .Room.RedTeam}} |     {{template "teamlist" .Room.RedTeam}} | ||||||
| @@ -35,10 +36,11 @@ | |||||||
|     {{template "cardtable" .Room}} |     {{template "cardtable" .Room}} | ||||||
|   </div> |   </div> | ||||||
|   <div> |   <div> | ||||||
|   {{if eq .State.Role "guesser"}} |     {{if and (eq .State.Role "guesser") (eq .State.Team .Room.TeamTurn)}} | ||||||
|     <button hx-get="/end-turn" hx-target="#room" class="bg-amber-100 text-black px-4 py-2 rounded">End Turn</button> |     <button hx-get="/end-turn" hx-target="#room" class="bg-amber-100 text-black px-4 py-2 rounded">End Turn</button> | ||||||
|     {{else if eq .State.Role "mime"}} |     {{else if eq .State.Role "mime"}} | ||||||
|     {{template "mimeclue"}} |     {{template "mimeclue"}} | ||||||
|     {{end}} |     {{end}} | ||||||
|   </div> |   </div> | ||||||
|  | </div> | ||||||
| {{end}} | {{end}} | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"errors" | 	"errors" | ||||||
|  | 	"golias/broker" | ||||||
| 	"golias/models" | 	"golias/models" | ||||||
| 	"golias/utils" | 	"golias/utils" | ||||||
| 	"strings" | 	"strings" | ||||||
| @@ -168,6 +169,7 @@ func joinTeam(ctx context.Context, role, team string) (*models.FullInfo, error) | |||||||
| 				return fi, err | 				return fi, err | ||||||
| 			} | 			} | ||||||
| 			fi.Room.BlueTeam.Mime = fi.State.Username | 			fi.Room.BlueTeam.Mime = fi.State.Username | ||||||
|  | 			fi.Room.BlueTeam.Color = "blue" | ||||||
| 			fi.State.Team = "blue" | 			fi.State.Team = "blue" | ||||||
| 			fi.State.Role = "mime" | 			fi.State.Role = "mime" | ||||||
| 			if fi.Room.RedTeam.Mime == fi.State.Username { | 			if fi.Room.RedTeam.Mime == fi.State.Username { | ||||||
| @@ -180,6 +182,7 @@ func joinTeam(ctx context.Context, role, team string) (*models.FullInfo, error) | |||||||
| 				return fi, err | 				return fi, err | ||||||
| 			} | 			} | ||||||
| 			fi.Room.RedTeam.Mime = fi.State.Username | 			fi.Room.RedTeam.Mime = fi.State.Username | ||||||
|  | 			fi.Room.RedTeam.Color = "red" | ||||||
| 			fi.State.Team = "red" | 			fi.State.Team = "red" | ||||||
| 			fi.State.Role = "mime" | 			fi.State.Role = "mime" | ||||||
| 			if fi.Room.BlueTeam.Mime == fi.State.Username { | 			if fi.Room.BlueTeam.Mime == fi.State.Username { | ||||||
| @@ -192,10 +195,12 @@ func joinTeam(ctx context.Context, role, team string) (*models.FullInfo, error) | |||||||
| 	} else if role == "guesser" { | 	} else if role == "guesser" { | ||||||
| 		if team == "blue" { | 		if team == "blue" { | ||||||
| 			fi.Room.BlueTeam.Guessers = append(fi.Room.BlueTeam.Guessers, fi.State.Username) | 			fi.Room.BlueTeam.Guessers = append(fi.Room.BlueTeam.Guessers, fi.State.Username) | ||||||
|  | 			fi.Room.BlueTeam.Color = "blue" | ||||||
| 			fi.State.Team = "blue" | 			fi.State.Team = "blue" | ||||||
| 			fi.State.Role = "guesser" | 			fi.State.Role = "guesser" | ||||||
| 		} else if team == "red" { | 		} else if team == "red" { | ||||||
| 			fi.Room.RedTeam.Guessers = append(fi.Room.RedTeam.Guessers, fi.State.Username) | 			fi.Room.RedTeam.Guessers = append(fi.Room.RedTeam.Guessers, fi.State.Username) | ||||||
|  | 			fi.Room.RedTeam.Color = "red" | ||||||
| 			fi.State.Team = "red" | 			fi.State.Team = "red" | ||||||
| 			fi.State.Role = "guesser" | 			fi.State.Role = "guesser" | ||||||
| 		} else { | 		} else { | ||||||
| @@ -232,3 +237,10 @@ func listPublicRooms() []*models.Room { | |||||||
| 	} | 	} | ||||||
| 	return publicRooms | 	return publicRooms | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func notify(event, msg string) { | ||||||
|  | 	Notifier.Notifier <- broker.NotificationEvent{ | ||||||
|  | 		EventName: event, | ||||||
|  | 		Payload:   msg, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|   | |||||||
| @@ -35,24 +35,23 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) { | |||||||
| 		abortWithError(w, err.Error()) | 		abortWithError(w, err.Error()) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	session, ok := ctx.Value(models.CtxSessionKey).(*models.Session) | 	fi, err := getFullInfoByCtx(ctx) | ||||||
| 	if !ok { |  | ||||||
| 		// trying to get color without a session -> error |  | ||||||
| 		http.Redirect(w, r, "/", 302) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	state, err := loadState(session.Username) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		abortWithError(w, err.Error()) | 		abortWithError(w, err.Error()) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	// TODO: whos move it is? | 	if fi.State.Role != "guesser" { | ||||||
| 	if state.Role != "guesser" { |  | ||||||
| 		err = errors.New("need to guesser to open the card") | 		err = errors.New("need to guesser to open the card") | ||||||
| 		abortWithError(w, err.Error()) | 		abortWithError(w, err.Error()) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	log.Debug("got state", "state", state) | 	// whos move it is? | ||||||
|  | 	if fi.State.Team != models.UserTeam(fi.Room.TeamTurn) { | ||||||
|  | 		err = errors.New("not your team's move") | ||||||
|  | 		abortWithError(w, err.Error()) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	log.Debug("got state", "state", fi) | ||||||
| 	// TODO: update room score | 	// TODO: update room score | ||||||
| 	color, exists := roundWords[word] | 	color, exists := roundWords[word] | ||||||
| 	log.Debug("got show-color request", "word", word, "color", color) | 	log.Debug("got show-color request", "word", word, "color", color) | ||||||
| @@ -65,5 +64,11 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) { | |||||||
| 		Color:    models.StrToWordColor(color), | 		Color:    models.StrToWordColor(color), | ||||||
| 		Revealed: true, | 		Revealed: true, | ||||||
| 	} | 	} | ||||||
|  | 	fi.Room.RevealSpecificWord(word) | ||||||
|  | 	if err := saveFullInfo(fi); err != nil { | ||||||
|  | 		abortWithError(w, err.Error()) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	notify(models.NotifyRoomUpdatePrefix+fi.Room.ID, "") | ||||||
| 	tmpl.ExecuteTemplate(w, "cardword", cardword) | 	tmpl.ExecuteTemplate(w, "cardword", cardword) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -149,6 +149,7 @@ func HandleJoinTeam(w http.ResponseWriter, r *http.Request) { | |||||||
| 		abortWithError(w, err.Error()) | 		abortWithError(w, err.Error()) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | 	notify(models.NotifyRoomUpdatePrefix+fi.Room.ID, "") | ||||||
| 	tmpl.ExecuteTemplate(w, "base", fi) | 	tmpl.ExecuteTemplate(w, "base", fi) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -176,6 +177,7 @@ func HandleEndTurn(w http.ResponseWriter, r *http.Request) { | |||||||
| 		abortWithError(w, err.Error()) | 		abortWithError(w, err.Error()) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | 	notify(models.NotifyRoomUpdatePrefix+fi.Room.ID, "") | ||||||
| 	tmpl.ExecuteTemplate(w, "base", fi) | 	tmpl.ExecuteTemplate(w, "base", fi) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -204,6 +206,8 @@ func HandleStartGame(w http.ResponseWriter, r *http.Request) { | |||||||
| 		abortWithError(w, err.Error()) | 		abortWithError(w, err.Error()) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | 	// to update only the room that should be updated | ||||||
|  | 	notify(models.NotifyRoomUpdatePrefix+fi.Room.ID, "") | ||||||
| 	tmpl.ExecuteTemplate(w, "room", fi) | 	tmpl.ExecuteTemplate(w, "room", fi) | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
| package handlers | package handlers | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" |  | ||||||
| 	"golias/broker" | 	"golias/broker" | ||||||
| 	"golias/config" | 	"golias/config" | ||||||
| 	"golias/pkg/cache" | 	"golias/pkg/cache" | ||||||
| @@ -9,7 +8,6 @@ import ( | |||||||
| 	"log/slog" | 	"log/slog" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"os" | 	"os" | ||||||
| 	"time" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| @@ -28,18 +26,6 @@ func init() { | |||||||
| 	cfg = config.LoadConfigOrDefault("") | 	cfg = config.LoadConfigOrDefault("") | ||||||
| 	Notifier = broker.NewBroker() | 	Notifier = broker.NewBroker() | ||||||
| 	go Notifier.Listen() | 	go Notifier.Listen() | ||||||
| 	ticker := time.NewTicker(2 * time.Second) |  | ||||||
| 	go func() { |  | ||||||
| 		counter := 0 |  | ||||||
| 		for { |  | ||||||
| 			<-ticker.C |  | ||||||
| 			Notifier.Notifier <- broker.NotificationEvent{ |  | ||||||
| 				EventName: "test", |  | ||||||
| 				Payload:   fmt.Sprintf("%v test call of notifier", counter), |  | ||||||
| 			} |  | ||||||
| 			counter++ |  | ||||||
| 		} |  | ||||||
| 	}() |  | ||||||
| } | } | ||||||
|  |  | ||||||
| var roundWords = map[string]string{ | var roundWords = map[string]string{ | ||||||
|   | |||||||
| @@ -7,4 +7,6 @@ var ( | |||||||
| 	// cache | 	// cache | ||||||
| 	CacheRoomPrefix  = "room#" | 	CacheRoomPrefix  = "room#" | ||||||
| 	CacheStatePrefix = "state-" | 	CacheStatePrefix = "state-" | ||||||
|  | 	// sse | ||||||
|  | 	NotifyRoomUpdatePrefix = "roomupdate_" | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -34,6 +34,7 @@ func StrToWordColor(s string) WordColor { | |||||||
| type Team struct { | type Team struct { | ||||||
| 	Guessers []string | 	Guessers []string | ||||||
| 	Mime     string | 	Mime     string | ||||||
|  | 	Color    string | ||||||
| } | } | ||||||
|  |  | ||||||
| type Room struct { | type Room struct { | ||||||
| @@ -109,6 +110,14 @@ func (r *Room) RevealAllCards() { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (r *Room) RevealSpecificWord(word string) { | ||||||
|  | 	for i, card := range r.Cards { | ||||||
|  | 		if card.Word == word { | ||||||
|  | 			r.Cards[i].Revealed = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| type WordCard struct { | type WordCard struct { | ||||||
| 	Word     string | 	Word     string | ||||||
| 	Color    WordColor | 	Color    WordColor | ||||||
|   | |||||||
| @@ -75,8 +75,8 @@ func MakeTestState(creatorName string) *FullInfo { | |||||||
| 		{Word: "tomato", Color: "red"}, | 		{Word: "tomato", Color: "red"}, | ||||||
| 		{Word: "cloud", Color: "white"}, | 		{Word: "cloud", Color: "white"}, | ||||||
| 	} | 	} | ||||||
| 	redTeam := Team{Guessers: []string{"Adam", "Eve"}, Mime: "Serpent"} | 	redTeam := Team{Guessers: []string{"Adam", "Eve"}, Mime: "Serpent", Color: "red"} | ||||||
| 	blueTeam := Team{Guessers: []string{"Abel", "Kain"}} | 	blueTeam := Team{Guessers: []string{"Abel", "Kain"}, Color: "blue"} | ||||||
| 	room := &Room{ | 	room := &Room{ | ||||||
| 		ID:          "test-id", | 		ID:          "test-id", | ||||||
| 		CreatedAt:   time.Now(), | 		CreatedAt:   time.Now(), | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Grail Finder
					Grail Finder