u
This commit is contained in:
1 parent
513a991b57
commit
8f8e8d03c8
22 files changed
+2212
-213
No files matched your search
@@ -0,0 +1,132 @@
|
||||
package ws
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// OnlineUser 在线成员信息
|
||||
type OnlineUser struct {
|
||||
UserID int64 `json:"user_id"`
|
||||
Nickname string `json:"nickname"`
|
||||
Avatar string `json:"avatar"`
|
||||
}
|
||||
|
||||
// Room 按 family_id 分组的聊天室
|
||||
type Room struct {
|
||||
clients map[int64]*Client // user_id → Client
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// Hub 管理所有 Room
|
||||
type Hub struct {
|
||||
rooms map[int64]*Room // family_id → Room
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
var defaultHub = &Hub{
|
||||
rooms: make(map[int64]*Room),
|
||||
}
|
||||
|
||||
func GetHub() *Hub {
|
||||
return defaultHub
|
||||
}
|
||||
|
||||
// getOrCreateRoom 获取或创建 Room
|
||||
func (h *Hub) getOrCreateRoom(familyID int64) *Room {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
|
||||
room, ok := h.rooms[familyID]
|
||||
if !ok {
|
||||
room = &Room{
|
||||
clients: make(map[int64]*Client),
|
||||
}
|
||||
h.rooms[familyID] = room
|
||||
}
|
||||
return room
|
||||
}
|
||||
|
||||
// Join 用户加入房间,广播 online 事件
|
||||
func (h *Hub) Join(familyID int64, client *Client) {
|
||||
room := h.getOrCreateRoom(familyID)
|
||||
|
||||
room.mu.Lock()
|
||||
room.clients[client.userID] = client
|
||||
onlineUsers := h.collectOnlineUsers(room)
|
||||
room.mu.Unlock()
|
||||
|
||||
h.broadcastOnlineUsers(familyID, onlineUsers)
|
||||
}
|
||||
|
||||
// Leave 用户离开房间,广播 offline 事件
|
||||
func (h *Hub) Leave(familyID int64, userID int64) {
|
||||
room := h.getOrCreateRoom(familyID)
|
||||
|
||||
room.mu.Lock()
|
||||
delete(room.clients, userID)
|
||||
onlineUsers := h.collectOnlineUsers(room)
|
||||
room.mu.Unlock()
|
||||
|
||||
// 广播 offline 给房间内其他人
|
||||
msg, _ := json.Marshal(map[string]any{
|
||||
"type": "offline",
|
||||
"user_id": userID,
|
||||
})
|
||||
h.broadcastRaw(familyID, msg)
|
||||
|
||||
// 广播更新后的在线列表
|
||||
h.broadcastOnlineUsers(familyID, onlineUsers)
|
||||
}
|
||||
|
||||
// Broadcast 向房间内所有连接广播消息
|
||||
func (h *Hub) Broadcast(familyID int64, msg any) {
|
||||
data, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
h.broadcastRaw(familyID, data)
|
||||
}
|
||||
|
||||
// broadcastRaw 向房间内所有连接广播原始字节
|
||||
func (h *Hub) broadcastRaw(familyID int64, data []byte) {
|
||||
h.mu.RLock()
|
||||
room, ok := h.rooms[familyID]
|
||||
h.mu.RUnlock()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
room.mu.RLock()
|
||||
defer room.mu.RUnlock()
|
||||
|
||||
for _, client := range room.clients {
|
||||
select {
|
||||
case client.send <- data:
|
||||
default:
|
||||
// 发送通道满则跳过
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// collectOnlineUsers 收集在线用户列表(调用方需持有 room.mu 锁)
|
||||
func (h *Hub) collectOnlineUsers(room *Room) []OnlineUser {
|
||||
users := make([]OnlineUser, 0, len(room.clients))
|
||||
for _, client := range room.clients {
|
||||
users = append(users, OnlineUser{
|
||||
UserID: client.userID,
|
||||
Nickname: client.nickname,
|
||||
Avatar: client.avatar,
|
||||
})
|
||||
}
|
||||
return users
|
||||
}
|
||||
|
||||
// broadcastOnlineUsers 广播在线用户列表
|
||||
func (h *Hub) broadcastOnlineUsers(familyID int64, users []OnlineUser) {
|
||||
msg, _ := json.Marshal(map[string]any{
|
||||
"type": "online",
|
||||
"users": users,
|
||||
})
|
||||
h.broadcastRaw(familyID, msg)
|
||||
}
|
||||
Reference in new issue
Block a user