package websocket import ( "fmt" "log" "sync" ) type BroadcastPayload struct { Message *WSMessage } type DirectPayload struct { To string Message *WSMessage } var rooms = make(map[string]*Room) var roomsMutex sync.Mutex func DeleteRoom(roomID string) { roomsMutex.Lock() defer roomsMutex.Unlock() delete(rooms, roomID) log.Printf("房间[%s]已从全局房间管理器删除", roomID) } type Room struct { ID string Connections map[*Connection]bool OnlineUsers map[string]bool Register chan *Connection Unregister chan *Connection Broadcast chan *BroadcastPayload Direct chan *DirectPayload Quit chan struct{} } func NewRoom(id string) *Room { r := &Room{ ID: id, Connections: make(map[*Connection]bool), OnlineUsers: make(map[string]bool), Register: make(chan *Connection), Unregister: make(chan *Connection), Broadcast: make(chan *BroadcastPayload), Direct: make(chan *DirectPayload), Quit: make(chan struct{}), } go r.Run() go func() { <-r.Quit log.Printf("房间[%s]销毁成功", r.ID) DeleteRoom(r.ID) // 从全局管理器删除 }() return r } func (r *Room) Run() { for { select { case conn := <-r.Register: r.Connections[conn] = true r.broadcastRoomInfo() case conn := <-r.Unregister: if _, ok := r.Connections[conn]; ok { delete(r.Connections, conn) close(conn.Send) r.broadcastRoomInfo() if len(r.Connections) == 0 { log.Printf("房间[%s]没人了,准备销毁", r.ID) close(r.Quit) return } } case payload := <-r.Broadcast: for conn := range r.Connections { select { case conn.Send <- payload.Message: default: close(conn.Send) delete(r.Connections, conn) } } case payload := <-r.Direct: for conn := range r.Connections { if conn.UID == payload.To { select { case conn.Send <- payload.Message: default: close(conn.Send) delete(r.Connections, conn) } } } } } } func (r *Room) broadcastRoomInfo() { infoMsg := &WSMessage{ Type: "room_info", Content: fmt.Sprintf("当前房间人数: %d", len(r.Connections)), } for conn := range r.Connections { select { case conn.Send <- infoMsg: default: close(conn.Send) delete(r.Connections, conn) } } }