You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
import { Subject } from "rxjs"; import type { Datagram } from "./wsTypes";
export type SocketState = "open" | "close" | "error";
class WebSocketClient { private ws: WebSocket | null = null; private url: string; private reconnectAttempts: number = -1; private maxReconnectAttempts: number = 5; private reconnectInterval: number = 3000;
private dataSub = new Subject<Datagram>(); get dataOb() { return this.dataSub.asObservable(); } private stateSub = new Subject<SocketState>(); get stateOb() { return this.stateSub.asObservable(); } constructor(url: string) { this.url = url; }
// 连接 WebSocket
connect(): void { try { // WebSocket.CONNECTING (0) WebSocket.OPEN (1)
if (this.ws && this.ws.readyState <= 1) { // 已连接
console.log(`${this.url} 正在连接或已连接,无需重复连接`); } else { this.ws = new WebSocket(this.url); this.bindEvents(); } } catch (error) { console.error("WebSocket 连接失败:", error); this.reconnect(); } }
// 绑定事件
private bindEvents(): void { if (!this.ws) return;
// 连接建立时的处理
this.ws.onopen = () => { console.log("WebSocket 连接已建立"); this.reconnectAttempts = -1; // 重置重连次数
this.stateSub.next("open"); };
// 接收消息的处理
this.ws.onmessage = (event: MessageEvent) => { try { const data = JSON.parse(event.data) as Datagram; // console.log("🚀 ~ WebSocketClient ~ bindEvents ~ data:", data);
if (data.type === "cmd") { this.dataSub.next({ type: data.type, data: { ...data.data, success: data.data.status === "D0000" } }); } else { this.dataSub.next(data); } } catch (error) { console.error("消息解析错误:", error); } };
this.ws.onclose = () => { this.stateSub.next("close"); console.log("WebSocket 连接已关闭"); this.reconnect(); };
this.ws.onerror = error => { this.stateSub.next("error"); console.error("WebSocket 错误:", error); }; }
// 重连机制
private reconnect(): void { if (this.reconnectAttempts === -1) { this.reconnectAttempts = 0; } if (this.reconnectAttempts >= this.maxReconnectAttempts) { console.log("达到最大重连次数,停止重连"); this.reconnectAttempts = -1; return; }
setTimeout(() => { console.log(`尝试第 ${this.reconnectAttempts + 1} 次重连...`); this.reconnectAttempts++; this.connect(); }, this.reconnectInterval); }
// 关闭连接
disconnect(): void { if (this.ws) { this.ws.close(); this.ws = null; } } }
const urlSocketMap = new Map<string, WebSocketClient>();
// 导出 WebSocket 客户端
export const createWebSocket = (url: string): WebSocketClient => { if (urlSocketMap.has(url)) { return urlSocketMap.get(url)!; } else { const client = new WebSocketClient(url); urlSocketMap.set(url, client); return client; } };
// export const sharedWsUrl = `ws://${window.location.hostname}:8080/ws`;
export const sharedWsUrl = `ws://${import.meta.env.VITE_API_HOST}:${import.meta.env.VITE_API_PORT}${ import.meta.env.VITE_WS_PATH }`;
|