Files
shoot-miniprograms/src/websocket.js
2025-07-15 18:14:59 +08:00

143 lines
3.3 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.

import { MESSAGETYPES } from "@/constants";
let socket = null;
let heartbeatInterval = null;
let reconnectCount = 0;
let reconnectTimer = null;
// 重连配置
const RECONNECT_CONFIG = {
MAX_COUNT: 999, // 最大重连次数
INITIAL_DELAY: 2000, // 初始重连延迟2秒
MAX_DELAY: 5000, // 最大重连延迟5秒
};
/**
* 建立 WebSocket 连接
*/
function createWebSocket(token, onMessage) {
const url = `wss://api.shelingxingqiu.com/socket?authorization=${token}`;
socket = uni.connectSocket({
url,
success: () => {
console.log("websocket 连接成功");
reconnectCount = 0; // 重置重连次数
// 启动心跳
startHeartbeat();
},
fail: () => {
reconnect(onMessage);
},
});
// 接收消息
uni.onSocketMessage((res) => {
const data = JSON.parse(res.data);
if (data.event === "pong" || !data.data.updates) return;
if (onMessage) onMessage(data.data.updates);
const msg = data.data.updates[0];
if (!msg) return;
if (msg.constructor === MESSAGETYPES.BackToGame) {
const { battleInfo } = msg;
uni.setStorageSync("current-battle", battleInfo);
// 约战
if (battleInfo.config.battleMode === 1) {
uni.navigateTo({
url: `/pages/battle-room?battleId=${battleInfo.id}`,
});
}
// 排位
if (battleInfo.config.battleMode === 2) {
if (battleInfo.config.mode === 1) {
uni.navigateTo({
url: `/pages/team-match?battleId=${battleInfo.id}`,
});
} else if (battleInfo.config.mode === 2) {
uni.navigateTo({
url: `/pages/melee-match?battleId=${battleInfo.id}`,
});
}
}
}
if (msg.constructor === MESSAGETYPES.PaySuccess) {
console.log(1111111, msg);
}
});
// 错误处理
uni.onSocketError((err) => {
console.error("WebSocket 错误", err);
reconnect(token, onMessage);
});
uni.onSocketClose((result) => {
console.log("WebSocket 已关闭", result);
stopHeartbeat();
reconnect(onMessage);
});
}
/**
* 重连机制
*/
function reconnect(onMessage) {
if (reconnectCount >= RECONNECT_CONFIG.MAX_COUNT) return;
reconnectTimer && clearTimeout(reconnectTimer);
const token = uni.getStorageSync("token");
if (!token) return;
// 计算重连延迟(指数退避)
const delay = Math.min(
RECONNECT_CONFIG.INITIAL_DELAY * Math.pow(2, reconnectCount),
RECONNECT_CONFIG.MAX_DELAY
);
reconnectTimer = setTimeout(() => {
console.log("reconnecting...");
createWebSocket(token, onMessage);
reconnectCount++;
}, delay);
}
function closeWebSocket() {
if (socket) {
// 清理重连定时器
reconnectCount = 0;
reconnectTimer && clearTimeout(reconnectTimer);
stopHeartbeat();
socket.close();
}
}
/**
* 启动心跳
*/
function startHeartbeat() {
stopHeartbeat(); // 防止重复启动
heartbeatInterval = setInterval(() => {
if (socket) {
uni.sendSocketMessage({
data: JSON.stringify({ event: "ping", data: {} }),
fail: (err) => {
console.error("发送心跳失败", err);
},
});
}
}, 10000);
}
/**
* 停止心跳
*/
function stopHeartbeat() {
if (heartbeatInterval) {
clearInterval(heartbeatInterval);
heartbeatInterval = null;
}
}
export default {
createWebSocket,
closeWebSocket,
};