import { ref, onMounted, onBeforeUnmount } from 'vue';
|
import { getToken } from './auth';
|
|
|
type WsCallbacks = {
|
onMessage?: (data: any) => void;
|
onError?: (error: Event) => void;
|
onClose?: (event: CloseEvent) => void;
|
};
|
export function useWebSocket( callbacks: WsCallbacks = {},options?:{heartbeatInterval?:number;// 心跳间隔时间
|
timeout?:number;// 时间
|
}) {
|
const {heartbeatInterval=3000,timeout=10000} = options || {};
|
// 新增重连控制变量
|
let isReconnecting = false;
|
let activeRetries = 0;
|
const maxRetries = 3;
|
|
let heartbeatTimer:number|null = null;
|
let lastActivity = Date.now();
|
const ws = ref<WebSocket>();
|
const isConnected = ref(false);
|
// 心跳定时器逻辑
|
const resetHeartbeat = () => {
|
if (heartbeatTimer !== null) {
|
clearInterval(heartbeatTimer);
|
}
|
heartbeatTimer = setInterval(() => {
|
if (ws.value?.readyState === WebSocket.OPEN) {
|
// 重置重试次数
|
activeRetries = 0;
|
ws.value.send(JSON.stringify({ type: 'ping' }));
|
if (Date.now() - lastActivity > timeout) {
|
console.log(`心跳超时(${timeout}ms),触发重连`);
|
reconnect();
|
}
|
}
|
}, heartbeatInterval) as unknown as number;
|
};
|
// 更新最后活跃时间
|
const updateActivity = () => {
|
lastActivity = Date.now();
|
};
|
const enhancedCallbacks = {
|
...callbacks,
|
onMessage: (data: any) => {
|
updateActivity();
|
callbacks.onMessage?.(data);
|
},
|
onError: (error: Event) => {
|
callbacks.onError?.(error);
|
reconnect();
|
}
|
};
|
|
// 初始化WebSocket连接
|
const connect = () => {
|
const token = getToken();
|
const fullUrl = `/ws?token=${token}`;
|
|
ws.value = new WebSocket(fullUrl);
|
|
ws.value.onopen = () => {
|
isConnected.value = true;
|
resetHeartbeat(); // 连接成功后启动心跳
|
};
|
// 修改WebSocket事件处理逻辑
|
ws.value.onmessage = (e) => {
|
try {
|
const response = JSON.parse(e.data);
|
if (response.type === 'pong') {
|
updateActivity();
|
return;
|
}
|
enhancedCallbacks.onMessage?.(response.data); // 改用增强回调
|
} catch (error:any) {
|
enhancedCallbacks.onError?.(error); // 改用增强回调
|
}
|
};
|
|
ws.value.onerror = (error) => {
|
enhancedCallbacks.onError?.(error); // 改用增强回调
|
};
|
|
ws.value.onclose = (event) => {
|
isConnected.value = false;
|
enhancedCallbacks.onClose?.(event); // 改用增强回调
|
};
|
};
|
// 自动重连机制
|
const reconnect = ( delay = 3000) => {
|
if (!isReconnecting && activeRetries < maxRetries) {
|
isReconnecting = true;
|
activeRetries++;
|
|
setTimeout(() => {
|
if (ws.value) {
|
ws.value.close(); // 先关闭旧连接
|
}
|
connect();
|
isReconnecting = false;
|
}, delay);
|
}
|
};
|
|
onMounted(() => {
|
if (!ws.value || ws.value.readyState === WebSocket.CLOSED) {
|
connect();
|
}
|
});
|
|
onBeforeUnmount(() => {
|
if (heartbeatTimer) {
|
clearInterval(heartbeatTimer);
|
}
|
if (ws.value && isConnected.value) {
|
ws.value.close();
|
}
|
});
|
|
return {
|
ws,
|
isConnected,
|
reconnect
|
};
|
}
|