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