Files
nl-im-pc/src/composables/useWebSocket.js
2025-07-04 12:56:18 +08:00

249 lines
6.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { ref, onMounted, onUnmounted } from "vue"
import { useUserStore } from "@/stores/user"
import { useChatStore } from "@/stores/chat"
export function useWebSocket() {
const userStore = useUserStore()
const chatStore = useChatStore()
const socket = ref(null)
const isConnected = ref(false)
const isConnecting = ref(false)
const reconnectAttempts = ref(0)
const maxReconnectAttempts = 5
const reconnectDelay = ref(1000)
const connectWebSocket = () => {
if (isConnecting.value || isConnected.value) return
isConnecting.value = true
chatStore.connectionStatus = "connecting"
try {
const wsUrl = import.meta.env.VITE_WS_URL || "ws://localhost:12080/ws"
socket.value = new WebSocket(wsUrl)
socket.value.onopen = handleOpen
socket.value.onmessage = handleMessage
socket.value.onclose = disconnectWebSocket
socket.value.onerror = handleError
} catch (error) {
console.error("WebSocket连接失败:", error)
isConnecting.value = false
chatStore.connectionStatus = "disconnected"
}
}
const handleOpen = (event) => {
console.log("WebSocket连接已建立")
isConnected.value = true
isConnecting.value = false
reconnectAttempts.value = 0
reconnectDelay.value = 1000
chatStore.connectionStatus = "connected"
chatStore.socket = socket.value
}
const handleMessage = (event) => {
try {
const data = JSON.parse(event.data)
console.log("收到消息:", data)
// 处理客户端ID
if (data?.clientId) {
// console.log("收到客户端ID:", data.clientId)
// userStore.setClientId(data.clientId)
//
// // 绑定用户
// if (userStore.currentUser?.id) {
bindUser(userStore.currentUser.id)
// }
return
}
// 处理通话信令
if (data.call_id && data.call_status) {
handleCallSignal(data)
return
}
// 处理普通消息
if (data.sender_user_id && data.receiver_user_id) {
chatStore.handleIncomingMessage(data, userStore.currentUser?.id)
}
} catch (error) {
console.error("解析WebSocket消息失败:", error)
}
}
const disconnectWebSocket = (event) => {
console.log("WebSocket连接已关闭:", event.code, event.reason)
isConnected.value = false
isConnecting.value = false
chatStore.connectionStatus = "disconnected"
chatStore.socket = null
// 自动重连
if (reconnectAttempts.value < maxReconnectAttempts) {
setTimeout(() => {
reconnectAttempts.value++
reconnectDelay.value = Math.min(reconnectDelay.value * 2, 30000)
console.log(`尝试重连 (${reconnectAttempts.value}/${maxReconnectAttempts})`)
connect()
}, reconnectDelay.value)
}
}
const handleError = (error) => {
console.error("WebSocket错误:", error)
isConnecting.value = false
chatStore.connectionStatus = "disconnected"
}
const handleCallSignal = (data) => {
console.log("收到通话信令:", data)
// 根据通话状态处理
switch (data.call_status) {
case "invite":
// 显示来电通知
showIncomingCallDialog(data)
break
case "accepted":
// 通话被接受
handleCallAccepted(data)
break
case "rejected":
// 通话被拒绝
handleCallRejected(data)
break
case "ended":
// 通话结束
handleCallEnded(data)
break
case "candidate":
// ICE候选
handleIceCandidate(data)
break
}
}
const bindUser = (userId) => {
console.log(userId, 'ssssssssss')
if (!isConnected.value || !userId) return
const bindMessage = {
request_type: "bind",
sender_user_id: userId,
client_id: userStore.clientId,
}
send(bindMessage)
}
const send = (message) => {
if (!isConnected.value || !socket.value) {
console.error("WebSocket未连接无法发送消息")
return false
}
try {
socket.value.send(JSON.stringify(message))
return true
} catch (error) {
console.error("发送消息失败:", error)
return false
}
}
const sendMessage = (receiverUserId, messageType, content) => {
const message = {
request_type: "send_message",
sender_user_id: userStore.currentUser?.id,
receiver_user_id: receiverUserId,
message_type: messageType,
message_content: content,
}
return send(message)
}
const sendCallSignal = (signal) => {
return send(signal)
}
const disconnect = () => {
if (socket.value) {
socket.value.close()
socket.value = null
}
isConnected.value = false
isConnecting.value = false
chatStore.connectionStatus = "disconnected"
chatStore.socket = null
}
// 生成唯一ID
const generateCallId = () => {
return Date.now().toString() + Math.random().toString(36).substr(2, 9)
}
onMounted(() => {
connectWebSocket()
})
onUnmounted(() => {
disconnectWebSocket()
})
return {
socket,
isConnected,
isConnecting,
connectWebSocket,
disconnectWebSocket,
send,
sendMessage,
sendCallSignal,
bindUser,
generateCallId,
}
}
// 全局通话处理函数
const incomingCallDialog = null
const currentCall = null
function showIncomingCallDialog(callData) {
// 这里应该显示来电弹窗
console.log("显示来电弹窗:", callData)
// 创建来电通知
if ("Notification" in window && Notification.permission === "granted") {
new Notification(`${callData.sender_user_id} 邀请您进行${callData.message_type === 6 ? "视频" : "语音"}通话`, {
icon: "/favicon.ico",
tag: "incoming-call",
})
}
}
function handleCallAccepted(data) {
console.log("通话被接受:", data)
// 开始WebRTC连接
}
function handleCallRejected(data) {
console.log("通话被拒绝:", data)
// 显示拒绝消息
}
function handleCallEnded(data) {
console.log("通话结束:", data)
// 清理通话状态
}
function handleIceCandidate(data) {
console.log("收到ICE候选:", data)
// 处理ICE候选
}