/** * 骑手端WebSocket管理工具 * 统一管理WebSocket连接、消息处理和状态维护 * * @author kxmall * @date 2025-01-08 */ class RiderWebSocketManager { constructor() { this.websocket = null; this.heartbeatTimer = null; this.reconnectTimer = null; this.isManualClose = false; // 是否手动关闭 this.reconnectAttempts = 0; // 重连尝试次数 this.maxReconnectAttempts = 5; // 最大重连次数 this.reconnectInterval = 5000; // 重连间隔 this.heartbeatInterval = 30000; // 心跳间隔 // 消息处理回调 this.onMessageCallbacks = new Map(); this.onStatusChangeCallback = null; // 绑定方法上下文 this.connect = this.connect.bind(this); this.disconnect = this.disconnect.bind(this); this.send = this.send.bind(this); this.handleMessage = this.handleMessage.bind(this); } /** * 连接WebSocket * @param {Object} userInfo 用户信息 * @param {String} baseUrl 基础URL */ connect(userInfo, baseUrl) { if (!userInfo || !userInfo.id) { console.error('用户信息不存在,无法连接WebSocket'); return; } if (this.websocket) { console.warn('WebSocket已存在,先断开再重连'); this.disconnect(); } // 构建WebSocket连接地址 const socketUrl = `ws://${baseUrl.replace('http://', '').replace('https://', '')}/websocket/rider/${userInfo.id}`; console.log('连接WebSocket:', socketUrl); try { this.websocket = uni.connectSocket({ url: socketUrl, success: () => { console.log('WebSocket连接请求发送成功'); }, fail: (err) => { console.error('WebSocket连接请求失败:', err); this._scheduleReconnect(userInfo, baseUrl); } }); this._setupEventHandlers(userInfo, baseUrl); } catch (error) { console.error('创建WebSocket连接失败:', error); this._scheduleReconnect(userInfo, baseUrl); } } /** * 设置事件处理器 * @private */ _setupEventHandlers(userInfo, baseUrl) { if (!this.websocket) return; // 监听连接打开 this.websocket.onOpen(() => { console.log('WebSocket连接已打开'); this.reconnectAttempts = 0; // 重置重连次数 this._startHeartbeat(); this._notifyStatusChange('connected'); }); // 监听消息 this.websocket.onMessage((res) => { console.log('收到WebSocket消息:', res.data); this.handleMessage(res.data); }); // 监听错误 this.websocket.onError((err) => { console.error('WebSocket发生错误:', err); this._notifyStatusChange('error', err); }); // 监听关闭 this.websocket.onClose((res) => { console.log('WebSocket连接关闭:', res); this._stopHeartbeat(); this._notifyStatusChange('disconnected'); // 如果不是手动关闭且用户仍然有效,则尝试重连 if (!this.isManualClose && userInfo && userInfo.state) { this._scheduleReconnect(userInfo, baseUrl); } }); } /** * 断开WebSocket连接 */ disconnect() { this.isManualClose = true; this._stopHeartbeat(); this._stopReconnect(); if (this.websocket) { this.websocket.close(); this.websocket = null; } console.log('WebSocket手动断开'); this._notifyStatusChange('disconnected'); } /** * 发送消息 * @param {String} message 消息内容 */ send(message) { if (!this.websocket) { console.warn('WebSocket未连接,无法发送消息'); return false; } this.websocket.send({ data: message, success: () => { console.log('WebSocket消息发送成功:', message); }, fail: (err) => { console.error('WebSocket消息发送失败:', err); } }); return true; } /** * 处理接收到的消息 * @param {String} data 消息数据 */ handleMessage(data) { try { // 处理心跳响应 if (data === '连接成功' || data === 'pong') { return; } // 解析JSON消息 const message = typeof data === 'string' ? JSON.parse(data) : data; // 调用对应的消息处理回调 const callback = this.onMessageCallbacks.get(message.type); if (callback && typeof callback === 'function') { callback(message); } else { console.warn('未找到消息类型处理器:', message.type); } } catch (error) { console.error('处理WebSocket消息失败:', error); } } /** * 注册消息处理回调 * @param {String} messageType 消息类型 * @param {Function} callback 回调函数 */ onMessage(messageType, callback) { this.onMessageCallbacks.set(messageType, callback); } /** * 注册状态变化回调 * @param {Function} callback 回调函数 */ onStatusChange(callback) { this.onStatusChangeCallback = callback; } /** * 移除消息处理回调 * @param {String} messageType 消息类型 */ offMessage(messageType) { this.onMessageCallbacks.delete(messageType); } /** * 清除所有回调 */ clearCallbacks() { this.onMessageCallbacks.clear(); this.onStatusChangeCallback = null; } /** * 获取连接状态 */ isConnected() { return this.websocket !== null; } /** * 开始心跳 * @private */ _startHeartbeat() { this._stopHeartbeat(); this.heartbeatTimer = setInterval(() => { this.send('ping'); }, this.heartbeatInterval); } /** * 停止心跳 * @private */ _stopHeartbeat() { if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); this.heartbeatTimer = null; } } /** * 计划重连 * @private */ _scheduleReconnect(userInfo, baseUrl) { if (this.isManualClose || this.reconnectAttempts >= this.maxReconnectAttempts) { console.log('不再尝试重连'); return; } this._stopReconnect(); this.reconnectAttempts++; const delay = this.reconnectInterval * this.reconnectAttempts; console.log(`${delay/1000}秒后尝试第${this.reconnectAttempts}次重连`); this.reconnectTimer = setTimeout(() => { console.log(`开始第${this.reconnectAttempts}次重连`); this.connect(userInfo, baseUrl); }, delay); } /** * 停止重连 * @private */ _stopReconnect() { if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = null; } } /** * 通知状态变化 * @private */ _notifyStatusChange(status, data = null) { if (this.onStatusChangeCallback && typeof this.onStatusChangeCallback === 'function') { this.onStatusChangeCallback(status, data); } } /** * 重置连接状态(用于手动重连) */ reset() { this.isManualClose = false; this.reconnectAttempts = 0; } /** * 销毁实例 */ destroy() { this.disconnect(); this.clearCallbacks(); this._stopReconnect(); } } // 消息类型常量 export const MESSAGE_TYPES = { NEW_ORDER: 'NEW_ORDER', ORDER_CANCEL: 'ORDER_CANCEL', ORDER_STATUS_UPDATE: 'ORDER_STATUS_UPDATE', SYSTEM_MESSAGE: 'SYSTEM_MESSAGE' }; // 连接状态常量 export const CONNECTION_STATUS = { CONNECTING: 'connecting', CONNECTED: 'connected', DISCONNECTED: 'disconnected', ERROR: 'error' }; // 导出单例实例 const riderWebSocketManager = new RiderWebSocketManager(); export default riderWebSocketManager;