dingdanquanliucheng/frontend/mini-app/utils/websocket.js

185 lines
3.7 KiB
JavaScript
Raw Normal View History

2026-06-20 09:19:16 +08:00
/**
* WebSocket 连接管理工具
* 职责建立和维护 WebSocket 连接接收实时推送消息
*/
var auth = require("./auth");
var config = require("../config");
var socketTask = null;
var heartbeatTimer = null;
var reconnectTimer = null;
var reconnectCount = 0;
var MAX_RECONNECT = 5;
var HEARTBEAT_INTERVAL = 30000; // 30秒心跳
var isConnecting = false;
/**
* 建立 WebSocket 连接
*/
function connect() {
if (socketTask || isConnecting) return;
var token = auth.getToken();
if (!token) {
console.log("[WS] 未登录,跳过连接");
return;
}
isConnecting = true;
var wsUrl = config.wsBaseUrl + "/ws/reminders?token=" + token;
console.log("[WS] 开始连接...");
socketTask = wx.connectSocket({
url: wsUrl,
success: function () {
console.log("[WS] 连接请求已发送");
},
});
socketTask.onOpen(function () {
console.log("[WS] 连接成功");
isConnecting = false;
reconnectCount = 0;
startHeartbeat();
});
socketTask.onMessage(function (res) {
try {
var data = JSON.parse(res.data);
if (data.type === "reminder") {
console.log("[WS] 收到提醒:", data.data);
handleMessage(data.data);
} else if (data.type === "connected") {
console.log("[WS] 服务端确认连接:", data.message);
}
} catch (e) {
console.error("[WS] 消息解析失败:", e);
}
});
socketTask.onClose(function (res) {
console.log("[WS] 连接关闭:", res);
isConnecting = false;
stopHeartbeat();
socketTask = null;
attemptReconnect();
});
socketTask.onError(function (err) {
console.error("[WS] 连接错误:", err);
isConnecting = false;
socketTask = null;
});
}
/**
* 断开 WebSocket 连接
*/
function disconnect() {
stopHeartbeat();
stopReconnect();
if (socketTask) {
try {
socketTask.close();
} catch (e) {
// ignore
}
socketTask = null;
}
isConnecting = false;
console.log("[WS] 已断开连接");
}
/**
* 启动心跳定时器
*/
function startHeartbeat() {
stopHeartbeat();
heartbeatTimer = setInterval(function () {
if (socketTask) {
try {
socketTask.send({ data: "ping" });
} catch (e) {
console.error("[WS] 心跳发送失败:", e);
}
}
}, HEARTBEAT_INTERVAL);
}
/**
* 停止心跳定时器
*/
function stopHeartbeat() {
if (heartbeatTimer) {
clearInterval(heartbeatTimer);
heartbeatTimer = null;
}
}
/**
* 尝试重连
*/
function attemptReconnect() {
if (reconnectCount >= MAX_RECONNECT) {
console.log("[WS] 达到最大重连次数,停止重连");
return;
}
var delay = Math.min(3000 * (reconnectCount + 1), 15000); // 递增延迟最大15秒
console.log("[WS] " + delay / 1000 + "秒后尝试第" + (reconnectCount + 1) + "次重连");
reconnectTimer = setTimeout(function () {
reconnectCount++;
connect();
}, delay);
}
/**
* 停止重连
*/
function stopReconnect() {
if (reconnectTimer) {
clearTimeout(reconnectTimer);
reconnectTimer = null;
}
reconnectCount = 0;
}
/**
* 处理收到的消息
*/
function handleMessage(data) {
var app = getApp();
if (!app) return;
// 触发全局事件
if (app._eventHandlers && app._eventHandlers["reminder"]) {
app._eventHandlers["reminder"].forEach(function (handler) {
try {
handler(data);
} catch (e) {
console.error("[WS] 事件处理异常:", e);
}
});
}
// 更新角标
var badge = require("./badge");
badge.updateTabBadge();
}
/**
* 获取连接状态
*/
function isConnected() {
return socketTask !== null && !isConnecting;
}
module.exports = {
connect: connect,
disconnect: disconnect,
isConnected: isConnected,
};