Compare commits
3 Commits
fcd3e32edf
...
917c97766d
Author | SHA1 | Date | |
---|---|---|---|
917c97766d | |||
f20c4ae586 | |||
9803ecad6f |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
mchess_server
|
@ -2,9 +2,9 @@ package chess
|
||||
|
||||
import (
|
||||
"log"
|
||||
"math/rand"
|
||||
"mchess_server/api"
|
||||
"mchess_server/types"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
@ -18,7 +18,9 @@ type Game struct {
|
||||
}
|
||||
|
||||
const (
|
||||
PlayerToMove = iota
|
||||
Init = iota
|
||||
Prepare
|
||||
PlayerToMove
|
||||
CheckMove
|
||||
CheckPlayerChange
|
||||
)
|
||||
@ -27,7 +29,7 @@ func NewGame() *Game {
|
||||
var game = Game{
|
||||
id: uuid.New(),
|
||||
board: newBoard(),
|
||||
gameState: PlayerToMove,
|
||||
gameState: Init,
|
||||
}
|
||||
game.board.Init()
|
||||
|
||||
@ -42,17 +44,18 @@ func (game Game) GetPlayer1() *Player {
|
||||
return game.players[0]
|
||||
}
|
||||
|
||||
func (game Game) GetRandomPlayer() *Player {
|
||||
index := rand.Int() % 2
|
||||
return game.players[index]
|
||||
}
|
||||
|
||||
func (game Game) GetPlayer2() *Player {
|
||||
return game.players[1]
|
||||
}
|
||||
|
||||
func (game *Game) prepare() {
|
||||
game.currentTurnPlayer = game.GetPlayer1()
|
||||
|
||||
ok := game.waitForWebsocketConnections()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
game.players[0].color = types.White
|
||||
game.players[1].color = types.Black
|
||||
|
||||
err := game.notifyPlayersAboutGameStart()
|
||||
if err != nil {
|
||||
@ -60,18 +63,32 @@ func (game *Game) prepare() {
|
||||
}
|
||||
}
|
||||
|
||||
//CHANGES:
|
||||
/*
|
||||
Do not wait for the players websocket connection before the game.
|
||||
Let Connection do it.
|
||||
Then here in game handler, just read from Connection (aka messagebuffer) and when data arrives, we read it
|
||||
Question: how do we handle connection losses, should game handler observe state of connection and send a notification to the other player when one player is disconnected
|
||||
Question: How would reconnect work in this scenario?
|
||||
*/
|
||||
func (game *Game) Handle() {
|
||||
defer game.killGame()
|
||||
|
||||
game.prepare()
|
||||
|
||||
var receivedMove types.Move
|
||||
var err error
|
||||
|
||||
for {
|
||||
switch game.gameState {
|
||||
case Init:
|
||||
game.currentTurnPlayer = game.GetPlayer1()
|
||||
game.gameState = Prepare
|
||||
|
||||
case Prepare:
|
||||
game.prepare()
|
||||
game.gameState = PlayerToMove
|
||||
|
||||
case PlayerToMove:
|
||||
log.Println("with player ", game.currentTurnPlayer, " to move")
|
||||
log.Println("with ", game.currentTurnPlayer.GetPlayerColor(), " to move")
|
||||
receivedMove, err = game.currentTurnPlayer.ReadMove()
|
||||
if err != nil {
|
||||
log.Println("Error while reading message:", err)
|
||||
@ -121,25 +138,6 @@ func (game *Game) killGame() {
|
||||
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 {
|
||||
colorDeterminedPlayer1, err := api.GetColorDeterminedMessage(types.White)
|
||||
if err != nil {
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"mchess_server/api"
|
||||
conn "mchess_server/connection"
|
||||
"mchess_server/types"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"nhooyr.io/websocket"
|
||||
@ -18,24 +17,23 @@ type Player struct {
|
||||
Uuid uuid.UUID
|
||||
Conn *conn.Connection
|
||||
InGame bool
|
||||
wsConnEstablished chan bool
|
||||
context context.Context
|
||||
color types.ChessColor
|
||||
}
|
||||
|
||||
func NewPlayer(uuid uuid.UUID) *Player {
|
||||
return &Player{
|
||||
Uuid: uuid,
|
||||
Conn: nil,
|
||||
Conn: conn.NewConnection(conn.WithContext(context.Background())),
|
||||
InGame: false,
|
||||
wsConnEstablished: make(chan bool),
|
||||
context: context.Background(),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Player) SetConnection(ctx context.Context, ws *websocket.Conn) {
|
||||
p.Conn = conn.NewConnection(conn.WithWebsocket(ws), conn.WithContext(p.context))
|
||||
p.context = ctx
|
||||
p.wsConnEstablished <- true
|
||||
func (p Player) HasWebsocketConnection() bool {
|
||||
return p.Conn.HasWebsocketConnection()
|
||||
}
|
||||
|
||||
func (p *Player) SetWebsocketConnection(ctx context.Context, ws *websocket.Conn) {
|
||||
p.Conn.SetWebsocketConnection(ws)
|
||||
}
|
||||
|
||||
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 {
|
||||
log.Printf("Writing message: %s to player %s", string(msg), p.Uuid.String())
|
||||
|
||||
return p.Conn.Write(p.context, msg)
|
||||
return p.Conn.Write(msg)
|
||||
}
|
||||
|
||||
func (p *Player) ReadMove() (types.Move, error) {
|
||||
@ -83,19 +79,12 @@ func (p *Player) ReadMove() (types.Move, 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())
|
||||
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func (p *Player) WaitForWebsocketConnection(c chan bool) {
|
||||
timer := time.NewTimer(5 * time.Second)
|
||||
|
||||
select {
|
||||
case <-p.wsConnEstablished:
|
||||
c <- true
|
||||
case <-timer.C:
|
||||
return
|
||||
}
|
||||
func (p Player) GetPlayerColor() string {
|
||||
return string(p.color)
|
||||
}
|
||||
|
@ -18,8 +18,7 @@ type message struct {
|
||||
}
|
||||
|
||||
func newMessageBuffer(size int) *MessageBuffer {
|
||||
mutex := &sync.Mutex{}
|
||||
cond := sync.NewCond(mutex)
|
||||
cond := sync.NewCond(&sync.Mutex{})
|
||||
|
||||
return &MessageBuffer{
|
||||
messages: make([]message, size),
|
||||
|
@ -2,34 +2,30 @@ package connection
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"nhooyr.io/websocket"
|
||||
)
|
||||
|
||||
type Connection struct {
|
||||
ws *websocket.Conn
|
||||
wsConnectionEstablished chan bool
|
||||
ctx context.Context
|
||||
buffer MessageBuffer
|
||||
}
|
||||
|
||||
var dbg_index int
|
||||
|
||||
func NewConnection(options ...func(*Connection)) *Connection {
|
||||
connection := Connection{
|
||||
buffer: *newMessageBuffer(100),
|
||||
wsConnectionEstablished: make(chan bool),
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(&connection)
|
||||
}
|
||||
|
||||
if connection.ws != nil {
|
||||
go func() {
|
||||
for {
|
||||
_, msg, _ := connection.ws.Read(connection.ctx)
|
||||
connection.buffer.Insert(string(msg))
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
return &connection
|
||||
}
|
||||
|
||||
@ -45,13 +41,43 @@ func WithContext(ctx context.Context) func(*Connection) {
|
||||
}
|
||||
}
|
||||
|
||||
func (conn *Connection) Write(ctx context.Context, msg []byte) error {
|
||||
return conn.ws.Write(ctx, websocket.MessageText, msg)
|
||||
func (conn *Connection) HasWebsocketConnection() bool {
|
||||
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()
|
||||
if err != nil {
|
||||
conn.ws = nil
|
||||
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) {
|
||||
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
|
||||
}
|
||||
|
||||
log.Println("read from websocket: ", msgType, string(msg), err)
|
||||
log.Println("read from websocket endpoint: ", msgType, string(msg), err)
|
||||
|
||||
var info api.PlayerInfo
|
||||
err = json.Unmarshal(msg, &info)
|
||||
@ -149,14 +149,18 @@ func waitForAndHandlePlayerID(ctx context.Context, conn *websocket.Conn) {
|
||||
}
|
||||
|
||||
lobby := lobbies.GetLobbyRegistry().GetLobbyByUUID(*info.LobbyID)
|
||||
if lobby == nil {
|
||||
conn.Close(websocket.StatusCode(400), "lobby not found")
|
||||
}
|
||||
|
||||
player, found := lobby.GetPlayerByUUID(*info.PlayerID)
|
||||
if !found {
|
||||
conn.Close(websocket.StatusCode(400), "player not found")
|
||||
return
|
||||
}
|
||||
if player.Conn != nil {
|
||||
if player.Conn.HasWebsocketConnection() {
|
||||
player.Conn.Close("closing existing connection")
|
||||
}
|
||||
player.SetConnection(ctx, conn)
|
||||
player.SetWebsocketConnection(ctx, conn)
|
||||
log.Println("player after setting connection: ", player)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user