(() => { goog.require('Mixly.Env'); goog.require('Mixly.Config'); goog.require('Mixly.MJson'); goog.require('Mixly.WebSocket'); goog.require('Mixly.LayerExt'); goog.require('Mixly.Command'); goog.provide('Mixly.WebSocket.Socket'); const { Env, Config, MJson, LayerExt, Command } = Mixly; const { SOFTWARE } = Config; const { Socket } = Mixly.WebSocket; Socket.obj = null; Socket.url = ''; Socket.jsonArr = []; Socket.connected = false; Socket.initFunc = null; Socket.debug = SOFTWARE.debug; Socket.disconnectTimes = 0; Socket.updating = false; // 构建 Socket.io 连接 URL (和后端统一使用 Socket.io) let { hostname, protocol, port } = window.location; if (protocol === 'http:') { Socket.protocol = 'ws:'; } else { Socket.protocol = 'wss:'; } Socket.url = Socket.protocol + '//' + hostname + (port ? ':' + port : ''); Socket.IPAddress = hostname; let lockReconnect = false; let timeoutFlag = true; let timeoutSet = null; let reconectNum = 0; const timeout = 5000; function reconnect() { if (lockReconnect) return; lockReconnect = true; setTimeout(function () { timeoutFlag = true; Socket.init(); console.info(`正在重连第${reconectNum + 1}次`); reconectNum++; lockReconnect = false; }, timeout); } // 心跳检测 const heartCheck = { timeout, timeoutObj: null, serverTimeoutObj: null, reset: function () { clearInterval(this.timeoutObj); clearTimeout(this.serverTimeoutObj); return this; }, start: function () { const self = this; let count = 0; this.timeoutObj = setInterval(() => { if (count < 3) { if (Socket.connected) { // Socket.io 自带心跳,这里可以发送自定义心跳 console.info(`HeartBeat第${count + 1}次`); } count++; } else { clearInterval(this.timeoutObj); count = 0; if (Socket.obj && !Socket.connected) { Socket.obj.disconnect(); } } }, self.timeout); } } Socket.init = (onopenFunc = (data) => { }, doFunc = () => { }) => { if (Socket.connected) { if (Socket.initFunc) { Socket.initFunc(); Socket.initFunc = null; } doFunc(); return; } timeoutSet = setTimeout(() => { if (timeoutFlag && reconectNum < 3) { console.info(`重连`); reconectNum++; Socket.init(); } }, timeout); // 使用 Socket.io 客户端连接(和后端统一) Socket.obj = io(`${Socket.url}/all`, { path: '/mixly-socket/', reconnection: true, reconnectionDelayMax: 10000, transports: ['websocket'] }); Socket.obj.on('connect', () => { console.log('已连接' + Socket.url); Socket.connected = true; Socket.initFunc = doFunc; reconectNum = 0; timeoutFlag = false; clearTimeout(timeoutSet); heartCheck.reset().start(); onopenFunc(Socket); Socket.reload(); if (Socket.updating) { Socket.updating = false; } }); // Socket.io 消息接收 Socket.obj.onAny((eventName, ...args) => { heartCheck.reset().start(); // 构造兼容原有 Command 格式的消息 const command = { event: eventName, data: args }; if (Socket.debug) { console.log('receive -> ', eventName, args); } // 尝试使用原有 Command 系统处理 try { Command.run(MJson.decode(command)); } catch (e) { // 如果 Command 系统不能处理,忽略 } }); Socket.obj.on('connect_error', (error) => { console.log('WebSocket error: ', error); reconnect(); }); Socket.obj.on('disconnect', (reason) => { Socket.connected = false; Socket.disconnectTimes += 1; if (Socket.disconnectTimes > 255) { Socket.disconnectTimes = 1; } console.log('已断开' + Socket.url); console.info(`关闭`, reason); if (reason !== 'io client disconnect') { timeoutFlag = false; clearTimeout(timeoutSet); reconnect(); } else { clearInterval(heartCheck.timeoutObj); clearTimeout(heartCheck.serverTimeoutObj); } }); } Socket.sendCommand = (command) => { if (!Socket.connected) { layer.msg('未连接' + Socket.url, { time: 1000 }); return; } try { const encodedCommand = MJson.encode(command); if (Socket.debug) { console.log('send -> ', encodedCommand); } // 使用 Socket.io emit 发送命令 Socket.obj.emit('command', encodedCommand); } catch (e) { console.log(e); return; } } Socket.clickConnect = () => { if (Socket.connected) { Socket.disconnect(); } else { Socket.connect((WS) => { layer.closeAll(); layer.msg(WS.url + '连接成功', { time: 1000 }); }); } } Socket.openLoadingBox = (title, successFunc = () => { }, endFunc = () => { }) => { layer.open({ type: 1, title: title, content: $('#mixly-loader-div'), shade: LayerExt.SHADE_ALL, closeBtn: 0, success: function () { $("#webusb-cancel").css("display", "none"); $(".layui-layer-page").css("z-index", "198910151"); successFunc(); }, end: function () { $("#mixly-loader-div").css("display", "none"); $(".layui-layer-shade").remove(); $("#webusb-cancel").css("display", "unset"); if (Socket.connected) endFunc(); } }); } Socket.connect = (onopenFunc = (data) => { }, doFunc = () => { }) => { if (Socket.connected) { doFunc(); return; } let title = '连接中...'; Socket.openLoadingBox(title, () => { setTimeout(() => { Socket.init(onopenFunc); }, 1000); }, doFunc); } Socket.disconnect = () => { if (!Socket.connected) return; let title = '断开中...'; Socket.openLoadingBox(title, () => { Socket.obj.disconnect(); }); } Socket.reload = () => { if (!Socket.updating && Socket.disconnectTimes) { window.location.reload(); } } })();