init: 通用库抽离——httpx/logger/wsc/wscclient/jwtx(合并分叉副本); 顶层包布局; module path git.zeroonesoft.cn/golib/zogo
This commit is contained in:
+103
@@ -0,0 +1,103 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user