/** * ws-client.js — WebSocket 客户端单例 * 全站共享一个 WS 连接,提供自动重连、消息分发、状态通知 */ var WsClient = (function() { var ws = null; var url = ''; var msgCallbacks = []; var statusCallbacks = []; var reconnectTimer = null; var reconnectDelay = 3000; var status = 'disconnected'; // 'connected' | 'disconnected' | 'connecting' function setStatus(s) { if (status !== s) { status = s; for (var i = 0; i < statusCallbacks.length; i++) { statusCallbacks[i](s); } } } function connect(wsUrl) { if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) { return; } url = wsUrl; setStatus('connecting'); try { ws = new WebSocket(url); } catch (e) { setStatus('disconnected'); scheduleReconnect(); return; } ws.onopen = function() { setStatus('connected'); if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; } }; ws.onclose = function() { setStatus('disconnected'); ws = null; scheduleReconnect(); }; ws.onerror = function() { // onclose will fire after onerror }; ws.onmessage = function(e) { var raw = e.data; // 写入监控日志 if (typeof MonitorRing !== 'undefined') { MonitorRing.push('↓', raw); } // 尝试解析 JSON var data = null; try { data = JSON.parse(raw); } catch (ex) { // 非 JSON 消息也分发原始数据 } // 分发给所有注册的回调 for (var i = 0; i < msgCallbacks.length; i++) { try { msgCallbacks[i](data || raw, raw); } catch (ex) { console.error('WsClient msg callback error:', ex); } } }; } function scheduleReconnect() { if (reconnectTimer) return; reconnectTimer = setTimeout(function() { reconnectTimer = null; if (status === 'disconnected') { connect(url); } }, reconnectDelay); } function send(data) { var raw = ''; if (typeof data === 'object') { raw = JSON.stringify(data); } else { raw = String(data); } // 写入监控日志 if (typeof MonitorRing !== 'undefined') { MonitorRing.push('↑', raw); } if (!ws || ws.readyState !== WebSocket.OPEN) { console.error('WsClient: not connected, cannot send'); return false; } try { ws.send(raw); return true; } catch (e) { console.error('WsClient: send failed', e); return false; } } function onMessage(cb) { msgCallbacks.push(cb); } function onStatusChange(cb) { statusCallbacks.push(cb); // 立即通知当前状态 cb(status); } function getStatus() { return status; } function disconnect() { if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; } if (ws) { ws.onclose = null; // 阻止自动重连 ws.close(); ws = null; } setStatus('disconnected'); } return { connect: connect, send: send, onMessage: onMessage, onStatusChange: onStatusChange, getStatus: getStatus, disconnect: disconnect }; })();