feat(call): enhance call handling with user connection events and active call management
- Updated CallService to handle user connection and disconnection events, allowing for automatic management of active calls based on user status. - Introduced methods to retrieve active calls for users and send pending call invites when users reconnect. - Modified the Invite method to return the callee's online status, improving user experience during call invitations. - Enhanced WSHandler to support connection and disconnection event handlers, ensuring accurate call state management.
This commit is contained in:
@@ -61,22 +61,36 @@ type subscriber struct {
|
||||
quit chan struct{}
|
||||
}
|
||||
|
||||
// DisconnectHandler 用户断开连接时的回调函数
|
||||
// userID: 断开的用户ID
|
||||
// remainingCount: 该用户剩余的连接数(0表示用户完全离线)
|
||||
type DisconnectHandler func(userID string, remainingCount int)
|
||||
|
||||
// ConnectHandler 用户连接时的回调函数
|
||||
// userID: 连接的用户ID
|
||||
// isFirstConnection: 是否是该用户的第一个连接(之前完全离线)
|
||||
type ConnectHandler func(userID string, isFirstConnection bool)
|
||||
|
||||
// Hub WebSocket连接管理器
|
||||
type Hub struct {
|
||||
seq uint64
|
||||
|
||||
mu sync.RWMutex
|
||||
clients map[string]map[uint64]*Client // userID -> clientID -> Client
|
||||
history map[string][]Event // userID -> []Event (用于断线重连历史回放)
|
||||
subscribers map[string]map[uint64]*subscriber // userID -> subscriberID -> subscriber
|
||||
mu sync.RWMutex
|
||||
clients map[string]map[uint64]*Client // userID -> clientID -> Client
|
||||
history map[string][]Event // userID -> []Event (用于断线重连历史回放)
|
||||
subscribers map[string]map[uint64]*subscriber // userID -> subscriberID -> subscriber
|
||||
disconnectHandlers []DisconnectHandler // 断开连接事件处理器列表
|
||||
connectHandlers []ConnectHandler // 连接事件处理器列表
|
||||
}
|
||||
|
||||
// NewHub 创建WebSocket Hub
|
||||
func NewHub() *Hub {
|
||||
return &Hub{
|
||||
clients: make(map[string]map[uint64]*Client),
|
||||
history: make(map[string][]Event),
|
||||
subscribers: make(map[string]map[uint64]*subscriber),
|
||||
clients: make(map[string]map[uint64]*Client),
|
||||
history: make(map[string][]Event),
|
||||
subscribers: make(map[string]map[uint64]*subscriber),
|
||||
disconnectHandlers: make([]DisconnectHandler, 0),
|
||||
connectHandlers: make([]ConnectHandler, 0),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,9 +102,12 @@ func (h *Hub) NextID() uint64 {
|
||||
// Register 注册客户端连接
|
||||
func (h *Hub) Register(client *Client) []Event {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
|
||||
if _, ok := h.clients[client.UserID]; !ok {
|
||||
// 检查是否是该用户的第一个连接(之前完全离线)
|
||||
_, existed := h.clients[client.UserID]
|
||||
isFirstConnection := !existed
|
||||
|
||||
if !existed {
|
||||
h.clients[client.UserID] = make(map[uint64]*Client)
|
||||
}
|
||||
h.clients[client.UserID][client.ID] = client
|
||||
@@ -105,31 +122,62 @@ func (h *Hub) Register(client *Client) []Event {
|
||||
zap.String("user_id", client.UserID),
|
||||
zap.Uint64("client_id", client.ID),
|
||||
zap.Int("total_clients", len(h.clients[client.UserID])),
|
||||
zap.Bool("is_first_connection", isFirstConnection),
|
||||
)
|
||||
|
||||
// 复制处理器列表避免锁竞争
|
||||
handlers := make([]ConnectHandler, len(h.connectHandlers))
|
||||
copy(handlers, h.connectHandlers)
|
||||
h.mu.Unlock()
|
||||
|
||||
// 异步调用连接处理器,避免阻塞 Register
|
||||
if len(handlers) > 0 {
|
||||
go func() {
|
||||
for _, handler := range handlers {
|
||||
handler(client.UserID, isFirstConnection)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
return replay
|
||||
}
|
||||
|
||||
// Unregister 注销客户端连接
|
||||
func (h *Hub) Unregister(client *Client) {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
|
||||
var remainingCount int
|
||||
if userClients, ok := h.clients[client.UserID]; ok {
|
||||
if _, exists := userClients[client.ID]; exists {
|
||||
delete(userClients, client.ID)
|
||||
close(client.Quit)
|
||||
remainingCount = len(userClients)
|
||||
|
||||
if len(userClients) == 0 {
|
||||
if remainingCount == 0 {
|
||||
delete(h.clients, client.UserID)
|
||||
}
|
||||
|
||||
zap.L().Debug("WebSocket client unregistered",
|
||||
zap.String("user_id", client.UserID),
|
||||
zap.Uint64("client_id", client.ID),
|
||||
zap.Int("remaining_connections", remainingCount),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 复制处理器列表避免锁竞争
|
||||
handlers := make([]DisconnectHandler, len(h.disconnectHandlers))
|
||||
copy(handlers, h.disconnectHandlers)
|
||||
h.mu.Unlock()
|
||||
|
||||
// 异步调用断开处理器,避免阻塞 Unregister
|
||||
if len(handlers) > 0 {
|
||||
go func() {
|
||||
for _, handler := range handlers {
|
||||
handler(client.UserID, remainingCount)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
// HasClients 检查用户是否有活跃连接
|
||||
@@ -139,6 +187,24 @@ func (h *Hub) HasClients(userID string) bool {
|
||||
return len(h.clients[userID]) > 0
|
||||
}
|
||||
|
||||
// OnDisconnect 注册断开连接事件处理器
|
||||
// 当用户断开 WebSocket 连接时,会调用所有注册的处理器
|
||||
// 处理器会收到用户ID和该用户剩余的连接数
|
||||
func (h *Hub) OnDisconnect(handler DisconnectHandler) {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
h.disconnectHandlers = append(h.disconnectHandlers, handler)
|
||||
}
|
||||
|
||||
// OnConnect 注册连接事件处理器
|
||||
// 当用户建立 WebSocket 连接时,会调用所有注册的处理器
|
||||
// 处理器会收到用户ID和是否是该用户的第一个连接
|
||||
func (h *Hub) OnConnect(handler ConnectHandler) {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
h.connectHandlers = append(h.connectHandlers, handler)
|
||||
}
|
||||
|
||||
// GetClientCount 获取用户的连接数
|
||||
func (h *Hub) GetClientCount(userID string) int {
|
||||
h.mu.RLock()
|
||||
|
||||
Reference in New Issue
Block a user