Files
admin-sjzx/src/utils/webSocketClient.ts
2025-04-16 09:43:27 +08:00

202 lines
6.4 KiB
TypeScript
Raw 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 { ElMessage, EVENT_CODE } from 'element-plus'
// 定义消息类型,用于类型检查
type MessageType = {
[key: string]: any
}
export default class SocketService {
// 单例模式实例
private static instance: SocketService | null = null
// 和服务端连接的socket对象
private ws: WebSocket | null = null
// 存储回调函数
private callBackMapping: { [key: string]: ((message: MessageType) => void) | null } = {}
// 标识是否连接成功
private connected: boolean = false
// 记录重试的次数
private sendRetryCount: number = 0
// 重新连接尝试的次数
private connectRetryCount: number = 0
// Web Worker 实例
private work: Worker | null = null
// 临时的 Blob URL
private workerBlobUrl: string | null = null
// 上次活动时间戳
private lastActivityTime: number = 0
// 最后一次收到心跳回复时间
private lastResponseHeartTime: number = Date.now()
// 重新连接延迟,单位毫秒
private reconnectDelay: number = 5000
// 单例模式获取实例
public static get Instance(): SocketService {
if (!this.instance) {
this.instance = new SocketService()
}
return this.instance
}
// 定义连接服务器的方法
public async connect(id: string) {
if (!window.WebSocket) {
console.log('您的浏览器不支持WebSocket')
return
}
const response = await fetch('/')
const mqttUrl = response.headers.get('X-Mqtt-Url')
setTimeout(() => {
const url = (mqttUrl || 'ws://192.168.1.31:10407/api/pushMessage/') + id
this.ws = new WebSocket(url)
this.ws.onopen = () => this.handleOpen()
this.ws.onclose = () => this.handleClose()
this.ws.onerror = () => this.handleError()
this.ws.onmessage = event => this.handleMessage(event)
}, 0)
}
// 处理连接成功事件
private handleOpen(): void {
ElMessage.success('webSocket连接服务端成功了')
console.log('连接服务端成功了')
this.connected = true
this.connectRetryCount = 0
this.updateLastActivityTime()
this.startHeartbeat()
}
// 处理连接关闭事件
private handleClose(): void {
console.log('连接webSocket服务端关闭')
this.connected = false
this.connectRetryCount++
this.clearHeartbeat()
// 可根据需要添加重连逻辑
// setTimeout(() => this.connect(), 500 * this.connectRetryCount);
}
// 处理连接错误事件
private handleError(): void {
ElMessage.error('webSocket连接异常')
}
// 处理服务端发送过来的数据
private handleMessage(event: MessageEvent): void {
// console.log('🚀 ~ SocketService ~ handleMessage ~ event.data:', event.data)
if (event.data == '连接成功') {
this.sendHeartbeat()
} else if (event.data.length > 10) {
let message: MessageType
try {
// console.log('Received message:', event.data)
message = JSON.parse(event.data)
} catch (e) {
console.error('消息解析失败', event.data, e)
return
}
// console.log("🚀 ~ SocketService ~ handleMessage ~ message:", message)
// 通过接受服务端发送的type字段来回调函数
if (message.key && this.callBackMapping['message']) {
this.callBackMapping['message']!(message)
} else {
console.log('抛弃====>')
// console.log(event.data)
// 丢弃或继续写你的逻辑
}
} else {
ElMessage.error(event.data)
}
}
// 启动心跳检测
private startHeartbeat(): void {
this.lastResponseHeartTime = Date.now()
const url = window.URL.createObjectURL(
new Blob(['(function(e){setInterval(function(){this.postMessage(null)},30000)})()'])
)
this.workerBlobUrl = url
this.work = new Worker(url)
this.work.onmessage = e => this.handleWorkerMessage(e)
}
// 处理 Web Worker 消息
private handleWorkerMessage(e: MessageEvent): void {
// if (this.lastActivityTime - this.lastResponseHeartTime > 30000) {
// // 说明已经三轮心跳没收到回复了,关闭检测,提示用户。
// // ElMessage.error('业务主体模块发生未知异常,请尝试重新启动!')
// this.clearHeartbeat()
// return
// }
// console.log(123);
this.sendHeartbeat()
}
// 发送心跳消息
private sendHeartbeat(): void {
// console.log(new Date() + '进入心跳消息发送。。。。。。。。。。。。。')
if (this.ws) {
this.ws.send('alive')
this.updateLastActivityTime()
}
}
// 更新活动时间
private updateLastActivityTime(): void {
this.lastActivityTime = Date.now()
}
// 清除心跳检测
private clearHeartbeat(): void {
if (this.work) {
this.work.terminate()
this.work = null
}
if (this.workerBlobUrl) {
window.URL.revokeObjectURL(this.workerBlobUrl)
this.workerBlobUrl = null
}
}
// 回调函数的注册
public registerCallBack(socketType: string, callBack: (message: MessageType) => void): void {
this.callBackMapping[socketType] = callBack
}
// 取消某一个回调函数
public unRegisterCallBack(socketType: string): void {
this.callBackMapping[socketType] = null
}
// 发送数据的方法
public send(data: any): void {
if (this.connected) {
this.sendRetryCount = 0
try {
if (this.ws) {
this.ws.send(JSON.stringify(data))
}
} catch (e) {
if (this.ws) {
this.ws.send(data)
}
}
} else {
this.sendRetryCount++
setTimeout(() => this.send(data), this.sendRetryCount * 500)
}
}
// 断开方法
public closeWs(): void {
if (this.connected && this.ws) {
this.ws.close()
}
console.log('执行WS关闭命令..')
}
}