package wsc import ( "encoding/json" "sync" "github.com/sirupsen/logrus" ) // Room 消息房间,用于业务隔离和群组广播。 type Room struct { name string members map[string]*Session mu sync.RWMutex onEmpty func(name string) // 房间空时回调 } func newRoom(name string) *Room { return &Room{ name: name, members: make(map[string]*Session), } } func (r *Room) Name() string { return r.name } func (r *Room) Len() int { r.mu.RLock() defer r.mu.RUnlock() return len(r.members) } func (r *Room) Join(ctx *Context) { r.mu.Lock() r.members[ctx.SessionID] = ctx.session r.mu.Unlock() } func (r *Room) Leave(ctx *Context) { r.mu.Lock() delete(r.members, ctx.SessionID) empty := len(r.members) == 0 r.mu.Unlock() if empty && r.onEmpty != nil { r.onEmpty(r.name) } } // Broadcast 向房间成员广播 Message(json.Marshal 后发原始字节)。 func (r *Room) Broadcast(excludeSessionID string, msg Message) error { m := map[string]any{"action": msg.Action} if len(msg.Payload) > 0 { // Payload 已是 json.RawMessage,直接复用 m["payload"] = msg.Payload } raw, err := json.Marshal(m) if err != nil { return err } return r.broadcastRaw(excludeSessionID, raw) } // BroadcastRaw 向房间成员广播已序列化的消息(性能优化)。 func (r *Room) BroadcastRaw(excludeSessionID string, data map[string]any) error { raw, err := json.Marshal(data) if err != nil { return err } return r.broadcastRaw(excludeSessionID, raw) } // broadcastRaw 向房间成员发送原始字节(锁外已序列化)。 func (r *Room) broadcastRaw(excludeSessionID string, raw []byte) error { r.mu.RLock() defer r.mu.RUnlock() for id, s := range r.members { if id == excludeSessionID { continue } if err := s.sendRaw(raw); err != nil { logrus.Errorf("[wsc] broadcast send failed: session=%s, err=%v", id[:8], err) } } return nil } // BroadcastAll 向房间所有成员广播。 func (r *Room) BroadcastAll(msg Message) error { return r.Broadcast("", msg) } // SendTo 向房间内指定成员发送消息。 func (r *Room) SendTo(sessionID string, msg Message) error { r.mu.RLock() s, ok := r.members[sessionID] r.mu.RUnlock() if !ok { return nil } return s.writeJSON(msg) }