feat: init commit

This commit is contained in:
merlin
2025-10-16 15:54:37 +08:00
commit b2bcfdf1a9
52 changed files with 10777 additions and 0 deletions

189
src/socket/onlineSocket.js Normal file
View File

@@ -0,0 +1,189 @@
import { ref } from "vue";
import { userInfoStore } from "@/store/store";
import { messagePointStore } from "@/store/store";
import {
messageStore,
messageSignStore,
groupMessageStore,
} from "@/store/message";
import { ElMessage } from "element-plus";
// userinfo 实例
const userinfo = userInfoStore();
// message 实例
const message = messageStore();
// groupMessage 实例
const groupMessage = groupMessageStore();
// messageSignStoregn 实例
const messageSign = messageSignStore();
// WebSocket 实例
const socket = ref(null);
//messagePoint 实例
const messagePoint = messagePointStore();
const isManualClose = ref(false);
const reconnectScheduled = ref(false);
const retryCount = ref(0);
export const getRetryCount = () => {
return retryCount.value;
};
export const addRetryCount = () => {
retryCount.value = retryCount.value + 1;
};
export const resetRetryCount = () => {
retryCount.value = 0;
};
export const setReconnectScheduled = (value) => {
reconnectScheduled.value = value;
};
export const getReconnectScheduled = () => {
return reconnectScheduled.value;
};
export const setIsManualClose = (value) => {
isManualClose.value = value;
};
export const getIsManualClose = () => {
return isManualClose.value;
};
// 连接WebSocket
export const connectWebSocket = () => {
const protocol = window.location.protocol === "https:" ? "wss://" : "ws://";
const host = window.location.host;
const socketUrl = `${protocol}${host}/online?u_id=${userinfo.user.u_id}&u_name=${userinfo.user.u_name}`;
// const socketUrl = `ws://localhost:8080/online?u_id=${userinfo.user.u_id}&u_name=${userinfo.user.u_name}`;
if (socket.value && socket.value.readyState !== WebSocket.CLOSED) {
console.log("还在重连中...");
return;
}
const retrytime = getRetryCount();
if (retrytime >= 10) {
console.log("重连失败,请稍后再试");
return;
}
console.log(retrytime);
socket.value = new WebSocket(socketUrl);
socket.value.onopen = (event) => {
console.log("WebSocket连接已建立", event);
setReconnectScheduled(false);
setIsManualClose(false);
resetRetryCount();
};
//处理消息逻辑
socket.value.onmessage = (event) => {
console.log("从服务器收到消息:", event.data);
try {
const MessageData = JSON.parse(event.data);
//是否为上下线消息(三类消息)
if (!MessageData.system) {
//是否为新消息
if (MessageData.message) {
messagePoint.hasNewMessage = true;
if (MessageData.group) {
//四类消息,群聊消息
console.log("有新群消息");
groupMessage.addMessage(MessageData);
console.log(groupMessage.messages);
messageSign.addSign({
sender_name: MessageData.sender_name,
g_id: MessageData.g_id,
g_name: MessageData.g_name,
});
} else {
//一类消息,私聊消息
console.log("有新消息");
message.addMessage(MessageData);
console.log(message.messages);
messageSign.addSign({
sender: MessageData.sender,
sender_name: MessageData.sender_name,
});
}
}
} else {
if (MessageData.engaged) {
// 五类消息,账号重复登录逻辑
setIsManualClose(true);
disconnectWebSocket();
ElMessage("账号重复登录,请注意密码泄露");
console.log("账号重复登陆");
window.location.replace("/");
} else {
//三类消息,指示用户上下线
if (MessageData.status === "online")
ElMessage("用户:" + MessageData.u_name + "上线");
else {
ElMessage("用户:" + MessageData.u_name + "下线");
}
}
}
} catch (error) {
console.error("解析 JSON 失败:", error);
}
};
socket.value.onerror = (error) => {
console.error("WebSocket发生错误", error);
setReconnectScheduled(true);
socket.value.close();
};
socket.value.onclose = (event) => {
if (!getIsManualClose()) {
if (getReconnectScheduled()) {
socket.value = null;
addRetryCount();
setTimeout(reConnectWebSocket, 5000);
setReconnectScheduled(false);
} else {
console.log("websocket因为浏览器省电设置断开");
console.log("WebSocket连接已关闭", event);
}
}
};
};
// 断开WebSocket连接
export const disconnectWebSocket = () => {
if (socket.value && socket.value.readyState === WebSocket.OPEN) {
socket.value.close();
}
};
// 重连机制
export const reConnectWebSocket = () => {
connectWebSocket();
};
// 发送消息
export const sendMessage = (message) => {
if (socket.value && socket.value.readyState === WebSocket.OPEN) {
socket.value.send(message);
} else {
console.warn("WebSocket未连接无法发送消息");
}
};
//没有错误的重连,只是浏览器在后台断开了连接
document.addEventListener("visibilitychange", () => {
if (document.hidden) {
} else {
if (!getIsManualClose() && socket.value.readyState === WebSocket.CLOSED) {
if (getReconnectScheduled()) {
return;
}
reConnectWebSocket();
}
}
});

