// useWebSocket.js
|
import { ref, onMounted, onUnmounted } from "vue";
|
import getWsUrl from "@/utils/getWsUrl";
|
import mitt from "mitt";
|
|
/**
|
*
|
* @param url socket的名称
|
* @returns {{socket: Ref<UnwrapRef<null>>, isConnected: Ref<UnwrapRef<boolean>>, message: Ref<UnwrapRef<string>>, sendData: sendData, eventBus: Emitter<Record<EventType, unknown>>}}
|
*/
|
export default function (url: string) {
|
url = getWsUrl(url);
|
const socket = ref<WebSocket>();
|
const isConnected = ref(false);
|
const message = ref("");
|
|
const eventBus = mitt();
|
let isManualClose = ref(false); // 是否手动关闭
|
let reconnectTimer: any; // 重连计时器
|
const reconnectInterval = 1000; // 初始重连间隔(ms)
|
const maxInterval = 30000; // 最大重连间隔(ms)
|
let retryCount = 0; // 重连计数
|
|
const connect = () => {
|
if (socket.value) {
|
socket.value.close();
|
}
|
socket.value = new WebSocket(url);
|
socket.value.onopen = () => {
|
isConnected.value = true;
|
retryCount = 0;
|
console.log("WebSocket Connected, url: ", url);
|
eventBus.emit("onopen", true);
|
};
|
|
socket.value.onmessage = (event) => {
|
// 处理接收到的消息
|
// console.log("Received:", event.data);
|
// 可以在这里通过 emit 发送消息到组件
|
message.value = event.data;
|
eventBus.emit("message", event.data);
|
};
|
|
socket.value.onerror = (error) => {
|
console.error("WebSocket Error:", error, url);
|
eventBus.emit("error", error);
|
socket.value?.close();
|
};
|
|
socket.value.onclose = () => {
|
isConnected.value = false;
|
// 手动关闭就不需要再重连了
|
if (isManualClose.value) return;
|
console.log("WebSocket 连接已关闭, url: ", url);
|
scheduleReconnect();
|
};
|
};
|
|
// 发送数据
|
const sendData = (data: any) => {
|
console.log(socket.value?.readyState);
|
if (socket.value && socket.value.readyState === socket.value.OPEN) {
|
console.log("send", data, "=============");
|
socket.value.send(data);
|
}
|
};
|
|
// 定时重连(指数退避)
|
const scheduleReconnect = () => {
|
const delay = Math.min(reconnectInterval * 2 ** retryCount, maxInterval);
|
console.log(`第${retryCount + 1}次重试,${delay}ms后重连${url}`);
|
reconnectTimer = setTimeout(() => {
|
retryCount++;
|
connect();
|
}, delay);
|
};
|
|
const close = () => {
|
isManualClose.value = true; // 手动关闭
|
if (socket.value) {
|
socket.value.close();
|
}
|
clearTimeout(reconnectTimer);
|
};
|
|
onMounted(() => {
|
connect();
|
});
|
|
onUnmounted(() => {
|
close();
|
});
|
|
// 返回 socket 对象和状态
|
return { socket, isConnected, message, sendData, eventBus };
|
}
|