104 lines
2.4 KiB
JavaScript
104 lines
2.4 KiB
JavaScript
/**
|
|
* @file ws-client.js
|
|
* @brief WebSocket 客户端封装 — 自动重连 + 事件分发
|
|
*/
|
|
|
|
|
|
var WsClient = {
|
|
ws: null, url: '', status: 'disconnected', timer: null,
|
|
msgCbs: [], statusCbs: [],
|
|
|
|
onMsg: function(cb) { this.msgCbs.push(cb); },
|
|
onStatus: function(cb) { this.statusCbs.push(cb); },
|
|
|
|
connect: function(url) {
|
|
if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.url = url;
|
|
this._setStatus('connecting');
|
|
|
|
try
|
|
{
|
|
this.ws = new WebSocket(url);
|
|
this.ws.binaryType = 'arraybuffer';
|
|
}
|
|
catch (e)
|
|
{
|
|
this._setStatus('disconnected');
|
|
this._schedule();
|
|
return;
|
|
}
|
|
|
|
this.ws.onopen = function() {
|
|
var self = WsClient;
|
|
self._setStatus('connected');
|
|
if (self.timer) { clearTimeout(self.timer); self.timer = null; }
|
|
self.send({ type: 'get_cmds' });
|
|
};
|
|
|
|
this.ws.onclose = function() {
|
|
var self = WsClient;
|
|
self._setStatus('disconnected');
|
|
self.ws = null;
|
|
self._schedule();
|
|
};
|
|
|
|
this.ws.onerror = function() {};
|
|
|
|
this.ws.onmessage = function(e) {
|
|
var self = WsClient;
|
|
var raw = e.data;
|
|
|
|
if (raw instanceof ArrayBuffer)
|
|
{
|
|
self.msgCbs.forEach(function(cb) { try { cb(null, raw); } catch(ex) {} });
|
|
return;
|
|
}
|
|
|
|
var data = null;
|
|
try { data = JSON.parse(raw); } catch(ex) {}
|
|
|
|
self.msgCbs.forEach(function(cb) { try { cb(data || raw, null); } catch(ex) {} });
|
|
};
|
|
},
|
|
|
|
send: function(obj) {
|
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN)
|
|
{
|
|
if (typeof toast === 'function') { toast(I18n.t('toast.ws_error'), 'error'); }
|
|
return;
|
|
}
|
|
|
|
var raw = (typeof obj === 'object') ? JSON.stringify(obj) : String(obj);
|
|
this.ws.send(raw);
|
|
},
|
|
|
|
_setStatus: function(s) {
|
|
if (this.status === s) return;
|
|
this.status = s;
|
|
|
|
var dot = document.getElementById('nav-status-dot');
|
|
var txt = document.getElementById('nav-status-text');
|
|
if (dot) { dot.className = 'nav-status-dot ' + s; }
|
|
if (txt)
|
|
{
|
|
var map = { connected: I18n.t('status.connected'), disconnected: I18n.t('status.disconnected'), connecting: I18n.t('status.connecting') };
|
|
txt.textContent = map[s] || s;
|
|
}
|
|
|
|
this.statusCbs.forEach(function(cb) { cb(s); });
|
|
},
|
|
|
|
_schedule: function() {
|
|
var self = this;
|
|
if (self.timer) return;
|
|
self.timer = setTimeout(function() {
|
|
self.timer = null;
|
|
if (self.status === 'disconnected') { self.connect(self.url); }
|
|
}, 3000);
|
|
}
|
|
};
|