import WebSocket from 'ws'; import logger from './logger' import { getStoreValue } from '../store.js' import { Notification } from "electron"; class WebSocketClient { constructor(options = {}) { this.reconnectInterval = options.reconnectInterval || 5000; // 重连间隔时间 this.lockReconnect = false; this.ws = null; this.pingTimeout = null; this.reconnectAttempts = 0; this.messageHandlers = new Map(); this.isConnected = false; this.options = options; // 延迟创建连接,避免在应用启动时立即连接 setTimeout(() => { this.createConnect(); }, 1000); } createConnect() { try { const apiUrl = getStoreValue("apiUrl"); const userInfo = getStoreValue("userInfo"); const token = getStoreValue("token"); // 检查必要的连接信息是否存在 if (!apiUrl || !userInfo || !token) { logger.info("WebSocket连接信息不完整,等待重试"); logger.info("apiUrl:", apiUrl); logger.info("userInfo:", userInfo); logger.info("token:", token); this.scheduleReconnect(); return; } // 处理基础URL let baseUrl = apiUrl.replace("https://", "wss://").replace("http://", "ws://"); // 移除末尾的斜杠(如果有) baseUrl = baseUrl.replace(/\/$/, ''); // 构建完整的WebSocket URL this.url = `${baseUrl}/bqw-ai/websocket/${userInfo.id}`; // this.url = `${baseUrl}/bqw-ai/${userInfo.id}`; logger.info("==================== WebSocketClient create WebSocketClient"); logger.info("WebSocket URL: " + this.url); // 设置WebSocket选项 this.options = { headers: { 'User-Agent': 'WebSocketClient', 'Connection': 'Upgrade', 'Upgrade': 'websocket', 'Sec-WebSocket-Version': '13' }, handshakeTimeout: 10000, perMessageDeflate: false, followRedirects: true, rejectUnauthorized: false }; logger.info("Token:", token); // 添加token日志 // 创建连接 this.connect(); } catch (error) { logger.error("创建WebSocket连接时发生错误:", error); this.scheduleReconnect(); } } scheduleReconnect() { if (this.lockReconnect) return; this.lockReconnect = true; logger.info("==================== WebSocketClient schedule reconnect"); setTimeout(() => { this.lockReconnect = false; this.createConnect(); // 重新获取本地缓存并创建连接 }, this.reconnectInterval); } connect() { logger.info("==================== WebSocketClient begin connect"); if (this.lockReconnect) return; try { const token = getStoreValue("token"); // 直接在构造函数中传递协议 this.ws = new WebSocket(this.url, token, this.options); this.ws.on('open', () => { logger.info('WebSocket 连接成功'); logger.info('WebSocket protocol:', this.ws.protocol); this.isConnected = true; this.reconnectAttempts = 0; this.lockReconnect = false; this.startHeartbeat(); this.emit('open'); }); this.ws.on('message', (data) => { try { const messageStr = data.toString(); const message = JSON.parse(messageStr); // 减少心跳消息的日志打印 if (message.cmd === 'heartcheck') { // 心跳消息不打印日志,或者只在调试模式下打印 if (process.env.NODE_ENV === 'development') { logger.debug('收到心跳消息'); } } else { logger.info('收到消息:', messageStr); } this.handleMessage(message); } catch (error) { logger.error('消息解析错误:', error); } }); this.ws.on('close', (code, reason) => { logger.info(`WebSocket连接已关闭,代码: ${code}, 原因: ${reason}`); this.isConnected = false; this.stopHeartbeat(); this.emit('close', { code, reason }); this.scheduleReconnect(); }); this.ws.on('error', (error) => { logger.error('WebSocket error:', error); this.emit('error', error); this.scheduleReconnect(); }); this.ws.on('unexpected-response', (request, response) => { logger.info(`收到响应: ${response.statusCode} ${response.statusMessage}`); logger.info('响应头:', response.headers); if (response.statusCode === 101) { logger.info('WebSocket升级成功'); return; } this.scheduleReconnect(); }); } catch (error) { logger.error('WebSocket connect error:', error); this.scheduleReconnect(); } } startHeartbeat() { this.pingTimeout = setInterval(() => { if (this.isConnected) { this.ws.send("heartcheck"); } }, 30000); } stopHeartbeat() { if (this.pingTimeout) { clearInterval(this.pingTimeout); this.pingTimeout = null; } } send(message) { if (!this.isConnected) { console.error('WebSocket未连接'); return false; } try { const data = typeof message === 'string' ? message : JSON.stringify(message); this.ws.send(data); return true; } catch (error) { console.error('发送消息失败:', error); return false; } } on(event, handler) { if (!this.messageHandlers.has(event)) { this.messageHandlers.set(event, new Set()); } this.messageHandlers.get(event).add(handler); } off(event, handler) { if (this.messageHandlers.has(event)) { this.messageHandlers.get(event).delete(handler); } } emit(event, data) { if (this.messageHandlers.has(event)) { this.messageHandlers.get(event).forEach(handler => { try { handler(data); } catch (error) { console.error(`事件处理器错误 (${event}):`, error); } }); } } handleMessage(message) { if (message.cmd==="Notification") { logger.info("Notification:", message) const msg=JSON.parse(message.msgTxt) // systemMsgType const isNotification = getStoreValue("Notification_"+msg.systemMsgType); if (isNotification!=0){ new Notification({ title: msg.title, body: msg.content }).show() } } this.emit('message', message); } close() { if (this.ws) { this.ws.close(); } } } export default WebSocketClient;