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) } }