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.
 
 
 
 
 

224 lines
5.6 KiB

/*
* @description: 封装socket方法
* @date: 2023-01-20
* @author: 郭安鹏
*/
import { ElMessage } from 'element-plus'
import { ref } from 'vue'
export const isClose = ref(true)
interface socket {
appKey: any
websocket: any
connectURL: string
socket_open: boolean
hearBeat_timer: any
hearBeat_interval: number
is_reconnect: boolean
reconnect_count: number
reconnect_current: number
reconnect_number: number
reconnect_timer: any
reconnect_interval: number
receiveMessageCallBackObj: any
initCallBacks: any
// eslint-disable-next-line ts/no-unsafe-function-type
receiveMessage: Function
// eslint-disable-next-line ts/no-unsafe-function-type
registerCallback: Function
// eslint-disable-next-line ts/no-unsafe-function-type
registerInitCallback: Function
// eslint-disable-next-line ts/no-unsafe-function-type
init: (receiveMessage?: Function | null, type?: string, connectURL?: string) => any
heartbeat: () => void
heartSend: () => void
send: (data: any, callback?: any) => void
close: () => void
reconnect: () => void
sendAppJoin: () => void
}
// eslint-disable-next-line ts/no-redeclare
export const socket: socket = {
appKey: null,
websocket: null,
connectURL: import.meta.env.FT_WS_URL,
// 开启标识
socket_open: false,
// 心跳timer
hearBeat_timer: null,
// 心跳发送频率
hearBeat_interval: 500,
// 是否需要重连
is_reconnect: true,
// 重连次数
reconnect_count: 10,
// 已发起重连次数
reconnect_current: 1,
// 网络错误提示此时
reconnect_number: 0,
// 重连timer
reconnect_timer: null,
// 重连频率
reconnect_interval: 1000,
receiveMessageCallBackObj: {},
initCallBacks: [],
// eslint-disable-next-line ts/no-unsafe-function-type
registerInitCallback: (fn: Function, ...args: any) => {
// socket 连接成功后的回调
socket.initCallBacks.push({
fn,
args,
})
},
// 接收消息的方法
receiveMessage: (e: any) => {
const message = JSON.parse(e.data)
const fn = socket.receiveMessageCallBackObj[message.type]
if (fn) {
fn(message)
}
else {
console.error('请注册当前类型的回调函数', message)
}
},
registerCallback: (fn: any, type: any) => {
// 接收消息的回调
socket.receiveMessageCallBackObj[type] = fn
},
init: async (
receiveMessageCallBack: any,
type?: string,
connectURL?: string,
reconnection?: boolean,
) => {
if (!('WebSocket' in window)) {
ElMessage.warning('浏览器不支持WebSocket')
return null
}
// 注册回调函数
if (receiveMessageCallBack && type) {
socket.registerCallback(receiveMessageCallBack, type)
}
// 已经创建过连接无需重复创建
if (socket.websocket && !reconnection) {
return socket.websocket
}
await new Promise((rs) => {
socket.websocket = new WebSocket(connectURL || socket.connectURL)
// 消息接收
socket.websocket.onmessage = (e: any) => {
socket.receiveMessage(e)
}
// socket关闭
socket.websocket.onclose = () => {
console.error('onclose')
clearInterval(socket.hearBeat_interval)
socket.socket_open = false
isClose.value = true
// 需要重新连接
if (socket.is_reconnect) {
socket.reconnect_timer = setTimeout(() => {
// 超过重连次数
// if (socket.reconnect_current > socket.reconnect_count) {
// clearTimeout(socket.reconnect_timer);
// socket.is_reconnect = false;
// console.error('超出重连次数,不再重连', new Date());
// return;
// }
// 记录重连次数
socket.reconnect_current++
socket.reconnect()
}, socket.reconnect_interval)
}
}
// 连接发生错误
socket.websocket.onerror = function () {
console.error('onerror')
isClose.value = true
socket.socket_open = false
}
// 连接成功
socket.websocket.onopen = function () {
socket.socket_open = true
socket.is_reconnect = true
// 开启心跳
socket.heartbeat()
// 连接成功后发起app加入消息
socket.sendAppJoin()
for (const fnItem of socket.initCallBacks) {
fnItem.fn(...fnItem.args)
}
isClose.value = false
rs(true) // socket 已连接
}
})
},
send: (data, callback = null) => {
// 开启状态直接发送
if (socket.websocket.readyState === socket.websocket.OPEN) {
socket.websocket.send(JSON.stringify(data))
if (callback) {
callback()
}
}
else {
clearInterval(socket.hearBeat_timer)
socket.reconnect_number++
}
},
heartbeat: () => {
if (socket.hearBeat_timer) {
clearInterval(socket.hearBeat_timer)
}
socket.hearBeat_timer = setInterval(() => {
socket.heartSend()
}, socket.hearBeat_interval)
},
heartSend: () => {
socket.send({
type: 'ping', // ping
})
},
close: () => {
clearInterval(socket.hearBeat_timer)
socket.is_reconnect = false
socket.websocket && socket.websocket.close()
socket.websocket = null
},
/**
* 重新连接
*/
reconnect: () => {
if (socket.websocket) {
// 需要重连
if (socket.is_reconnect) {
socket.websocket.close()
socket.websocket = null
socket.init()
}
else {
socket.close()
}
}
},
sendAppJoin: () => {
socket.send({
appKey: socket.appKey,
type: 1, // appJoin
})
},
}