104 lines
2.2 KiB
Go
104 lines
2.2 KiB
Go
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)
|
||
}
|