石墨仪设备 前端仓库
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.
 
 
 
 
 

123 lines
3.0 KiB

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
}`;