feat(call): enhance call handling with user connection events and active call management
All checks were successful
Build Backend / build (push) Successful in 13m52s
Build Backend / build-docker (push) Successful in 1m8s

- 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:
lafay
2026-03-28 04:34:49 +08:00
parent 63cfbad65c
commit d357998321
4 changed files with 255 additions and 35 deletions

View File

@@ -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()