0
src/socket/roomSocket.js Normal file
View File

287
src/socket/voiceSocket.js Normal file
View File

@@ -0,0 +1,287 @@
import { ref } from "vue";
import { userInfoStore } from "@/store/store";
import { onCallStore } from "@/store/VoiceTarget";
import { ElMessage } from "element-plus";
// userinfo 实例
const userinfo = userInfoStore();
// oncall 实例
const oncall = onCallStore();
// WebSocket 实例
const socket = ref(null);
const isManualClose = ref(false);
const reconnectScheduled = ref(false);
const retryCount = ref(0);
const getRetryCount = () => {
return retryCount.value;
};
const addRetryCount = () => {
retryCount.value = retryCount.value + 1;
};
const resetRetryCount = () => {
retryCount.value = 0;
};
const setReconnectScheduled = (value) => {
reconnectScheduled.value = value;
};
const getReconnectScheduled = () => {
return reconnectScheduled.value;
};
const setIsManualClose = (value) => {
isManualClose.value = value;
};
const getIsManualClose = () => {
return isManualClose.value;
};
const iceserver = {
iceServers: [
{
// urls: "stun:stun.l.google.com:19302"
urls: "stun:8.134.92.199:3478",
},
{
urls: "turn:8.134.92.199:3478",
username: "test",
credential: "123456",
},
],
};
// 连接WebSocket
export const connectVoicesocket = () => {
const protocol = window.location.protocol === "https:" ? "wss://" : "ws://";
const host = window.location.host;
const socketUrl = `${protocol}${host}/voice?u_id=${userinfo.user.u_id}&u_name=${userinfo.user.u_name}`;
if (socket.value && socket.value.readyState !== WebSocket.CLOSED) {
console.log("还在重连中...");
return;
}
const retrytime = getRetryCount();
if (retrytime >= 10) {
console.log("重连失败,请稍后再试");
return;
}
console.log(retrytime);
socket.value = new WebSocket(socketUrl);
socket.value.onopen = (event) => {
console.log("Voice连接已建立", event);
setReconnectScheduled(false);
setIsManualClose(false);
resetRetryCount();
};
// 处理消息逻辑
socket.value.onmessage = async (event) => {
try {
const data = JSON.parse(event.data);
if (data.type === "status") {
ElMessage.error("对方已离线");
oncall.panelOff();
oncall.callingOff();
} else if (data.type === "incomingcall") {
// 通话请求处理
oncall.setTarget(data.from, data.from_name, data.from_avatar);
oncall.panelOn();
oncall.callingOn();
oncall.fromOff();
oncall.statusOff();
} else if (data.type === "pickup") {
ElMessage.success("对方已接听,等待连接中...");
try {
await initRTCconnection();
RTCpeerConnection.value.onicecandidate = (event) => {
if (event.candidate) {
console.log("发送candidate", event.candidate);
const message = {
type: "single",
content: "candidate",
from: userinfo.user.u_id,
to: oncall.target.u_id,
candidate: event.candidate,
};
sendMessage(JSON.stringify(message));
}
};
RTCpeerConnection.value.ontrack = (event) => {
console.log("收到对方音频流", event);
oncall.setRemoteStream(event.streams[0]);
};
} catch (e) {
console.log("webRTC初始化失败", e);
}
const offer = await RTCpeerConnection.value.createOffer({
offerToReceiveAudio: 1,
});
await RTCpeerConnection.value.setLocalDescription(offer);
// 发送offer
const message = {
type: "single",
content: "offer",
from: userinfo.user.u_id,
to: oncall.target.u_id,
offer: offer,
};
sendMessage(JSON.stringify(message));
} else if (data.type === "hangup") {
ElMessage.success("对方已挂断");
oncall.panelOff();
oncall.callingOff();
oncall.fromOff();
oncall.statusOff();
RTCpeerConnection.value.close();
RTCpeerConnection.value = null;
oncall.resetStream();
} else if (data.content === "offer") {
ElMessage.success("收到对方offer");
console.log("收到对方offer", data);
try {
await initRTCconnection();
RTCpeerConnection.value.onicecandidate = (event) => {
if (event.candidate) {
console.log("发送candidate", event.candidate);
const message = {
type: "single",
content: "candidate",
from: userinfo.user.u_id,
to: oncall.target.u_id,
candidate: event.candidate,
};
sendMessage(JSON.stringify(message));
}
};
RTCpeerConnection.value.ontrack = (event) => {
console.log("收到对方音频流", event);
oncall.setRemoteStream(event.streams[0]);
};
} catch (e) {
console.log("webRTC初始化失败", e);
}
await RTCpeerConnection.value.setRemoteDescription(data.offer);
const answer = await RTCpeerConnection.value.createAnswer();
await RTCpeerConnection.value.setLocalDescription(answer);
// 发送answer
const message = {
type: "single",
content: "answer",
from: userinfo.user.u_id,
to: oncall.target.u_id,
answer: answer,
};
sendMessage(JSON.stringify(message));
} else if (data.content === "answer") {
ElMessage.success("对方已接受");
console.log("对方已接受", data);
await RTCpeerConnection.value.setRemoteDescription(data.answer);
} else if (data.content === "candidate") {
console.log("收到candidate", data);
await RTCpeerConnection.value.addIceCandidate(data.candidate);
}
} catch (e) {
console.log("VoiceSocket消息格式错误", e);
}
};
socket.value.onerror = (error) => {
console.error("Voicesocket发生错误", error);
setReconnectScheduled(true);
socket.value.close();
};
socket.value.onclose = (event) => {
if (!getIsManualClose()) {
if (getReconnectScheduled()) {
socket.value = null;
addRetryCount();
setTimeout(reConnectVoicesocket, 5000);
setReconnectScheduled(false);
} else {
console.log("Voicesocket因为浏览器省电设置断开");
console.log("Voicesocket连接已关闭", event);
}
}
};
};
// 断开Voicesocket连接
export const disconnectVoicesocket = () => {
if (socket.value && socket.value.readyState === WebSocket.OPEN) {
socket.value.close();
}
};
// 重连机制
export const reConnectVoicesocket = () => {
connectVoicesocket();
};
// 发送消息
export const sendMessage = (message) => {
if (socket.value && socket.value.readyState === WebSocket.OPEN) {
socket.value.send(message);
} else {
console.warn("Voicesocket未连接无法发送消息");
}
};
//没有错误的重连,只是浏览器在后台断开了连接
document.addEventListener("visibilitychange", () => {
if (document.hidden) {
} else {
if (!getIsManualClose() && socket.value.readyState === WebSocket.CLOSED) {
if (getReconnectScheduled()) {
return;
}
reConnectVoicesocket();
}
}
});
//WebRTC连接相关代码
const RTCpeerConnection = ref(null);
export const getlocalStream = async () => {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
console.log("获取本地音频流成功", stream);
return stream;
// // 获取音频和视频轨道
// const audioTrack = stream.getAudioTracks()[0];
// // 将轨道添加到 RTCPeerConnection
// peerConnection.addTrack(audioTrack, stream);
};
const initRTCconnection = async () => {
RTCpeerConnection.value = new RTCPeerConnection(iceserver);
const stream = await getlocalStream();
RTCpeerConnection.value.addTrack(stream.getAudioTracks()[0], stream);
};
export const hangup = () => {
oncall.panelOff();
oncall.callingOff();
oncall.fromOff();
oncall.statusOff();
oncall.resetStream();
RTCpeerConnection.value.close();
RTCpeerConnection.value = null;
const message = {
type: "hangup",
from: userinfo.user.u_id,
to: oncall.target.u_id,
};
sendMessage(JSON.stringify(message));
};