Files

179 lines
3.4 KiB
JavaScript
Raw Permalink 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 { 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;
}
}