@@ -0,0 +1,167 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/websocket"
|
||||
|
||||
"mrcc/internal/config"
|
||||
"mrcc/internal/httpserver"
|
||||
"mrcc/internal/logger"
|
||||
"mrcc/pkg/response"
|
||||
)
|
||||
|
||||
// === 数据结构骨架(对照开发文档 18.5 节)===
|
||||
|
||||
type RoomStatus string
|
||||
|
||||
const (
|
||||
RoomCreated RoomStatus = "created"
|
||||
RoomWaiting RoomStatus = "waiting"
|
||||
RoomPlaying RoomStatus = "playing"
|
||||
RoomFinished RoomStatus = "finished"
|
||||
)
|
||||
|
||||
// Player 玩家连接
|
||||
type Player struct {
|
||||
UserID string `json:"user_id"`
|
||||
Username string `json:"username"`
|
||||
Conn *websocket.Conn `json:"-"`
|
||||
IsReady bool `json:"is_ready"`
|
||||
JoinedAt time.Time `json:"joined_at"`
|
||||
SendQueue chan []byte `json:"-"`
|
||||
}
|
||||
|
||||
// Room 房间
|
||||
type Room struct {
|
||||
ID string `json:"id"`
|
||||
Status RoomStatus `json:"status"`
|
||||
HostUserID string `json:"host_user_id"`
|
||||
MaxPlayers int `json:"max_players"`
|
||||
Players map[string]*Player `json:"players"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
mu sync.RWMutex `json:"-"`
|
||||
}
|
||||
|
||||
// RelayServer 中转服务器
|
||||
type RelayServer struct {
|
||||
Rooms map[string]*Room
|
||||
Players map[string]*Player
|
||||
Register chan *Player
|
||||
Unregister chan *Player
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func NewRelayServer() *RelayServer {
|
||||
return &RelayServer{
|
||||
Rooms: make(map[string]*Room),
|
||||
Players: make(map[string]*Player),
|
||||
Register: make(chan *Player, 64),
|
||||
Unregister: make(chan *Player, 64),
|
||||
}
|
||||
}
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
return true // 开发阶段允许所有来源
|
||||
},
|
||||
}
|
||||
|
||||
// HandleWS 处理 WebSocket 连接升级
|
||||
func HandleWS(relay *RelayServer) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
userID := c.Query("user_id")
|
||||
if userID == "" {
|
||||
userID = "anonymous"
|
||||
}
|
||||
|
||||
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||
if err != nil {
|
||||
log.Printf("websocket upgrade failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
player := &Player{
|
||||
UserID: userID,
|
||||
Conn: conn,
|
||||
JoinedAt: time.Now(),
|
||||
SendQueue: make(chan []byte, 256),
|
||||
}
|
||||
|
||||
relay.Register <- player
|
||||
|
||||
log.Printf("player connected: %s", userID)
|
||||
|
||||
// TODO: 实现读写 goroutine、房间管理、消息路由、断线重连
|
||||
// 当前骨架仅保持连接并读取消息
|
||||
go func() {
|
||||
defer func() {
|
||||
relay.Unregister <- player
|
||||
conn.Close()
|
||||
}()
|
||||
|
||||
for {
|
||||
_, _, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := config.Load("relay-server", "8086")
|
||||
logger.WithService(cfg.Name).Info("starting relay server", "port", cfg.Port)
|
||||
|
||||
relay := NewRelayServer()
|
||||
|
||||
// 后台处理注册/注销
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case player := <-relay.Register:
|
||||
relay.mu.Lock()
|
||||
relay.Players[player.UserID] = player
|
||||
relay.mu.Unlock()
|
||||
log.Printf("player registered: %s", player.UserID)
|
||||
|
||||
case player := <-relay.Unregister:
|
||||
relay.mu.Lock()
|
||||
delete(relay.Players, player.UserID)
|
||||
relay.mu.Unlock()
|
||||
log.Printf("player unregistered: %s", player.UserID)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
srv := httpserver.New(cfg)
|
||||
|
||||
// WebSocket 端点
|
||||
srv.GET("/ws", HandleWS(relay))
|
||||
|
||||
// 房间信息端点(骨架)
|
||||
srv.GET("/rooms", func(c *gin.Context) {
|
||||
relay.mu.RLock()
|
||||
defer relay.mu.RUnlock()
|
||||
|
||||
rooms := make([]gin.H, 0, len(relay.Rooms))
|
||||
for id, room := range relay.Rooms {
|
||||
rooms = append(rooms, gin.H{
|
||||
"id": id,
|
||||
"status": room.Status,
|
||||
"playerCount": len(room.Players),
|
||||
})
|
||||
}
|
||||
response.OK(c, gin.H{"rooms": rooms, "total": len(rooms)})
|
||||
})
|
||||
|
||||
log.Printf("relay-server listening on %s (WS: /ws)", cfg.Address())
|
||||
if err := srv.Run(cfg.Address()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user