First changes to move away from central registry of all players

1. Introduce 'usher' that opens lobbies and fills it and waits for them
   to be filled
2. Add global registry of all games
This commit is contained in:
Marco 2023-05-31 23:55:40 +02:00
parent 71ca61f047
commit aac428baab
9 changed files with 138 additions and 13 deletions

View File

@ -1,4 +1,4 @@
package server
package chess
type Move struct {
StartSquare Coordinate `json:"startSquare"`

View File

@ -1,4 +1,4 @@
package server
package chess
import (
"sync"

View File

@ -1,4 +1,4 @@
package server
package chess
import (
"log"

View File

@ -1,4 +1,4 @@
package server
package chess
import (
"context"
@ -14,6 +14,8 @@ type Player struct {
InGame bool
wsConnEstablished chan bool
context context.Context
JoinedLobby chan bool
}
type PlayerInfo struct {
@ -26,6 +28,7 @@ func NewPlayer(uuid uuid.UUID) *Player {
Conn: nil,
InGame: false,
wsConnEstablished: make(chan bool),
JoinedLobby: make(chan bool),
}
}

View File

@ -1,4 +1,4 @@
package server
package chess
import (
"net/http"

33
lobby_registry/lobby.go Normal file
View File

@ -0,0 +1,33 @@
package lobby_registry
import (
"local/m/mchess_server/chess"
"github.com/google/uuid"
)
type Lobby struct {
uuid uuid.UUID
players []*chess.Player
}
func NewEmptyLobbyByUUID(uuid uuid.UUID) *Lobby {
return &Lobby{uuid: uuid}
}
func (w *Lobby) AddPlayer(player *chess.Player) {
w.players = append(w.players, player)
player.JoinedLobby <- true
}
func (w *Lobby) IsFull() bool {
return len(w.players) == 2
}
func (l *Lobby) GetPlayer1() *chess.Player {
return l.players[0]
}
func (l *Lobby) GetPlayer2() *chess.Player {
return l.players[1]
}

View File

@ -0,0 +1,41 @@
package lobby_registry
import (
"github.com/google/uuid"
)
type LobbyRegistry struct {
lobbies map[uuid.UUID]*Lobby
}
var instance *LobbyRegistry
func GetLobbyRegistry() *LobbyRegistry {
if instance == nil {
instance = newLobbyRegistry()
}
return instance
}
func newLobbyRegistry() *LobbyRegistry {
return &LobbyRegistry{lobbies: make(map[uuid.UUID]*Lobby)}
}
func (r *LobbyRegistry) GetLobbyForPlayer() *Lobby {
for _, lobby := range r.lobbies {
if !lobby.IsFull() {
return lobby
}
}
newLobby := NewEmptyLobbyByUUID(uuid.New())
r.addNewLobby(newLobby)
return newLobby
}
func (r *LobbyRegistry) addNewLobby(lobby *Lobby) uuid.UUID {
uuid := uuid.New()
r.lobbies[uuid] = lobby
return uuid
}

25
main.go
View File

@ -2,7 +2,8 @@ package main
import (
"context"
"local/m/mchess_server/server"
"local/m/mchess_server/chess"
"local/m/mchess_server/usher"
"log"
"net/http"
"os"
@ -50,16 +51,21 @@ func registerForRandomGame(c *gin.Context) {
3. Only after a second player joins, respond with player id and game id.
*/
player := server.NewPlayer(uuid.New())
player := chess.NewPlayer(uuid.New())
lobby := server.GetLobby()
lobby.Lock()
server.GetLobby().RegisterPlayer(player)
lobby.Unlock()
usher := usher.GetUsher()
lobby := usher.WelcomeNewPlayer(player)
usher.AddPlayerToLobby(player, lobby)
// Counter point to this approach:
// Waiting for two players might not be necessary.
// Just open the lobby and respond with lobby/game id and player id
// The waiting can be done in the game handler until both players opened a ws connection
usher.WaitForTwoPlayersInLobby(lobby)
log.Println("responding with player id ", player.Uuid)
c.IndentedJSON(http.StatusOK, server.PlayerInfo{
c.IndentedJSON(http.StatusOK, chess.PlayerInfo{
PlayerID: player.Uuid,
})
}
@ -86,7 +92,10 @@ func waitForAndHandlePlayerID(ctx context.Context, conn websocket.Conn) {
return
}
lobby := server.GetLobby()
// since we cannot use the lobby anymore (it does not exist anymore after this change) the client needs to
// send game id and player id so we can make the connection to the player
//lobby := chess.GetLobby()
player, found := lobby.GetPlayer(uuid)
if !found {
conn.Close(websocket.StatusCode(400), "player not found")

39
usher/usher.go Normal file
View File

@ -0,0 +1,39 @@
package usher
import (
"local/m/mchess_server/chess"
lobbies "local/m/mchess_server/lobby_registry"
)
type Usher struct {
}
var instance *Usher
func NewUsher() *Usher {
return &Usher{}
}
func GetUsher() *Usher {
if instance == nil {
instance = NewUsher()
}
return instance
}
func (u *Usher) WelcomeNewPlayer(player *chess.Player) *lobbies.Lobby {
lobby := lobbies.GetLobbyRegistry().GetLobbyForPlayer()
return lobby
}
func (u *Usher) AddPlayerToLobby(player *chess.Player, lobby *lobbies.Lobby) {
lobby.AddPlayer(player)
}
func (u *Usher) WaitForTwoPlayersInLobby(lobby *lobbies.Lobby) {
player1 := lobby.GetPlayer1()
<-player1.JoinedLobby
player2 := lobby.GetPlayer2()
<-player2.JoinedLobby
}