2025-03-13 18:26:03 +08:00
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 定义连接服务器的方法
|
2025-04-14 11:13:18 +08:00
|
|
|
|
public async connect(id: string) {
|
2025-03-13 18:26:03 +08:00
|
|
|
|
if (!window.WebSocket) {
|
|
|
|
|
|
console.log('您的浏览器不支持WebSocket')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-14 11:13:18 +08:00
|
|
|
|
const response = await fetch('/')
|
|
|
|
|
|
const mqttUrl = response.headers.get('X-Mqtt-Url')
|
|
|
|
|
|
setTimeout(() => {
|
2025-04-16 09:43:27 +08:00
|
|
|
|
const url = (mqttUrl || 'ws://192.168.1.31:10407/api/pushMessage/') + id
|
2025-04-14 11:13:18 +08:00
|
|
|
|
this.ws = new WebSocket(url)
|
2025-03-13 18:26:03 +08:00
|
|
|
|
|
2025-04-14 11:13:18 +08:00
|
|
|
|
this.ws.onopen = () => this.handleOpen()
|
|
|
|
|
|
this.ws.onclose = () => this.handleClose()
|
|
|
|
|
|
this.ws.onerror = () => this.handleError()
|
|
|
|
|
|
this.ws.onmessage = event => this.handleMessage(event)
|
|
|
|
|
|
}, 0)
|
2025-03-13 18:26:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理连接成功事件
|
|
|
|
|
|
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关闭命令..')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|