// WebSocket实时通信工具 // 专为小程序设计的WebSocket封装,模拟Socket.IO功能 // 导入配置 const API = require('./api.js'); // WebSocket连接实例 let socket = null; let isConnecting = false; let reconnectAttempts = 0; const maxReconnectAttempts = 5; const reconnectDelay = 3000; // 重连延迟时间(毫秒) // 事件监听器存储 const eventListeners = {}; // 存储当前连接的用户信息 let currentUserPhone = null; let currentChatId = null; // 获取WebSocket服务器URL function getSocketUrl() { // 从API的BASE_URL获取服务器地址 // 注意:小程序中无法直接获取API的BASE_URL,需要根据环境设置 const baseUrl = API.isTestMode() ? API.SERVER_CONFIG.DEFAULT_LOCAL_IP : API.SERVER_CONFIG.PRODUCTION; // 替换http为ws,https为wss return baseUrl.replace(/^http/, 'ws'); } // 初始化WebSocket连接 function initSocket(userPhone, chatId) { return new Promise((resolve, reject) => { // 存储当前用户信息 currentUserPhone = userPhone; currentChatId = chatId; // 如果已经连接,直接返回 if (socket && socket.connected) { console.log('WebSocket已经连接'); resolve(socket); return; } // 如果正在连接中,等待连接完成 if (isConnecting) { console.log('WebSocket正在连接中...'); // 等待连接完成 const checkConnection = setInterval(() => { if (socket && socket.connected) { clearInterval(checkConnection); resolve(socket); } else if (!isConnecting) { clearInterval(checkConnection); reject(new Error('WebSocket连接失败')); } }, 100); return; } isConnecting = true; reconnectAttempts = 0; try { const socketUrl = getSocketUrl(); const fullUrl = `${socketUrl}?user_phone=${userPhone}&chat_id=${chatId}`; console.log('正在连接WebSocket服务器:', fullUrl); // 创建WebSocket连接 socket = wx.connectSocket({ url: fullUrl, header: { 'content-type': 'application/json' }, protocols: ['chat'], success: () => { console.log('WebSocket连接创建请求发送成功'); }, fail: (error) => { console.error('WebSocket连接创建失败:', error); isConnecting = false; reject(error); } }); // 连接成功事件 socket.onOpen(() => { console.log('WebSocket连接成功'); socket.connected = true; isConnecting = false; reconnectAttempts = 0; resolve(socket); }); // 连接错误事件 socket.onError((error) => { console.error('WebSocket连接错误:', error); socket.connected = false; isConnecting = false; reject(error); }); // 断开连接事件 socket.onClose((res) => { console.log('WebSocket断开连接:', res); socket.connected = false; isConnecting = false; // 如果不是手动断开(code !== 1000),尝试重连 if (res.code !== 1000) { reconnect(); } }); // 接收消息事件 socket.onMessage((res) => { console.log('收到WebSocket消息:', res); try { const message = JSON.parse(res.data); // 触发对应类型的事件 if (message.type) { emitEvent(message.type, message.data); } else { // 兼容旧格式消息 emitEvent('message', message); } } catch (error) { console.error('消息解析失败:', error); } }); } catch (error) { console.error('初始化WebSocket失败:', error); isConnecting = false; reject(error); } }); } // 重连函数 function reconnect() { if (reconnectAttempts >= maxReconnectAttempts) { console.error('WebSocket重连次数超过限制,停止重连'); return; } reconnectAttempts++; console.log(`WebSocket正在重连,尝试次数: ${reconnectAttempts}/${maxReconnectAttempts}`); // 延迟重连 setTimeout(() => { if (currentUserPhone && currentChatId) { initSocket(currentUserPhone, currentChatId) .then(() => { console.log('WebSocket重连成功'); }) .catch((error) => { console.error('WebSocket重连失败:', error); }); } }, reconnectDelay); } // 发送消息 function sendMessage(messageData) { return new Promise((resolve, reject) => { if (!socket || !socket.connected) { reject(new Error('WebSocket未连接')); return; } try { // 构造消息格式,模拟Socket.IO的事件机制 const message = { type: 'chat message', data: messageData }; socket.send({ data: JSON.stringify(message), success: () => { console.log('WebSocket消息发送成功'); resolve({ success: true }); }, fail: (error) => { console.error('WebSocket消息发送失败:', error); reject(error); } }); } catch (error) { console.error('发送WebSocket消息失败:', error); reject(error); } }); } // 断开连接 function disconnect() { if (socket) { console.log('手动断开WebSocket连接'); socket.close(1000, 'normal closure'); socket = null; } isConnecting = false; reconnectAttempts = 0; } // 注册事件监听器 function on(eventName, callback) { if (!eventListeners[eventName]) { eventListeners[eventName] = []; } eventListeners[eventName].push(callback); } // 移除事件监听器 function off(eventName, callback) { if (eventListeners[eventName]) { if (callback) { eventListeners[eventName] = eventListeners[eventName].filter(cb => cb !== callback); } else { delete eventListeners[eventName]; } } } // 触发事件 function emitEvent(eventName, data) { if (eventListeners[eventName]) { eventListeners[eventName].forEach(callback => { try { callback(data); } catch (error) { console.error('事件监听器执行错误:', error); } }); } } // 导出WebSocket工具 module.exports = { initSocket, sendMessage, disconnect, on, off, isConnected: () => socket && socket.connected };