|
@ -0,0 +1,108 @@ |
|
|
|
|
|
import { Subject } from "rxjs"; |
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
|
|
|
|
|
|
|
readonly dataOb = new Subject() |
|
|
|
|
|
readonly stateOb = new Subject<SocketState>() |
|
|
|
|
|
|
|
|
|
|
|
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.stateOb.next('open') |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// 接收消息的处理
|
|
|
|
|
|
this.ws.onmessage = (event: MessageEvent) => { |
|
|
|
|
|
try { |
|
|
|
|
|
const data = JSON.parse(event.data); |
|
|
|
|
|
// console.log('🚀 ~ WebSocketClient ~ bindEvents ~ data:', data)
|
|
|
|
|
|
this.dataOb.next(data) |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error("消息解析错误:", error); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
this.ws.onclose = () => { |
|
|
|
|
|
this.stateOb.next('close') |
|
|
|
|
|
console.log("WebSocket 连接已关闭"); |
|
|
|
|
|
this.reconnect(); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
this.ws.onerror = error => { |
|
|
|
|
|
this.stateOb.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; |
|
|
|
|
|
} |
|
|
|
|
|
}; |