Change websocket handling
With this commit, we stop waiting for the websocket connection to be established before the game starts. Now, the Connection type is responsible for waiting for the websocket connection before writing.
This commit is contained in:
parent
f20c4ae586
commit
917c97766d
@ -2,9 +2,9 @@ package chess
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
"math/rand"
|
||||||
"mchess_server/api"
|
"mchess_server/api"
|
||||||
"mchess_server/types"
|
"mchess_server/types"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
@ -29,7 +29,7 @@ func NewGame() *Game {
|
|||||||
var game = Game{
|
var game = Game{
|
||||||
id: uuid.New(),
|
id: uuid.New(),
|
||||||
board: newBoard(),
|
board: newBoard(),
|
||||||
gameState: PlayerToMove,
|
gameState: Init,
|
||||||
}
|
}
|
||||||
game.board.Init()
|
game.board.Init()
|
||||||
|
|
||||||
@ -44,15 +44,18 @@ func (game Game) GetPlayer1() *Player {
|
|||||||
return game.players[0]
|
return game.players[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (game Game) GetRandomPlayer() *Player {
|
||||||
|
index := rand.Int() % 2
|
||||||
|
return game.players[index]
|
||||||
|
}
|
||||||
|
|
||||||
func (game Game) GetPlayer2() *Player {
|
func (game Game) GetPlayer2() *Player {
|
||||||
return game.players[1]
|
return game.players[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (game *Game) prepare() {
|
func (game *Game) prepare() {
|
||||||
ok := game.waitForWebsocketConnections()
|
game.players[0].color = types.White
|
||||||
if !ok {
|
game.players[1].color = types.Black
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err := game.notifyPlayersAboutGameStart()
|
err := game.notifyPlayersAboutGameStart()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -78,10 +81,14 @@ func (game *Game) Handle() {
|
|||||||
switch game.gameState {
|
switch game.gameState {
|
||||||
case Init:
|
case Init:
|
||||||
game.currentTurnPlayer = game.GetPlayer1()
|
game.currentTurnPlayer = game.GetPlayer1()
|
||||||
|
game.gameState = Prepare
|
||||||
|
|
||||||
case Prepare:
|
case Prepare:
|
||||||
game.prepare()
|
game.prepare()
|
||||||
|
game.gameState = PlayerToMove
|
||||||
|
|
||||||
case PlayerToMove:
|
case PlayerToMove:
|
||||||
log.Println("with player ", game.currentTurnPlayer, " to move")
|
log.Println("with ", game.currentTurnPlayer.GetPlayerColor(), " to move")
|
||||||
receivedMove, err = game.currentTurnPlayer.ReadMove()
|
receivedMove, err = game.currentTurnPlayer.ReadMove()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error while reading message:", err)
|
log.Println("Error while reading message:", err)
|
||||||
@ -131,25 +138,6 @@ func (game *Game) killGame() {
|
|||||||
log.Println("Game should be killed")
|
log.Println("Game should be killed")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (game *Game) waitForWebsocketConnections() bool {
|
|
||||||
timer := time.NewTimer(5 * time.Second)
|
|
||||||
numberOfConnections := 0
|
|
||||||
waitingForPlayers := make(chan bool)
|
|
||||||
|
|
||||||
go game.GetPlayer1().WaitForWebsocketConnection(waitingForPlayers)
|
|
||||||
go game.GetPlayer2().WaitForWebsocketConnection(waitingForPlayers)
|
|
||||||
|
|
||||||
for numberOfConnections < 2 {
|
|
||||||
select {
|
|
||||||
case <-waitingForPlayers:
|
|
||||||
numberOfConnections++
|
|
||||||
case <-timer.C:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (game Game) notifyPlayersAboutGameStart() error {
|
func (game Game) notifyPlayersAboutGameStart() error {
|
||||||
colorDeterminedPlayer1, err := api.GetColorDeterminedMessage(types.White)
|
colorDeterminedPlayer1, err := api.GetColorDeterminedMessage(types.White)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -8,34 +8,32 @@ import (
|
|||||||
"mchess_server/api"
|
"mchess_server/api"
|
||||||
conn "mchess_server/connection"
|
conn "mchess_server/connection"
|
||||||
"mchess_server/types"
|
"mchess_server/types"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"nhooyr.io/websocket"
|
"nhooyr.io/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Player struct {
|
type Player struct {
|
||||||
Uuid uuid.UUID
|
Uuid uuid.UUID
|
||||||
Conn *conn.Connection
|
Conn *conn.Connection
|
||||||
InGame bool
|
InGame bool
|
||||||
wsConnEstablished chan bool
|
color types.ChessColor
|
||||||
context context.Context
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPlayer(uuid uuid.UUID) *Player {
|
func NewPlayer(uuid uuid.UUID) *Player {
|
||||||
return &Player{
|
return &Player{
|
||||||
Uuid: uuid,
|
Uuid: uuid,
|
||||||
Conn: nil,
|
Conn: conn.NewConnection(conn.WithContext(context.Background())),
|
||||||
InGame: false,
|
InGame: false,
|
||||||
wsConnEstablished: make(chan bool),
|
|
||||||
context: context.Background(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) SetConnection(ctx context.Context, ws *websocket.Conn) {
|
func (p Player) HasWebsocketConnection() bool {
|
||||||
p.Conn = conn.NewConnection(conn.WithWebsocket(ws), conn.WithContext(p.context))
|
return p.Conn.HasWebsocketConnection()
|
||||||
p.context = ctx
|
}
|
||||||
p.wsConnEstablished <- true
|
|
||||||
|
func (p *Player) SetWebsocketConnection(ctx context.Context, ws *websocket.Conn) {
|
||||||
|
p.Conn.SetWebsocketConnection(ws)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) SendMoveAndPosition(move types.Move, boardPosition string) error {
|
func (p *Player) SendMoveAndPosition(move types.Move, boardPosition string) error {
|
||||||
@ -58,9 +56,7 @@ func (p *Player) SendMoveAndPosition(move types.Move, boardPosition string) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) writeMessage(msg []byte) error {
|
func (p *Player) writeMessage(msg []byte) error {
|
||||||
log.Printf("Writing message: %s to player %s", string(msg), p.Uuid.String())
|
return p.Conn.Write(msg)
|
||||||
|
|
||||||
return p.Conn.Write(p.context, msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) ReadMove() (types.Move, error) {
|
func (p *Player) ReadMove() (types.Move, error) {
|
||||||
@ -83,19 +79,12 @@ func (p *Player) ReadMove() (types.Move, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) readMessage() ([]byte, error) {
|
func (p *Player) readMessage() ([]byte, error) {
|
||||||
msg, err := p.Conn.Read(p.context)
|
msg, err := p.Conn.Read()
|
||||||
log.Printf("Reading message: %s from player %s", string(msg), p.Uuid.String())
|
log.Printf("Reading message: %s from player %s", string(msg), p.Uuid.String())
|
||||||
|
|
||||||
return msg, err
|
return msg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) WaitForWebsocketConnection(c chan bool) {
|
func (p Player) GetPlayerColor() string {
|
||||||
timer := time.NewTimer(5 * time.Second)
|
return string(p.color)
|
||||||
|
|
||||||
select {
|
|
||||||
case <-p.wsConnEstablished:
|
|
||||||
c <- true
|
|
||||||
case <-timer.C:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,34 +2,30 @@ package connection
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"log"
|
||||||
|
|
||||||
"nhooyr.io/websocket"
|
"nhooyr.io/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Connection struct {
|
type Connection struct {
|
||||||
ws *websocket.Conn
|
ws *websocket.Conn
|
||||||
ctx context.Context
|
wsConnectionEstablished chan bool
|
||||||
buffer MessageBuffer
|
ctx context.Context
|
||||||
|
buffer MessageBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var dbg_index int
|
||||||
|
|
||||||
func NewConnection(options ...func(*Connection)) *Connection {
|
func NewConnection(options ...func(*Connection)) *Connection {
|
||||||
connection := Connection{
|
connection := Connection{
|
||||||
buffer: *newMessageBuffer(100),
|
buffer: *newMessageBuffer(100),
|
||||||
|
wsConnectionEstablished: make(chan bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
option(&connection)
|
option(&connection)
|
||||||
}
|
}
|
||||||
|
|
||||||
if connection.ws != nil {
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
_, msg, _ := connection.ws.Read(connection.ctx)
|
|
||||||
connection.buffer.Insert(string(msg))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
return &connection
|
return &connection
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,13 +41,43 @@ func WithContext(ctx context.Context) func(*Connection) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Connection) Write(ctx context.Context, msg []byte) error {
|
func (conn *Connection) HasWebsocketConnection() bool {
|
||||||
return conn.ws.Write(ctx, websocket.MessageText, msg)
|
return conn.ws != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Connection) Read(ctx context.Context) ([]byte, error) {
|
func (conn *Connection) SetWebsocketConnection(ws *websocket.Conn) {
|
||||||
|
if ws == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.ws = ws
|
||||||
|
|
||||||
|
select {
|
||||||
|
case conn.wsConnectionEstablished <- true:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
_, msg, _ := conn.ws.Read(conn.ctx)
|
||||||
|
conn.buffer.Insert(string(msg))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *Connection) Write(msg []byte) error {
|
||||||
|
if conn.ws == nil { //if ws is not yet set, we wait for it
|
||||||
|
<-conn.wsConnectionEstablished
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Writing message: %s", string(msg))
|
||||||
|
return conn.ws.Write(conn.ctx, websocket.MessageText, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *Connection) Read() ([]byte, error) {
|
||||||
msg, err := conn.buffer.Get()
|
msg, err := conn.buffer.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
conn.ws = nil
|
||||||
return nil, err // Tell game-handler that connection was lost
|
return nil, err // Tell game-handler that connection was lost
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,4 +86,5 @@ func (conn *Connection) Read(ctx context.Context) ([]byte, error) {
|
|||||||
|
|
||||||
func (conn *Connection) Close(msg string) {
|
func (conn *Connection) Close(msg string) {
|
||||||
conn.ws.Close(websocket.StatusCode(400), msg)
|
conn.ws.Close(websocket.StatusCode(400), msg)
|
||||||
|
conn.ws = nil
|
||||||
}
|
}
|
||||||
|
10
main.go
10
main.go
@ -137,7 +137,7 @@ func waitForAndHandlePlayerID(ctx context.Context, conn *websocket.Conn) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("read from websocket: ", msgType, string(msg), err)
|
log.Println("read from websocket endpoint: ", msgType, string(msg), err)
|
||||||
|
|
||||||
var info api.PlayerInfo
|
var info api.PlayerInfo
|
||||||
err = json.Unmarshal(msg, &info)
|
err = json.Unmarshal(msg, &info)
|
||||||
@ -149,14 +149,18 @@ func waitForAndHandlePlayerID(ctx context.Context, conn *websocket.Conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lobby := lobbies.GetLobbyRegistry().GetLobbyByUUID(*info.LobbyID)
|
lobby := lobbies.GetLobbyRegistry().GetLobbyByUUID(*info.LobbyID)
|
||||||
|
if lobby == nil {
|
||||||
|
conn.Close(websocket.StatusCode(400), "lobby not found")
|
||||||
|
}
|
||||||
|
|
||||||
player, found := lobby.GetPlayerByUUID(*info.PlayerID)
|
player, found := lobby.GetPlayerByUUID(*info.PlayerID)
|
||||||
if !found {
|
if !found {
|
||||||
conn.Close(websocket.StatusCode(400), "player not found")
|
conn.Close(websocket.StatusCode(400), "player not found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if player.Conn != nil {
|
if player.Conn.HasWebsocketConnection() {
|
||||||
player.Conn.Close("closing existing connection")
|
player.Conn.Close("closing existing connection")
|
||||||
}
|
}
|
||||||
player.SetConnection(ctx, conn)
|
player.SetWebsocketConnection(ctx, conn)
|
||||||
log.Println("player after setting connection: ", player)
|
log.Println("player after setting connection: ", player)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user