import env from "../config/env.js"; class WebSocketService { constructor() { this.socketTask = null; this.isConnected = false; this.reconnectAttempts = 0; this.maxReconnectAttempts = 5; this.reconnectInterval = 3000; // 3秒重连 this.heartbeatInterval = 60000; // 60秒发送一次心跳 this.heartbeatTimer = null; this.reconnectTimer = null; } async connect() { // 先关闭之前的连接 // await this.disconnect(); const userId = uni.getStorageSync("userInfo").userId; const baseUrl = env.baseUrl.replace("https://", ""); const wsUrl = `wss://${baseUrl}/ws?userId=${userId}`; console.log("Attempting to connect to WebSocket:", wsUrl); return new Promise((resolve, reject) => { try { this.socketTask = uni.connectSocket({ url: wsUrl, complete: () => { console.log("WebSocket connection attempt completed"); }, }); if (!this.socketTask) { console.error("Failed to create socket task"); reject(new Error("Failed to create socket task")); return; } // 监听连接打开 this.socketTask.onOpen(() => { console.log("WebSocket connected successfully"); this.isConnected = true; this.reconnectAttempts = 0; // 启动心跳 this.startHeartbeat(); resolve(); }); // 监听消息 this.socketTask.onMessage((res) => { try { // 先解析 JSON 字符串 const data = JSON.parse(res.data); // 判断是否是心跳响应 if (data.message === "PONG") { return; } switch (data.type) { case "INIT": uni.$emit("init", data); break; case "RUNNING": uni.$emit("newMessage", data); break; case "NEW_RECORD": uni.$emit("newRecord", data); break; default: console.log("Unknown message type:", data.type); } } catch (error) { console.error("Failed to parse WebSocket message:", error); } }); // 监听连接关闭 this.socketTask.onClose((res) => { console.log("WebSocket closed:", res); this.isConnected = false; this.stopHeartbeat(); if ( !res.wasClean && this.reconnectAttempts < this.maxReconnectAttempts ) { this.reconnectAttempts++; console.log( `Attempting to reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts})` ); this.reconnectTimer = setTimeout( () => this.connect(), this.reconnectInterval ); } }); // 监听错误 this.socketTask.onError((error) => { console.error("WebSocket error:", error); this.isConnected = false; this.stopHeartbeat(); reject(error); }); } catch (error) { console.error("Failed to create WebSocket connection:", error); reject(error); } }); } // 启动心跳 startHeartbeat() { this.stopHeartbeat(); // 先清除可能存在的定时器 this.heartbeatTimer = setInterval(() => { if (this.isConnected) { this.send({ type: "PING" }); } }, this.heartbeatInterval); } // 停止心跳 stopHeartbeat() { if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); this.heartbeatTimer = null; } } async disconnect() { this.stopHeartbeat(); if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = null; } return new Promise((resolve) => { if (this.socketTask) { this.socketTask.close({ success: () => { console.log("WebSocket disconnected successfully"); this.socketTask = null; this.isConnected = false; resolve(); }, fail: (error) => { console.error("Failed to disconnect WebSocket:", error); this.socketTask = null; this.isConnected = false; resolve(); }, }); } else { resolve(); } }); } async send(message) { if (!this.isConnected || !this.socketTask) { console.error("WebSocket is not connected"); return false; } return new Promise((resolve, reject) => { this.socketTask.send({ data: JSON.stringify(message), success: () => { console.log("Message sent successfully"); resolve(true); }, fail: (error) => { console.error("Failed to send message:", error); reject(error); }, }); }); } } // 创建单例 const websocketService = new WebSocketService(); export default websocketService;