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

190 lines
3.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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;
// 如果是重连成功,触发提醒事件让页面刷新数据
if (reconnectCount > 0) {
console.log("[WS] 重连成功,触发提醒事件刷新数据");
handleMessage({ type: "reconnected" });
}
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,
};