mirror of
https://github.com/tiennm99/gomoku.git
synced 2026-05-14 02:58:05 +00:00
4c068849c4
Rename - server/database/ → server/lobby/ (17 import sites + qualified references) - Package was named "database" but there is no database — it's in-memory hashmaps for players/rooms/spectators. "lobby" accurately names its role: the multiplayer game lobby state (who is in what room, joining/leaving, spectating). Ratel-online legacy cleanup - Delete server/README.md — 100% Chinese, entirely about ratel card games (斗地主/跑得快/德州扑克/麻将/骗子酒馆/Uno). Zero relevance to gomoku. - Delete server/build.sh + server/build.ps1 — multi-platform ratel-server build scripts with mixed Chinese comments, superseded by Makefile + Dockerfile. - Delete server/docs/ — Chinese Docker deployment guide + quickstart, superseded by root docs/deployment-guide.md and root README.md. - Delete server/demo.gif — ratel card-game demo screenshot. Comment fixes: update "database" references in consts/const.go and game/board.go package docs to point at "lobby" instead. go vet + go test ./... green.
71 lines
2.0 KiB
Go
71 lines
2.0 KiB
Go
package network
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/gorilla/websocket"
|
|
|
|
"github.com/tiennm99/gomoku/server/lobby"
|
|
"github.com/tiennm99/gomoku/server/pkg/log"
|
|
)
|
|
|
|
const (
|
|
// maxMessageSize caps inbound WS frame size at 4 KB.
|
|
// Protobuf game messages are tiny; anything larger is malicious or buggy.
|
|
maxMessageSize = 4 * 1024
|
|
|
|
// readDeadline is the maximum time to wait for a frame before considering
|
|
// the client dead. Clients send heartbeats every ~50 s; 90 s gives headroom.
|
|
readDeadline = 90 * time.Second
|
|
)
|
|
|
|
// readLoop blocks until the connection closes or an unrecoverable read error occurs.
|
|
// It decodes each binary WS frame into a Request and dispatches it.
|
|
// On exit it closes the player's CmdCh and removes them from the store.
|
|
func readLoop(conn *websocket.Conn, player *lobby.Player) {
|
|
conn.SetReadLimit(maxMessageSize)
|
|
_ = conn.SetReadDeadline(time.Now().Add(readDeadline))
|
|
|
|
// Extend deadline on each ping/pong so the 90 s window is per-message, not absolute.
|
|
conn.SetPongHandler(func(string) error {
|
|
return conn.SetReadDeadline(time.Now().Add(readDeadline))
|
|
})
|
|
|
|
defer func() {
|
|
// Signal state machine and writer goroutine that this player is gone.
|
|
if player.CmdCh != nil {
|
|
close(player.CmdCh)
|
|
}
|
|
lobby.RemovePlayer(player.ID)
|
|
log.Infof("[reader] player %d disconnected\n", player.ID)
|
|
}()
|
|
|
|
for {
|
|
msgType, data, err := conn.ReadMessage()
|
|
if err != nil {
|
|
if websocket.IsUnexpectedCloseError(err,
|
|
websocket.CloseGoingAway,
|
|
websocket.CloseNormalClosure,
|
|
websocket.CloseNoStatusReceived) {
|
|
log.Errorf("[reader] player %d read error: %v\n", player.ID, err)
|
|
}
|
|
return
|
|
}
|
|
if msgType != websocket.BinaryMessage {
|
|
log.Errorf("[reader] player %d: unexpected message type %d, dropping\n", player.ID, msgType)
|
|
continue
|
|
}
|
|
|
|
// Reset deadline on any incoming frame (heartbeats count).
|
|
_ = conn.SetReadDeadline(time.Now().Add(readDeadline))
|
|
|
|
req, err := DecodeRequest(data)
|
|
if err != nil {
|
|
log.Errorf("[reader] player %d decode error: %v\n", player.ID, err)
|
|
continue
|
|
}
|
|
|
|
Dispatch(player, req)
|
|
}
|
|
}
|