topfans/frontend/utils/socket/GlobalSocketManager.js

102 lines
3.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { getAiChatSocket } from './AiChatSocket'
import { getActivitySocket } from './ActivitySocket'
/**
* 全局 WebSocket 管理器
* 统一管理多个服务的 WebSocket 连接
*/
class GlobalSocketManager {
constructor() {
this.sockets = {} // serviceName -> SocketManager
this.token = null
this.isAllConnected = false
this._initialized = false // 防止重复 init 导致监听器累积
// 保存监听器引用,用于 cleanup
this._aiChatConnectHandler = null
this._aiChatErrorHandler = null
this._activityConnectHandler = null
this._activityErrorHandler = null
}
/**
* 初始化所有连接(幂等,重复调用会先清理旧监听器再重连)
*/
init(token) {
this.token = token
// 总是先清理旧监听器再注册新的,防止累积。
// 注意closeAll() 会清空 this.sockets所以 cleanup 必须通过单例 getter 获取 socket 引用。
this._cleanupListeners()
this._initialized = true
this._initAiChat()
this._initActivity()
// Future: this._initNotification()
}
async _initAiChat() {
const aiChat = getAiChatSocket()
this._aiChatConnectHandler = () => console.log('AI Chat connected')
this._aiChatErrorHandler = (err) => console.error('AI Chat error:', err)
aiChat.on('connect', this._aiChatConnectHandler)
aiChat.on('error', this._aiChatErrorHandler)
await aiChat.connect(this.token)
this.sockets['ai_chat'] = aiChat
}
async _initActivity() {
const activity = getActivitySocket()
this._activityConnectHandler = () => console.log('Activity socket connected')
this._activityErrorHandler = (err) => console.error('Activity socket error:', err)
activity.on('connect', this._activityConnectHandler)
activity.on('error', this._activityErrorHandler)
if (this.token) {
await activity.connect(this.token)
}
this.sockets['activity'] = activity
}
/**
* 清理之前注册的监听器,防止每次 init() 累积。
* 通过单例 getter 获取 socket 引用(而非 this.sockets
* 因为 closeAll() 会清空 this.sockets 但单例仍存活。
*/
_cleanupListeners() {
try {
const aiChat = getAiChatSocket()
if (this._aiChatConnectHandler) {
aiChat.off('connect', this._aiChatConnectHandler)
aiChat.off('error', this._aiChatErrorHandler)
}
} catch (e) { /* singleton not yet created, skip */ }
try {
const activity = getActivitySocket()
if (this._activityConnectHandler) {
activity.off('connect', this._activityConnectHandler)
activity.off('error', this._activityErrorHandler)
}
} catch (e) { /* singleton not yet created, skip */ }
}
getSocket(serviceName) {
return this.sockets[serviceName]
}
closeAll() {
Object.values(this.sockets).forEach(socket => socket.close())
this.sockets = {}
this._initialized = false // 关闭后允许下次 init() 重新注册监听器
}
}
let globalInstance = null
export function getGlobalSocket() {
if (!globalInstance) {
globalInstance = new GlobalSocketManager()
}
return globalInstance
}
export default GlobalSocketManager