|
|
|
|
|
|
|
|
|
import { ref, onMounted, onUnmounted } from 'vue';
|
|
|
|
|
|
|
|
|
|
let heartbeatTimer: NodeJS.Timeout;
|
|
|
|
|
|
|
|
|
|
export default function () {
|
|
|
|
|
|
|
|
|
|
const socket = ref<WebSocket | null>(null);
|
|
|
|
|
const message = ref<string>();
|
|
|
|
|
const status = ref<'connecting' | 'open' | 'error' | 'closed'>('closed');
|
|
|
|
|
const pendingMessages = ref([]);
|
|
|
|
|
const reconnectAttempts = ref(0);
|
|
|
|
|
const maxReconnectAttempts = 5;
|
|
|
|
|
const isConnected = computed(() => { return status.value === 'open' });
|
|
|
|
|
const isConnecting = computed(() => { return status.value === 'connecting' });
|
|
|
|
|
const config = useRuntimeConfig();
|
|
|
|
|
|
|
|
|
|
const connectionTimeout = config.public.apiTimeout || 5000; // 5秒连接超时
|
|
|
|
|
|
|
|
|
|
// 初始化连接
|
|
|
|
|
const connect = () => {
|
|
|
|
|
if (isConnected.value || isConnecting.value) return;
|
|
|
|
|
status.value = 'connecting';
|
|
|
|
|
socket.value = new WebSocket(config.public.wsUrl, "json");
|
|
|
|
|
|
|
|
|
|
socket.value.onopen = () => {
|
|
|
|
|
status.value = 'open';
|
|
|
|
|
reconnectAttempts.value = 0;
|
|
|
|
|
console.log('WebSocket连接成功');
|
|
|
|
|
|
|
|
|
|
retryPendingMessages();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
socket.value.onmessage = (event) => {
|
|
|
|
|
message.value = event.data;
|
|
|
|
|
// console.log('收到消息:', event.data);
|
|
|
|
|
// try {
|
|
|
|
|
// const json = JSON.parse(event.data);
|
|
|
|
|
// // console.info(json);
|
|
|
|
|
// const evtType = json.type;
|
|
|
|
|
// console.log(evtType)
|
|
|
|
|
// }
|
|
|
|
|
// finally{
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
socket.value.onerror = (error) => {
|
|
|
|
|
status.value = 'error';
|
|
|
|
|
console.error('WebSocket发生错误:', error);
|
|
|
|
|
|
|
|
|
|
// 重试逻辑
|
|
|
|
|
if (reconnectAttempts.value < maxReconnectAttempts) {
|
|
|
|
|
setTimeout(connect, 1000 * reconnectAttempts.value);
|
|
|
|
|
reconnectAttempts.value++;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
socket.value.onclose = (event) => {
|
|
|
|
|
status.value = 'closed';
|
|
|
|
|
console.log('WebSocket连接关闭');
|
|
|
|
|
if (!event.wasClean) {
|
|
|
|
|
// 非正常关闭时尝试重连
|
|
|
|
|
connect();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 等待连接就绪
|
|
|
|
|
const waitForConnection = () => {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
if (isConnected.value) {
|
|
|
|
|
resolve(true);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置连接超时
|
|
|
|
|
const timeout = setTimeout(() => {
|
|
|
|
|
reject(new Error('连接超时'));
|
|
|
|
|
}, connectionTimeout);
|
|
|
|
|
|
|
|
|
|
// 监听连接状态变化
|
|
|
|
|
const watchHandle = watch(isConnected, (newVal) => {
|
|
|
|
|
if (newVal) {
|
|
|
|
|
clearTimeout(timeout);
|
|
|
|
|
watchHandle(); // 取消监听
|
|
|
|
|
resolve(true);
|
|
|
|
|
}
|
|
|
|
|
}, { immediate: true });
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 发送消息
|
|
|
|
|
const send = async (name: string, json: object, token: string = '') => {
|
|
|
|
|
const msg = {
|
|
|
|
|
type: name,
|
|
|
|
|
drawerToken: token || localStorage.getItem('drawerToken') || '',
|
|
|
|
|
data: json
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
// 等待连接就绪
|
|
|
|
|
await waitForConnection();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
socket.value.send(JSON.stringify(msg));
|
|
|
|
|
if (name != 'ping' && name != 'MouseMove') {
|
|
|
|
|
console.log('发送消息:', msg);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('消息发送失败:', error);
|
|
|
|
|
// 添加到待发队列
|
|
|
|
|
pendingMessages.value.push(JSON.stringify({ type: name, data: json }));
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 重发待处理消息
|
|
|
|
|
const retryPendingMessages = () => {
|
|
|
|
|
while (pendingMessages.value.length > 0) {
|
|
|
|
|
const message = pendingMessages.value.shift();
|
|
|
|
|
let jsonData = JSON.parse(message);
|
|
|
|
|
send(jsonData.type, jsonData.data);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const startHeartbeat = () => {
|
|
|
|
|
heartbeatTimer = setInterval(() => {
|
|
|
|
|
if (socket.value?.readyState === WebSocket.OPEN) {
|
|
|
|
|
send("ping", {});
|
|
|
|
|
// console.log('发送心跳');
|
|
|
|
|
}
|
|
|
|
|
}, 5000)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// const reconnect = ()=>{
|
|
|
|
|
// setTimeout(()=>{
|
|
|
|
|
// console.log('尝试重新连接WebSocket');
|
|
|
|
|
// connect();
|
|
|
|
|
// },50000)
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
connect();
|
|
|
|
|
startHeartbeat();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
if (heartbeatTimer) {
|
|
|
|
|
clearInterval(heartbeatTimer);
|
|
|
|
|
};
|
|
|
|
|
socket.value?.close();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return { message, status, send, connect, waitForConnection }
|
|
|
|
|
}
|