mirror of
https://gitee.com/mirrors/AllinSSL.git
synced 2026-03-10 00:31:10 +08:00
145 lines
4.5 KiB
TypeScript
145 lines
4.5 KiB
TypeScript
import { ref } from 'vue'
|
||
|
||
export interface SocketOptions {
|
||
autoReconnect?: boolean // 是否自动重连, 默认为 true
|
||
middleware?: (data: any) => any // 数据中间件函数,支持原始数据处理,默认为直接返回,支持多个中间件
|
||
maxReconnectAttempts?: number // 最大重连次数, 默认无限制
|
||
reconnectDelay?: number // 重连延迟, 默认为3000ms
|
||
heartbeatInterval?: number // 心跳间隔, 单位毫秒
|
||
heartbeatMessage?: any // 心跳包消息
|
||
}
|
||
|
||
/**
|
||
* @description 将对象参数拼接到 URL 上,返回新的 URL 字符串
|
||
* @param url - 基础 URL(如 'https://example.com')
|
||
* @param obj - 要拼接到 URL 上的对象参数(键值对)
|
||
* @returns 拼接参数后的完整 URL 字符串
|
||
*/
|
||
export function setObjToUrlParams(url: string, obj: Record<string, any>): string {
|
||
// 将对象的每一个键值对转换成 'key=value' 形式,并且对 value 做 URL 编码
|
||
const paramsArray: string[] = Object.entries(obj).map(([key, value]) => {
|
||
return `${String(key)}=${encodeURIComponent(String(value))}`
|
||
})
|
||
|
||
// 将所有 'key=value' 形式的字符串用 '&' 符号连接起来,形成 URL 查询字符串
|
||
const parameters: string = paramsArray.join('&')
|
||
|
||
// 判断原 URL 是否以 '?' 结尾
|
||
const hasQuestionMarkAtEnd: boolean = /\?$/.test(url)
|
||
|
||
// 根据 URL 是否已经有 '?' 来决定如何拼接参数
|
||
if (hasQuestionMarkAtEnd) {
|
||
// 如果 URL 已经以 '?' 结尾,直接加参数
|
||
return url + parameters
|
||
} else {
|
||
// 如果 URL 没有以 '?' 结尾,需要先去除可能的结尾 '/',然后加上 '?'
|
||
const cleanUrl = url.replace(/\/?$/, '')
|
||
return cleanUrl + '?' + parameters
|
||
}
|
||
}
|
||
|
||
export default function useSocket(url: string, options?: SocketOptions) {
|
||
const {
|
||
autoReconnect = true,
|
||
reconnectDelay = 3000,
|
||
middleware = (data: any) => data,
|
||
maxReconnectAttempts,
|
||
heartbeatInterval = 5000,
|
||
heartbeatMessage = 'ping',
|
||
} = options || {}
|
||
|
||
const socket = ref<WebSocket | null>(null)
|
||
const connected = ref(false)
|
||
const message = ref<any>(null)
|
||
let manuallyDisconnected = false // 标记是否主动断开
|
||
|
||
// 新增重连计数与心跳定时器变量
|
||
let reconnectAttempts = 0
|
||
let heartbeatTimer: ReturnType<typeof setInterval> | null = null
|
||
|
||
// 建立WebSocket连接
|
||
const connect = () => {
|
||
// 兼容检测:若当前环境不支持 WebSocket,则打印错误并退出
|
||
if (typeof WebSocket === 'undefined') {
|
||
console.error('WebSocket is not supported in this environment.')
|
||
return
|
||
}
|
||
manuallyDisconnected = false // 重置主动断开标记
|
||
// 清除之前的心跳定时器
|
||
if (heartbeatTimer) {
|
||
clearInterval(heartbeatTimer)
|
||
heartbeatTimer = null
|
||
}
|
||
socket.value = new WebSocket(url)
|
||
|
||
// 连接成功的回调
|
||
socket.value.onopen = () => {
|
||
console.log(4123432)
|
||
connected.value = true
|
||
reconnectAttempts = 0 // 重置重连计数
|
||
// 如果配置了心跳包,启动心跳定时器
|
||
if (heartbeatInterval && heartbeatMessage !== undefined) {
|
||
heartbeatTimer = setInterval(() => {
|
||
if (socket.value && connected.value) {
|
||
socket.value.send(heartbeatMessage)
|
||
}
|
||
}, heartbeatInterval)
|
||
}
|
||
}
|
||
|
||
// 收到消息后,使用中间件处理数据
|
||
socket.value.onmessage = (event: MessageEvent) => {
|
||
message.value = middleware(event.data)
|
||
}
|
||
|
||
// 出现错误时打印日志
|
||
socket.value.onerror = (error) => {
|
||
console.error('WebSocket error:', error)
|
||
}
|
||
|
||
// 关闭连接的回调,判断是否需要自动重连
|
||
socket.value.onclose = () => {
|
||
connected.value = false // 更新连接状态
|
||
socket.value = null
|
||
// 清除心跳定时器
|
||
if (heartbeatTimer) {
|
||
clearInterval(heartbeatTimer)
|
||
heartbeatTimer = null
|
||
}
|
||
// 如果自动重连且未主动断开,则在延迟后重连
|
||
if (autoReconnect && !manuallyDisconnected) {
|
||
if (maxReconnectAttempts !== undefined) {
|
||
if (reconnectAttempts < maxReconnectAttempts) {
|
||
reconnectAttempts++
|
||
setTimeout(() => connect(), reconnectDelay)
|
||
}
|
||
} else {
|
||
setTimeout(() => connect(), reconnectDelay)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 主动断开连接,禁止自动重连
|
||
const disconnect = () => {
|
||
manuallyDisconnected = true // 标记为主动断开
|
||
if (socket.value) {
|
||
socket.value.close()
|
||
}
|
||
// 清除心跳定时器
|
||
if (heartbeatTimer) {
|
||
clearInterval(heartbeatTimer)
|
||
heartbeatTimer = null
|
||
}
|
||
}
|
||
|
||
// 发送数据方法,仅在连接状态时执行
|
||
const send = (data: any) => {
|
||
if (socket.value && connected.value) {
|
||
socket.value.send(data)
|
||
}
|
||
}
|
||
|
||
return { socket, connect, disconnect, send, message, connected }
|
||
}
|