Files

179 lines
3.4 KiB
JavaScript
Raw Permalink Normal View History

2026-04-23 14:35:54 +08:00
import { getToken } from "../until";
let ws = null;
let reconnectTimer = null;
let manualClose = false;
let retryCount = 0;
const subscribers = new Set();
const WS_PATH = "/ws";
const MAX_RECONNECT_DELAY = 30000;
function getWsBaseUrl() {
const baseApi = import.meta.env.VITE_APP_BASE_API || "";
if (/^https?:\/\//.test(baseApi)) {
return baseApi.replace(/^http/, "ws").replace(/\/$/, "");
}
// UniApp 没有 window用 uni 接口获取
const platform = uni.getSystemInfoSync().platform;
const isH5 = platform === "h5";
const protocol =
isH5 && window.location.protocol === "https:" ? "wss:" : "ws:";
let host = "";
if (isH5) {
host = window.location.host;
} else {
// 非H5小程序/App需要你配置真实域名
host = "你的后端域名";
}
return `${protocol}//${host}${baseApi}`.replace(/\/$/, "");
}
function buildWsUrl() {
const baseUrl = getWsBaseUrl();
const url = `${baseUrl}${WS_PATH}`;
const token = getToken();
const params = new URLSearchParams();
if (token) {
params.append("token", token);
}
const query = params.toString();
return query ? `${url}?${query}` : url;
}
export function connectWs(onMessage) {
if (!getToken()) {
console.warn("[WebSocket] missing token");
return;
}
if (typeof onMessage === "function") {
subscribers.add(onMessage);
}
manualClose = false;
clearReconnectTimer();
if (ws) {
return;
}
// ========== UniApp 专用 ==========
ws = uni.connectSocket({
url: buildWsUrl(),
success: () => {},
});
ws.onOpen = () => {
retryCount = 0;
console.log("[WebSocket] connected");
};
ws.onMessage = (event) => {
let data = event.data;
try {
data = JSON.parse(event.data);
} catch (e) {}
subscribers.forEach((handler) => {
try {
handler(data, event);
} catch (error) {
console.error("[WebSocket] subscriber error", error);
}
});
};
ws.onClose = () => {
console.log("[WebSocket] closed");
ws = null;
if (!manualClose && subscribers.size > 0) {
reconnectTimer = setTimeout(() => {
console.log("[WebSocket] reconnecting");
connectWs();
}, getReconnectDelay());
}
};
ws.onError = (error) => {
console.error("[WebSocket] error", error);
};
}
export function closeWs(onMessage) {
if (typeof onMessage === "function") {
subscribers.delete(onMessage);
} else {
subscribers.clear();
}
if (subscribers.size > 0) {
return;
}
manualClose = true;
retryCount = 0;
clearReconnectTimer();
if (ws) {
ws.close();
ws = null;
}
}
export function reconnectWs(onMessage) {
if (typeof onMessage === "function") {
subscribers.add(onMessage);
}
manualClose = false;
retryCount = 0;
clearReconnectTimer();
if (ws) {
ws.close();
ws = null;
}
manualClose = false;
connectWs();
}
export function sendWs(data) {
if (!ws) {
console.warn("[WebSocket] send failed, socket is not open");
return false;
}
ws.send({
data: typeof data === "string" ? data : JSON.stringify(data),
success: () => {},
fail: () => {},
});
return true;
}
export function getWsState() {
if (!ws) return 3; // CLOSED
return ws.readyState;
}
function getReconnectDelay() {
retryCount += 1;
return Math.min(5000 * retryCount, MAX_RECONNECT_DELAY);
}
function clearReconnectTimer() {
if (reconnectTimer) {
clearTimeout(reconnectTimer);
reconnectTimer = null;
}
}