import {checkDev} from "@/utils/utils"; export class WebSocketManager { constructor(url) { this.url = url; this.socket = null; this.isConnected = false; this.isAuthenticated = false; // 是否已认证 this.reconnectAttempts = 0; this.maxReconnectAttempts = 5; this.reconnectDelay = 1000; this.messageHandlers = []; this.pingInterval = null; this.cachedToken = null; // 缓存的token } /** * 获取当前用户的token * @returns {string|null} */ getToken() { // 从本地存储获取token(不使用缓存,确保获取最新token) let token = uni.getStorageSync('token'); if (token) { // 移除Bearer前缀(如果有) token = token.replace('Bearer ', ''); this.cachedToken = token; } return token || null; } /** * 清除缓存的token(登录后需要调用,以获取最新token) */ clearCachedToken() { this.cachedToken = null; } /** * 重新绑定用户(登录后调用) */ rebindUser() { const userId = uni.getStorageSync('user_id'); if (!userId) { console.warn('重新绑定用户失败:user_id不存在'); return false; } // 清除缓存的token,确保获取最新token this.clearCachedToken(); if (this.isConnected) { // 如果已连接,直接绑定 return this.bindUser(userId); } else { // 如果未连接,先连接再绑定 this.connect(); // 连接成功后会在 onOpen 中自动绑定 return true; } } connect() { if (this.isConnected) return; console.log('正在连接WebSocket...'); this.socket = uni.connectSocket({ url: this.url, success: () => { console.log('WebSocket连接成功'); }, fail: (err) => { console.error('WebSocket连接失败:', err); this.handleReconnect(); } }); this.socket.onOpen(() => { console.log('WebSocket连接已打开'); this.isConnected = true; this.reconnectAttempts = 0; // 开始心跳检测 this.startHeartbeat(); // 绑定当前用户(使用正确的key:user_id) const userId = uni.getStorageSync('user_id'); if (userId) { this.bindUser(userId); } }); this.socket.onMessage((res) => { try { const data = JSON.parse(res.data); console.log('收到消息:', data); this.handleMessage(data); } catch (e) { console.error('解析消息失败:', e); } }); this.socket.onClose((res) => { console.log('WebSocket连接关闭:', res); this.isConnected = false; this.stopHeartbeat(); this.handleReconnect(); }); this.socket.onError((err) => { console.error('WebSocket错误:', err); }); } /** * 绑定用户(携带token进行认证) * @param {string} userId 用户ID */ bindUser(userId) { const token = this.getToken(); if (!token) { console.error('绑定用户失败:token不存在'); return false; } return this.send({ request_type: 'bind', user_type: 'user', sender_user_id: userId, token: token }); } /** * 发送消息(自动携带token) * @param {Object} message 消息对象 * @param {boolean} requireAuth 是否需要认证(默认true) * @returns {boolean} 是否发送成功 */ send(message, requireAuth = true) { if (!this.isConnected) { console.error('WebSocket未连接'); return false; } try { // 如果需要认证且消息中没有token,自动添加token if (requireAuth && !message.token && message.request_type !== 'ping') { const token = this.getToken(); if (token) { message.token = token; } } const messageStr = JSON.stringify(message); this.socket.send({ data: messageStr, success: () => { console.log('消息发送成功:', message); }, fail: (err) => { console.error('消息发送失败:', err); } }); return true; } catch (err) { console.error('发送消息出错:', err); return false; } } addMessageHandler(handler) { this.messageHandlers.push(handler); } removeMessageHandler(handler) { const index = this.messageHandlers.indexOf(handler); if (index !== -1) { this.messageHandlers.splice(index, 1); } } /** * 获取用户ID并绑定客户端(携带token) * @returns {string|null} 用户ID */ getUserIdAndBindClientId() { const userId = uni.getStorageSync('user_id'); // 实际项目中从存储获取 const token = this.getToken(); if (userId == null || userId === 'user-' || userId === '') { // 等待10秒后重试 setTimeout(() => { this.getUserIdAndBindClientId(); }, 10000) } else if (!token) { // token不存在,等待后重试 console.warn('token不存在,等待后重试绑定'); setTimeout(() => { this.getUserIdAndBindClientId(); }, 5000) } else { const bindMessage = { request_type: 'bind', user_type: 'user', sender_user_id: `user-${userId}`, token: token }; this.send(bindMessage); } return userId; } handleMessage(data) { // 处理认证响应 if (data.auth_status !== undefined) { if (data.auth_status === 'success') { console.log('WebSocket认证成功'); this.isAuthenticated = true; } else if (data.auth_status === 'failed') { console.error('WebSocket认证失败:', data.message); this.isAuthenticated = false; // 清除缓存的token this.cachedToken = null; } else if (data.auth_status === 'token_expired') { console.warn('Token已过期,需要重新认证'); this.isAuthenticated = false; this.cachedToken = null; // 通知应用层token过期 uni.$emit('ws-token-expired'); // 尝试重新绑定 this.getUserIdAndBindClientId(); } return; } // 如果对象中有clientId则给websocket发送绑定请求 if (data.clientId) { this.getUserIdAndBindClientId(data.clientId); } // 处理聊天消息或其他消息 this.messageHandlers.forEach(handler => { try { handler(data); } catch (e) { console.error('消息处理出错:', e); } }); } startHeartbeat() { this.pingInterval = setInterval(() => { if (this.isConnected) { this.send({type: 'ping'}); } }, 300000); } stopHeartbeat() { if (this.pingInterval) { clearInterval(this.pingInterval); this.pingInterval = null; } } handleReconnect() { if (this.reconnectAttempts >= this.maxReconnectAttempts) { console.log('已达到最大重连次数'); return; } setTimeout(() => { this.reconnectAttempts++; this.reconnectDelay = Math.min(this.reconnectDelay * 2, 30000); console.log(`尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})`); this.connect(); }, this.reconnectDelay); } disconnect() { if (this.socket) { this.socket.close(); this.socket = null; } this.isConnected = false; this.stopHeartbeat(); } } // 全局WebSocket实例 // export const webSocketManager = new WebSocketManager('ws://127.0.0.1:12080/ws'); const wsUrl = checkDev('dev')? 'ws://127.0.0.1:12080/ws':'wss://api.ws.g.xiaokang88.com/ws'; export const webSocketManager = new WebSocketManager(wsUrl);