Fix/enable reconnecting to existing games #15
@ -30,7 +30,6 @@ func HostGameHandler(c *gin.Context) {
|
|||||||
passphrase := lobby.Passphrase.String()
|
passphrase := lobby.Passphrase.String()
|
||||||
info := api.PlayerInfo{
|
info := api.PlayerInfo{
|
||||||
PlayerID: &player.Uuid,
|
PlayerID: &player.Uuid,
|
||||||
LobbyID: &lobby.Uuid,
|
|
||||||
Passphrase: &passphrase,
|
Passphrase: &passphrase,
|
||||||
}
|
}
|
||||||
c.Header("Access-Control-Allow-Origin", "*")
|
c.Header("Access-Control-Allow-Origin", "*")
|
||||||
@ -54,15 +53,14 @@ func GetLobbyForPassphraseHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
lobbyInfo := api.LobbyInfo{
|
passphrase := api.Passphrase{
|
||||||
ID: &lobby.Uuid,
|
Value: (*string)(&lobby.Passphrase),
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Header("Access-Control-Allow-Origin", "*")
|
c.Header("Access-Control-Allow-Origin", "*")
|
||||||
c.IndentedJSON(http.StatusOK, lobbyInfo)
|
c.IndentedJSON(http.StatusOK, passphrase)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this will be replaced by the JoinGameHandler()
|
|
||||||
func JoinPrivateGame(c *gin.Context) {
|
func JoinPrivateGame(c *gin.Context) {
|
||||||
limiter.Take()
|
limiter.Take()
|
||||||
|
|
||||||
@ -77,8 +75,7 @@ func JoinPrivateGame(c *gin.Context) {
|
|||||||
|
|
||||||
if req.Passphrase != nil &&
|
if req.Passphrase != nil &&
|
||||||
*req.Passphrase != "" &&
|
*req.Passphrase != "" &&
|
||||||
req.PlayerID != nil &&
|
req.PlayerID != nil { //is reconnect
|
||||||
req.LobbyID != nil { //is reconnect
|
|
||||||
lobby := u.FindExistingPrivateLobby(utils.Passphrase(*req.Passphrase))
|
lobby := u.FindExistingPrivateLobby(utils.Passphrase(*req.Passphrase))
|
||||||
var found bool
|
var found bool
|
||||||
if lobby != nil {
|
if lobby != nil {
|
||||||
@ -90,7 +87,6 @@ func JoinPrivateGame(c *gin.Context) {
|
|||||||
http.StatusOK,
|
http.StatusOK,
|
||||||
api.PlayerInfo{
|
api.PlayerInfo{
|
||||||
PlayerID: req.PlayerID,
|
PlayerID: req.PlayerID,
|
||||||
LobbyID: req.LobbyID,
|
|
||||||
Passphrase: req.Passphrase,
|
Passphrase: req.Passphrase,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@ -114,7 +110,6 @@ func JoinPrivateGame(c *gin.Context) {
|
|||||||
|
|
||||||
info := api.PlayerInfo{
|
info := api.PlayerInfo{
|
||||||
PlayerID: &player.Uuid,
|
PlayerID: &player.Uuid,
|
||||||
LobbyID: &lobby.Uuid,
|
|
||||||
Passphrase: req.Passphrase,
|
Passphrase: req.Passphrase,
|
||||||
}
|
}
|
||||||
c.Header("Access-Control-Allow-Origin", "*")
|
c.Header("Access-Control-Allow-Origin", "*")
|
||||||
@ -124,25 +119,22 @@ func JoinPrivateGame(c *gin.Context) {
|
|||||||
func JoinGameHandler(c *gin.Context) {
|
func JoinGameHandler(c *gin.Context) {
|
||||||
limiter.Take()
|
limiter.Take()
|
||||||
|
|
||||||
id := c.Param("id")
|
passphrase := api.Passphrase{}
|
||||||
idAsUUID, err := uuid.Parse(id)
|
err := c.ShouldBindJSON(&passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.IndentedJSON(http.StatusBadRequest, nil)
|
c.IndentedJSON(http.StatusBadRequest, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
passphrase := api.Passphrase{}
|
|
||||||
c.ShouldBindJSON(&passphrase)
|
|
||||||
|
|
||||||
u := lobbies.GetUsher()
|
u := lobbies.GetUsher()
|
||||||
lobby := u.GetLobbyByID(idAsUUID)
|
lobby := u.FindExistingPrivateLobby(utils.Passphrase(*passphrase.Value))
|
||||||
if lobby == nil {
|
if lobby == nil {
|
||||||
c.IndentedJSON(http.StatusNotFound, nil)
|
c.IndentedJSON(http.StatusNotFound, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
lobbyInfo := api.LobbyInfo{
|
lobbyInfo := api.Passphrase{
|
||||||
ID: &lobby.Uuid,
|
Value: (*string)(&lobby.Passphrase),
|
||||||
}
|
}
|
||||||
|
|
||||||
c.IndentedJSON(http.StatusOK, lobbyInfo)
|
c.IndentedJSON(http.StatusOK, lobbyInfo)
|
||||||
|
@ -9,13 +9,12 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_GetLobbyFromPassphraseHandler(t *testing.T) {
|
func Test_GetLobbyFromPassphraseHandler(t *testing.T) {
|
||||||
var passphraseURLParameter string
|
var passphraseURLParameter string
|
||||||
var hostedLobbyId uuid.UUID
|
var receivedPhrase string
|
||||||
|
|
||||||
t.Run("host a lobby", func(t *testing.T) {
|
t.Run("host a lobby", func(t *testing.T) {
|
||||||
r1 := httptest.NewRecorder()
|
r1 := httptest.NewRecorder()
|
||||||
@ -30,8 +29,7 @@ func Test_GetLobbyFromPassphraseHandler(t *testing.T) {
|
|||||||
err := json.Unmarshal(r1.Body.Bytes(), &playerInfo)
|
err := json.Unmarshal(r1.Body.Bytes(), &playerInfo)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
receivedPhrase := *playerInfo.Passphrase
|
receivedPhrase = *playerInfo.Passphrase
|
||||||
hostedLobbyId = *playerInfo.LobbyID
|
|
||||||
|
|
||||||
passphrase := utils.NewPassphraseFromString(receivedPhrase)
|
passphrase := utils.NewPassphraseFromString(receivedPhrase)
|
||||||
passphraseURLParameter = passphrase.AsURLParam()
|
passphraseURLParameter = passphrase.AsURLParam()
|
||||||
@ -48,10 +46,10 @@ func Test_GetLobbyFromPassphraseHandler(t *testing.T) {
|
|||||||
|
|
||||||
engine.ServeHTTP(r2, getLobbyRequest)
|
engine.ServeHTTP(r2, getLobbyRequest)
|
||||||
|
|
||||||
lobbyInfo := api.LobbyInfo{}
|
passhrase := api.Passphrase{}
|
||||||
err := json.Unmarshal(r2.Body.Bytes(), &lobbyInfo)
|
err := json.Unmarshal(r2.Body.Bytes(), &passhrase)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, hostedLobbyId, *lobbyInfo.ID)
|
assert.Equal(t, http.StatusOK, r2.Code)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"mchess_server/api"
|
"mchess_server/api"
|
||||||
|
"mchess_server/utils"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"mchess_server/lobbies"
|
"mchess_server/lobbies"
|
||||||
@ -23,7 +24,6 @@ var upgrader = gorillaws.Upgrader{
|
|||||||
func RegisterWebSocketConnection(c *gin.Context) {
|
func RegisterWebSocketConnection(c *gin.Context) {
|
||||||
limiter.Take()
|
limiter.Take()
|
||||||
|
|
||||||
log.Println(c.Request)
|
|
||||||
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
@ -55,7 +55,7 @@ func waitForAndHandlePlayerID(ctx context.Context, conn *gorillaws.Conn) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
lobby := lobbies.GetLobbyRegistry().GetLobbyByUUID(*info.LobbyID)
|
lobby := lobbies.GetLobbyRegistry().GetLobbyByPassphrase(utils.NewPassphraseFromString(*info.Passphrase))
|
||||||
if lobby == nil {
|
if lobby == nil {
|
||||||
conn.WriteMessage(msgType, []byte("lobby not found"))
|
conn.WriteMessage(msgType, []byte("lobby not found"))
|
||||||
conn.Close()
|
conn.Close()
|
||||||
@ -68,11 +68,13 @@ func waitForAndHandlePlayerID(ctx context.Context, conn *gorillaws.Conn) {
|
|||||||
conn.Close()
|
conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if player.Conn.HasWebsocketConnection() {
|
|
||||||
player.Conn.Close("closing existing connection")
|
|
||||||
}
|
|
||||||
lobby.Game.SetWebsocketConnectionFor(ctx, player, conn)
|
lobby.Game.SetWebsocketConnectionFor(ctx, player, conn)
|
||||||
log.Println("player after setting connection: ", player)
|
|
||||||
|
log.Println("player after setting connection: ")
|
||||||
|
log.Println("id: ", player.Uuid)
|
||||||
|
log.Println("color: ", player.GetColor())
|
||||||
|
log.Println("Connection: ", player.Conn.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConnectWsForGame(c *gin.Context) {
|
func ConnectWsForGame(c *gin.Context) {
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import "github.com/google/uuid"
|
|
||||||
|
|
||||||
type LobbyInfo struct {
|
|
||||||
ID *uuid.UUID `json:"id,omitempty"`
|
|
||||||
}
|
|
@ -4,6 +4,5 @@ import "github.com/google/uuid"
|
|||||||
|
|
||||||
type PlayerInfo struct {
|
type PlayerInfo struct {
|
||||||
PlayerID *uuid.UUID `json:"playerID,omitempty"`
|
PlayerID *uuid.UUID `json:"playerID,omitempty"`
|
||||||
LobbyID *uuid.UUID `json:"lobbyID,omitempty"`
|
|
||||||
Passphrase *string `json:"passphrase,omitempty"`
|
Passphrase *string `json:"passphrase,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ func (game *Game) Handle() {
|
|||||||
log.Println("Error while reading message:", err)
|
log.Println("Error while reading message:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Println("Player ", game.currentTurnPlayer, " moved:\n", receivedMove)
|
log.Println("Player ", game.currentTurnPlayer.color.String(), " moved:\n", receivedMove)
|
||||||
|
|
||||||
game.gameState = CheckMove
|
game.gameState = CheckMove
|
||||||
case CheckMove:
|
case CheckMove:
|
||||||
@ -117,7 +117,7 @@ func (game *Game) Handle() {
|
|||||||
log.Println("Error marshalling 'colorDetermined' message for player 1", err)
|
log.Println("Error marshalling 'colorDetermined' message for player 1", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
game.currentTurnPlayer.writeMessage(invalidMoveMessage)
|
game.currentTurnPlayer.writeMessage(string(invalidMoveMessage))
|
||||||
game.gameState = PlayerToMove
|
game.gameState = PlayerToMove
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -181,15 +181,16 @@ func (game Game) notifyPlayersAboutGameStart() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
game.GetPlayer1().writeMessage(colorDeterminedPlayer1)
|
game.GetPlayer1().writeMessage(string(colorDeterminedPlayer1))
|
||||||
game.GetPlayer1().SendBoardState(types.Move{}, game.board.PGN(), types.White)
|
game.GetPlayer1().SendBoardState(types.Move{}, game.board.PGN(), types.White)
|
||||||
|
|
||||||
game.GetPlayer2().writeMessage(colorDeterminedPlayer2)
|
game.GetPlayer2().writeMessage(string(colorDeterminedPlayer2))
|
||||||
game.GetPlayer2().SendBoardState(types.Move{}, game.board.PGN(), types.White)
|
game.GetPlayer2().SendBoardState(types.Move{}, game.board.PGN(), types.White)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (game Game) broadcastMove(move types.Move) error {
|
func (game Game) broadcastMove(move types.Move) error {
|
||||||
|
log.Println("broadcast move")
|
||||||
err := game.GetPlayer1().SendBoardState(move, game.board.PGN(), game.currentTurnPlayer.GetColor())
|
err := game.GetPlayer1().SendBoardState(move, game.board.PGN(), game.currentTurnPlayer.GetColor())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -222,3 +223,7 @@ func (game *Game) playerDisconnected(p *Player) {
|
|||||||
func (game *Game) SetWebsocketConnectionFor(ctx context.Context, p *Player, ws *gorillaws.Conn) {
|
func (game *Game) SetWebsocketConnectionFor(ctx context.Context, p *Player, ws *gorillaws.Conn) {
|
||||||
p.SetWebsocketConnectionAndSendBoardState(ctx, ws, &game.board)
|
p.SetWebsocketConnectionAndSendBoardState(ctx, ws, &game.board)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (game *Game) SendBoardStateTo(p *Player) {
|
||||||
|
p.SendBoardState(game.board.getLastMove(), game.board.PGN(), game.board.colorToMove)
|
||||||
|
}
|
||||||
|
@ -36,6 +36,7 @@ func (p Player) hasWebsocketConnection() bool {
|
|||||||
|
|
||||||
func (p *Player) SetWebsocketConnection(ctx context.Context, ws *gorillaws.Conn) {
|
func (p *Player) SetWebsocketConnection(ctx context.Context, ws *gorillaws.Conn) {
|
||||||
p.Conn.SetWebsocketConnection(ws)
|
p.Conn.SetWebsocketConnection(ws)
|
||||||
|
p.Conn.SetForColor(p.color)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) SetWebsocketConnectionAndSendBoardState(
|
func (p *Player) SetWebsocketConnectionAndSendBoardState(
|
||||||
@ -49,6 +50,7 @@ func (p *Player) SetWebsocketConnectionAndSendBoardState(
|
|||||||
|
|
||||||
func (p *Player) SetColor(color types.ChessColor) {
|
func (p *Player) SetColor(color types.ChessColor) {
|
||||||
p.color = color
|
p.color = color
|
||||||
|
p.Conn.SetForColor(p.color)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) GetColor() types.ChessColor {
|
func (p *Player) GetColor() types.ChessColor {
|
||||||
@ -87,11 +89,8 @@ func (p *Player) SendBoardState(move types.Move, boardPosition string, turnColor
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = p.writeMessage(messageToSend)
|
p.writeMessage(string(messageToSend))
|
||||||
if err != nil {
|
|
||||||
log.Println("Error during message writing:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,11 +105,8 @@ func (p *Player) SendMoveAndPosition(move types.Move, boardPosition string) erro
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = p.writeMessage(messageToSend)
|
p.writeMessage(string(messageToSend))
|
||||||
if err != nil {
|
|
||||||
log.Println("Error during message writing:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,26 +120,20 @@ func (p *Player) SendGameEnded(reason GameEndedReason) error {
|
|||||||
log.Println("Error while marshalling: ", err)
|
log.Println("Error while marshalling: ", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = p.writeMessage(messageToSend)
|
p.writeMessage(string(messageToSend))
|
||||||
if err != nil {
|
|
||||||
log.Println("Error during message writing:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) writeMessage(msg []byte) error {
|
func (p *Player) writeMessage(msg string) {
|
||||||
return p.Conn.Write(msg)
|
p.Conn.Write(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) ReadMove() (types.Move, error) {
|
func (p *Player) ReadMove() (types.Move, error) {
|
||||||
receivedMessage, err := p.readMessage()
|
receivedMessage := p.readMessage()
|
||||||
if err != nil {
|
|
||||||
return types.Move{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var msg api.WebsocketMessage
|
var msg api.WebsocketMessage
|
||||||
err = json.Unmarshal(receivedMessage, &msg)
|
err := json.Unmarshal(receivedMessage, &msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.Move{}, err
|
return types.Move{}, err
|
||||||
}
|
}
|
||||||
@ -155,9 +145,9 @@ func (p *Player) ReadMove() (types.Move, error) {
|
|||||||
return *msg.Move, nil
|
return *msg.Move, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) readMessage() ([]byte, error) {
|
func (p *Player) readMessage() []byte {
|
||||||
msg, err := p.Conn.Read()
|
msg := p.Conn.Read()
|
||||||
log.Printf("Reading message: %s from player %s", string(msg), p.Uuid.String())
|
log.Printf("Reading message from %s: %s", p.color.String(), string(msg))
|
||||||
|
|
||||||
return msg, err
|
return msg
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ func (b *MessageBuffer) Insert(msg string) {
|
|||||||
b.cond.Broadcast()
|
b.cond.Broadcast()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *MessageBuffer) Get() (string, error) {
|
func (b *MessageBuffer) Get() string {
|
||||||
b.cond.L.Lock()
|
b.cond.L.Lock()
|
||||||
defer b.cond.L.Unlock()
|
defer b.cond.L.Unlock()
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ func (b *MessageBuffer) Get() (string, error) {
|
|||||||
}
|
}
|
||||||
b.getIndex = b.incrementAndWrapIndex(b.getIndex)
|
b.getIndex = b.incrementAndWrapIndex(b.getIndex)
|
||||||
|
|
||||||
return msg.content, nil
|
return msg.content
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b MessageBuffer) incrementAndWrapIndex(index int) int {
|
func (b MessageBuffer) incrementAndWrapIndex(index int) int {
|
||||||
|
@ -66,8 +66,7 @@ func Test_MessageBuffer_GetWaitsForFirstData(t *testing.T) {
|
|||||||
buf.Insert("delayed-message")
|
buf.Insert("delayed-message")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
msg, err := buf.Get()
|
msg := buf.Get()
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
endTime := time.Now()
|
endTime := time.Now()
|
||||||
|
|
||||||
@ -79,8 +78,7 @@ func Test_MessageBuffer_GetWaitsForNewData(t *testing.T) {
|
|||||||
buf := newMessageBuffer(2)
|
buf := newMessageBuffer(2)
|
||||||
|
|
||||||
buf.Insert("message-1")
|
buf.Insert("message-1")
|
||||||
msg, err := buf.Get()
|
msg := buf.Get()
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, "message-1", msg)
|
assert.Equal(t, "message-1", msg)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -89,8 +87,7 @@ func Test_MessageBuffer_GetWaitsForNewData(t *testing.T) {
|
|||||||
buf.Insert("delayed-message")
|
buf.Insert("delayed-message")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
msg, err = buf.Get()
|
msg = buf.Get()
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, "delayed-message", msg)
|
assert.Equal(t, "delayed-message", msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,8 +114,7 @@ func Test_MessageBuffer_IndexesAreCorrectAfterOverwritingOldData(t *testing.T) {
|
|||||||
},
|
},
|
||||||
buf.messages)
|
buf.messages)
|
||||||
|
|
||||||
msg, err := buf.Get()
|
msg := buf.Get()
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, "message-2", msg)
|
assert.Equal(t, "message-2", msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,13 +122,11 @@ func Test_MessageBuffer_GetWaitsForNewDataIfOldOneWasAlreadyGotten(t *testing.T)
|
|||||||
buf := newMessageBuffer(2)
|
buf := newMessageBuffer(2)
|
||||||
|
|
||||||
buf.Insert(message1)
|
buf.Insert(message1)
|
||||||
msg, err := buf.Get()
|
msg := buf.Get()
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, message1, msg)
|
assert.Equal(t, message1, msg)
|
||||||
|
|
||||||
buf.Insert(message2)
|
buf.Insert(message2)
|
||||||
msg, err = buf.Get()
|
msg = buf.Get()
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, message2, msg)
|
assert.Equal(t, message2, msg)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -140,8 +134,7 @@ func Test_MessageBuffer_GetWaitsForNewDataIfOldOneWasAlreadyGotten(t *testing.T)
|
|||||||
buf.Insert(message3)
|
buf.Insert(message3)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
msg, err = buf.Get()
|
msg = buf.Get()
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, message3, msg)
|
assert.Equal(t, message3, msg)
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -157,9 +150,8 @@ func Test_MessageBuffer_InsertCatchesUpWithRead(t *testing.T) {
|
|||||||
buf.Insert(message6)
|
buf.Insert(message6)
|
||||||
buf.Insert(message7)
|
buf.Insert(message7)
|
||||||
|
|
||||||
msg, err := buf.Get()
|
msg := buf.Get()
|
||||||
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, message3, msg)
|
assert.Equal(t, message3, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +164,7 @@ func Test_MessageBuffer_FuckShitUp(t *testing.T) {
|
|||||||
var readMsg = make([]string, 0)
|
var readMsg = make([]string, 0)
|
||||||
go func() {
|
go func() {
|
||||||
for i := 0; i < size*10; i++ {
|
for i := 0; i < size*10; i++ {
|
||||||
msg, _ := buf.Get()
|
msg := buf.Get()
|
||||||
if msg == "99" {
|
if msg == "99" {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -3,24 +3,27 @@ package connection
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"log"
|
"log"
|
||||||
"sync"
|
"mchess_server/types"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
gorillaws "github.com/gorilla/websocket"
|
gorillaws "github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Connection struct {
|
type Connection struct {
|
||||||
ws *gorillaws.Conn
|
ID uuid.UUID
|
||||||
wsConnectionEstablished chan bool
|
ws *gorillaws.Conn
|
||||||
wsWriteLock sync.Mutex
|
ctx context.Context
|
||||||
ctx context.Context
|
rxBuffer *MessageBuffer
|
||||||
buffer MessageBuffer
|
txBuffer *MessageBuffer
|
||||||
disconnectCallback func()
|
disconnectCallback func()
|
||||||
|
forColor types.ChessColor
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConnection(options ...func(*Connection)) *Connection {
|
func NewConnection(options ...func(*Connection)) *Connection {
|
||||||
connection := Connection{
|
connection := Connection{
|
||||||
buffer: *newMessageBuffer(100),
|
ID: uuid.New(),
|
||||||
wsConnectionEstablished: make(chan bool),
|
rxBuffer: newMessageBuffer(100),
|
||||||
|
txBuffer: newMessageBuffer(100),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
@ -50,6 +53,10 @@ func WithDisconnectCallback(cb func()) func(*Connection) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (conn *Connection) SetForColor(color types.ChessColor) {
|
||||||
|
conn.forColor = color
|
||||||
|
}
|
||||||
|
|
||||||
func (conn *Connection) SetDisconnectCallback(cb func()) {
|
func (conn *Connection) SetDisconnectCallback(cb func()) {
|
||||||
conn.disconnectCallback = cb
|
conn.disconnectCallback = cb
|
||||||
}
|
}
|
||||||
@ -58,63 +65,73 @@ func (conn *Connection) HasWebsocketConnection() bool {
|
|||||||
return conn.ws != nil
|
return conn.ws != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (conn *Connection) readFromRxBuffer() {
|
||||||
|
for {
|
||||||
|
_, msg, err := conn.ws.ReadMessage()
|
||||||
|
if err != nil {
|
||||||
|
conn.logConnection("while reading from websocket: %w", err)
|
||||||
|
conn.Close("")
|
||||||
|
conn.txBuffer.Insert("we do this to make txBuffer.Get() return")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn.rxBuffer.Insert(string(msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *Connection) writeTxBuffer() {
|
||||||
|
for {
|
||||||
|
msg := conn.txBuffer.Get()
|
||||||
|
|
||||||
|
if conn.ws == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := conn.ws.WriteMessage(gorillaws.TextMessage, []byte(msg))
|
||||||
|
if err != nil {
|
||||||
|
conn.logConnection("while writing to websocket: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (conn *Connection) SetWebsocketConnection(ws *gorillaws.Conn) {
|
func (conn *Connection) SetWebsocketConnection(ws *gorillaws.Conn) {
|
||||||
if ws == nil {
|
if ws == nil {
|
||||||
|
conn.logConnection("ERROR: setting ws = null")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.ws = ws
|
conn.ws = ws
|
||||||
|
|
||||||
select {
|
go conn.readFromRxBuffer()
|
||||||
case conn.wsConnectionEstablished <- true:
|
go conn.writeTxBuffer()
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
defer conn.logConnection("websocket connection set")
|
||||||
for {
|
|
||||||
_, msg, err := conn.ws.ReadMessage()
|
|
||||||
if err != nil {
|
|
||||||
log.Println("while reading from websocket: %w", err)
|
|
||||||
|
|
||||||
conn.unsetWebsocketConnection()
|
|
||||||
if conn.disconnectCallback != nil {
|
|
||||||
conn.disconnectCallback()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
conn.buffer.Insert(string(msg))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Connection) unsetWebsocketConnection() {
|
func (conn *Connection) unsetWebsocketConnection() {
|
||||||
|
conn.logConnection("websocket connection unset")
|
||||||
conn.ws = nil
|
conn.ws = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Connection) Write(msg []byte) error {
|
func (conn *Connection) Write(msg string) {
|
||||||
conn.wsWriteLock.Lock()
|
conn.logConnection("Writing message: ", string(msg))
|
||||||
defer conn.wsWriteLock.Unlock()
|
conn.txBuffer.Insert(msg)
|
||||||
|
|
||||||
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.WriteMessage(gorillaws.TextMessage, msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Connection) Read() ([]byte, error) {
|
func (conn *Connection) Read() []byte {
|
||||||
msg, err := conn.buffer.Get()
|
msg := conn.rxBuffer.Get()
|
||||||
if err != nil {
|
|
||||||
conn.ws = nil
|
|
||||||
return nil, err // TODO: Tell game-handler that connection was lost
|
|
||||||
}
|
|
||||||
|
|
||||||
return []byte(msg), err
|
return []byte(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Connection) Close(msg string) {
|
func (conn *Connection) Close(msg string) {
|
||||||
|
conn.logConnection("closing websocket connection")
|
||||||
conn.ws.WriteMessage(gorillaws.TextMessage, []byte(msg))
|
conn.ws.WriteMessage(gorillaws.TextMessage, []byte(msg))
|
||||||
conn.ws.Close()
|
conn.ws.Close()
|
||||||
conn.ws = nil
|
conn.ws = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (con *Connection) logConnection(v ...any) {
|
||||||
|
log.Println("on connection: ", con.ID)
|
||||||
|
log.Println("for color: ", con.forColor.String(), v)
|
||||||
|
}
|
||||||
|
@ -8,17 +8,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Lobby struct {
|
type Lobby struct {
|
||||||
Uuid uuid.UUID
|
Uuid uuid.UUID
|
||||||
Game *chess.Game
|
Game *chess.Game
|
||||||
PlayerJoined chan bool
|
Passphrase utils.Passphrase
|
||||||
Passphrase utils.Passphrase
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEmptyLobbyWithUUID(uuid uuid.UUID) *Lobby {
|
func NewEmptyLobbyWithUUID(uuid uuid.UUID) *Lobby {
|
||||||
return &Lobby{
|
return &Lobby{
|
||||||
Uuid: uuid,
|
Uuid: uuid,
|
||||||
Game: chess.NewGame(),
|
Game: chess.NewGame(),
|
||||||
PlayerJoined: make(chan bool),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type LobbyRegistry struct {
|
type LobbyRegistry struct {
|
||||||
lobbies map[uuid.UUID]*Lobby
|
lobbies map[utils.Passphrase]*Lobby
|
||||||
}
|
}
|
||||||
|
|
||||||
var instance *LobbyRegistry
|
var instance *LobbyRegistry
|
||||||
@ -21,7 +21,7 @@ func GetLobbyRegistry() *LobbyRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newLobbyRegistry() *LobbyRegistry {
|
func newLobbyRegistry() *LobbyRegistry {
|
||||||
return &LobbyRegistry{lobbies: make(map[uuid.UUID]*Lobby)}
|
return &LobbyRegistry{lobbies: make(map[utils.Passphrase]*Lobby)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LobbyRegistry) CreateNewPrivateLobby() *Lobby {
|
func (r *LobbyRegistry) CreateNewPrivateLobby() *Lobby {
|
||||||
@ -42,10 +42,6 @@ func (r *LobbyRegistry) GetLobbyForPlayer() *Lobby {
|
|||||||
return newLobby
|
return newLobby
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LobbyRegistry) GetLobbyByUUID(uuid uuid.UUID) *Lobby {
|
|
||||||
return r.lobbies[uuid]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *LobbyRegistry) GetLobbyByPassphrase(p utils.Passphrase) *Lobby {
|
func (r *LobbyRegistry) GetLobbyByPassphrase(p utils.Passphrase) *Lobby {
|
||||||
for _, lobby := range r.lobbies {
|
for _, lobby := range r.lobbies {
|
||||||
if lobby.Passphrase == p {
|
if lobby.Passphrase == p {
|
||||||
@ -56,6 +52,6 @@ func (r *LobbyRegistry) GetLobbyByPassphrase(p utils.Passphrase) *Lobby {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *LobbyRegistry) addNewLobby(lobby *Lobby) uuid.UUID {
|
func (r *LobbyRegistry) addNewLobby(lobby *Lobby) uuid.UUID {
|
||||||
r.lobbies[lobby.Uuid] = lobby
|
r.lobbies[lobby.Passphrase] = lobby
|
||||||
return lobby.Uuid
|
return lobby.Uuid
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,6 @@ package lobbies
|
|||||||
import (
|
import (
|
||||||
"mchess_server/chess"
|
"mchess_server/chess"
|
||||||
"mchess_server/utils"
|
"mchess_server/utils"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Usher struct {
|
type Usher struct {
|
||||||
@ -24,25 +22,15 @@ func GetUsher() *Usher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *Usher) WelcomeNewPlayer(player *chess.Player) *Lobby {
|
func (u *Usher) WelcomeNewPlayer(player *chess.Player) *Lobby {
|
||||||
lobby := GetLobbyRegistry().GetLobbyForPlayer()
|
return GetLobbyRegistry().GetLobbyForPlayer()
|
||||||
return lobby
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Usher) CreateNewPrivateLobby(player *chess.Player) *Lobby {
|
func (u *Usher) CreateNewPrivateLobby(player *chess.Player) *Lobby {
|
||||||
lobby := GetLobbyRegistry().CreateNewPrivateLobby()
|
return GetLobbyRegistry().CreateNewPrivateLobby()
|
||||||
return lobby
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Usher) FindExistingPrivateLobby(p utils.Passphrase) *Lobby {
|
func (u *Usher) FindExistingPrivateLobby(p utils.Passphrase) *Lobby {
|
||||||
lobby := GetLobbyRegistry().GetLobbyByPassphrase(p)
|
return GetLobbyRegistry().GetLobbyByPassphrase(p)
|
||||||
if lobby == nil || lobby.AreBothPlayersConnected() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return lobby
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Usher) GetLobbyByID(id uuid.UUID) *Lobby {
|
|
||||||
return GetLobbyRegistry().GetLobbyByUUID(id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Usher) AddPlayerToLobbyAndStartGameIfFull(player *chess.Player, lobby *Lobby) {
|
func (u *Usher) AddPlayerToLobbyAndStartGameIfFull(player *chess.Player, lobby *Lobby) {
|
||||||
|
Loading…
Reference in New Issue
Block a user