|
@@ -6,7 +6,6 @@ import { useWalletStore } from "@/stores/modules/walletStore";
|
|
|
import { getMessageApi } from "@/api/path/im.api";
|
|
|
import { MSG_TYPE, MSG_TYPE_MAP } from "@/common/constant/msgType";
|
|
|
|
|
|
-
|
|
|
import {
|
|
|
setMessageHook,
|
|
|
handleMessageHook,
|
|
@@ -20,9 +19,7 @@ export const useWebSocketStore = defineStore("webSocketStore", {
|
|
|
socket: null, // socket实例
|
|
|
peer: null, // peer实例
|
|
|
lockConnection: false, // 锁定连接
|
|
|
- reconnectAttempts: 0, // 重连次数
|
|
|
- maxReconnectAttempts: 80, // 最大重连次数
|
|
|
- reconnectInterval: 2000, // 重连间隔
|
|
|
+ reconnectAttempts: 0, // 重连次数
|
|
|
messages: [], // 消息列表
|
|
|
toUserInfo: {},
|
|
|
unreadMessages: [], // 未读消息列表
|
|
@@ -31,10 +28,12 @@ export const useWebSocketStore = defineStore("webSocketStore", {
|
|
|
|
|
|
// 心跳检测配置
|
|
|
heartCheck: {
|
|
|
- timeout: 10000, // 连接丢失后,多长时间内没有收到服务端的消息,则认为连接已断开
|
|
|
- timeoutObj: null, // 定时器对象
|
|
|
- serverTimeoutObj: null, // 服务器定时器对象
|
|
|
- num: 3, // 重连次数
|
|
|
+ interval: 30000, // 心跳发送间隔(30秒)
|
|
|
+ timeout: 10000, // 响应超时时间(10秒)
|
|
|
+ timeoutObj: null,
|
|
|
+ serverTimeoutObj: null,
|
|
|
+ retryLimit: 3, // 重试次数
|
|
|
+ retryCount: 0, // 当前重试计数
|
|
|
},
|
|
|
}),
|
|
|
persist: {
|
|
@@ -73,16 +72,16 @@ export const useWebSocketStore = defineStore("webSocketStore", {
|
|
|
console.error("WebSocket未连接");
|
|
|
return false;
|
|
|
}
|
|
|
-
|
|
|
- // 获取url上uuid参数
|
|
|
+
|
|
|
+ // 获取url上uuid参数
|
|
|
const walletStore = useWalletStore();
|
|
|
let data = {
|
|
|
...messageData,
|
|
|
fromUsername: walletStore.username,
|
|
|
from: walletStore.account,
|
|
|
to: this.toUserInfo.uuid,
|
|
|
- };
|
|
|
- console.log("发送消息=", data)
|
|
|
+ };
|
|
|
+ console.log("发送消息=", data);
|
|
|
try {
|
|
|
const MessageType = protobuf.lookupType("protocol.Message");
|
|
|
const messagePB = MessageType.create(data);
|
|
@@ -98,34 +97,73 @@ export const useWebSocketStore = defineStore("webSocketStore", {
|
|
|
}
|
|
|
},
|
|
|
// 初始化socket
|
|
|
- startHeartbeat() {
|
|
|
- const self = this;
|
|
|
- const _num = this.heartCheck.num;
|
|
|
+ // startHeartbeat() {
|
|
|
+ // const self = this;
|
|
|
+ // const _num = this.heartCheck.num;
|
|
|
|
|
|
- this.heartCheck.timeoutObj && clearTimeout(this.heartCheck.timeoutObj);
|
|
|
- this.heartCheck.serverTimeoutObj &&
|
|
|
- clearTimeout(this.heartCheck.serverTimeoutObj);
|
|
|
+ // this.heartCheck.timeoutObj && clearTimeout(this.heartCheck.timeoutObj);
|
|
|
+ // this.heartCheck.serverTimeoutObj &&
|
|
|
+ // clearTimeout(this.heartCheck.serverTimeoutObj);
|
|
|
+
|
|
|
+ // this.heartCheck.timeoutObj = setTimeout(() => {
|
|
|
+ // if (this.socket?.readyState === WebSocket.OPEN) {
|
|
|
+ // const data = {
|
|
|
+ // type: "heatbeat",
|
|
|
+ // content: "ping",
|
|
|
+ // };
|
|
|
+ // const MessageType = protobuf.lookupType("protocol.Message");
|
|
|
+ // const messagePB = MessageType.create(data);
|
|
|
+ // const buffer = MessageType.encode(messagePB).finish();
|
|
|
+ // this.socket.send(buffer);
|
|
|
+ // }
|
|
|
+
|
|
|
+ // self.heartCheck.serverTimeoutObj = setTimeout(() => {
|
|
|
+ // _num--;
|
|
|
+ // if (_num <= 0) {
|
|
|
+ // console.log("the ping num is more then 3, close socket!");
|
|
|
+ // this.socket?.close();
|
|
|
+ // }
|
|
|
+ // }, self.heartCheck.timeout);
|
|
|
+ // }, this.heartCheck.timeout);
|
|
|
+ // },
|
|
|
+
|
|
|
+ startHeartbeat() {
|
|
|
+ this.resetHeartbeat();
|
|
|
|
|
|
this.heartCheck.timeoutObj = setTimeout(() => {
|
|
|
- if (this.socket?.readyState === WebSocket.OPEN) {
|
|
|
- const data = {
|
|
|
- type: "heatbeat",
|
|
|
- content: "ping",
|
|
|
- };
|
|
|
- const MessageType = protobuf.lookupType("protocol.Message");
|
|
|
- const messagePB = MessageType.create(data);
|
|
|
- const buffer = MessageType.encode(messagePB).finish();
|
|
|
- this.socket.send(buffer);
|
|
|
- }
|
|
|
+ if (this.isConnected) {
|
|
|
+ try {
|
|
|
+ const pingMsg = {
|
|
|
+ type: "heatbeat",
|
|
|
+ content: "ping",
|
|
|
+ timestamp: Date.now(),
|
|
|
+ };
|
|
|
|
|
|
- self.heartCheck.serverTimeoutObj = setTimeout(() => {
|
|
|
- _num--;
|
|
|
- if (_num <= 0) {
|
|
|
- console.log("the ping num is more then 3, close socket!");
|
|
|
- this.socket?.close();
|
|
|
+ const MessageType = protobuf.lookupType("protocol.Message");
|
|
|
+ const messagePB = MessageType.create(pingMsg);
|
|
|
+ const buffer = MessageType.encode(messagePB).finish();
|
|
|
+ this.socket.send(buffer);
|
|
|
+
|
|
|
+ // 设置响应超时检测
|
|
|
+ this.heartCheck.serverTimeoutObj = setTimeout(() => {
|
|
|
+ this.heartCheck.retryCount++;
|
|
|
+
|
|
|
+ if (this.heartCheck.retryCount >= this.heartCheck.retryLimit) {
|
|
|
+ console.error("心跳响应超时,关闭连接");
|
|
|
+ this.socket?.close();
|
|
|
+ } else {
|
|
|
+ console.warn(
|
|
|
+ `心跳无响应,第${this.heartCheck.retryCount}次重试`
|
|
|
+ );
|
|
|
+ this.startHeartbeat(); // 重新发送心跳
|
|
|
+ }
|
|
|
+ }, this.heartCheck.timeout);
|
|
|
+ } catch (error) {
|
|
|
+ console.error("心跳发送失败:", error);
|
|
|
+ this.reconnect();
|
|
|
}
|
|
|
- }, self.heartCheck.timeout);
|
|
|
- }, this.heartCheck.timeout);
|
|
|
+ }
|
|
|
+ }, this.heartCheck.interval);
|
|
|
},
|
|
|
|
|
|
resetHeartbeat() {
|
|
@@ -138,6 +176,7 @@ export const useWebSocketStore = defineStore("webSocketStore", {
|
|
|
connect(userUuid) {
|
|
|
if (!userUuid) return;
|
|
|
console.log("开始连接...");
|
|
|
+ this.uuid = userUuid;
|
|
|
this.disconnect(); // 确保先断开现有连接
|
|
|
|
|
|
this.peer = new RTCPeerConnection();
|
|
@@ -202,25 +241,34 @@ export const useWebSocketStore = defineStore("webSocketStore", {
|
|
|
reader.readAsArrayBuffer(data);
|
|
|
},
|
|
|
// 断线重连
|
|
|
+
|
|
|
+ // 替换现有的reconnect方法
|
|
|
reconnect() {
|
|
|
- if (
|
|
|
- this.lockConnection ||
|
|
|
- this.reconnectAttempts >= this.maxReconnectAttempts
|
|
|
- ) {
|
|
|
- return;
|
|
|
- }
|
|
|
+ if (this.lockConnection) return;
|
|
|
|
|
|
this.lockConnection = true;
|
|
|
- this.reconnectAttempts++;
|
|
|
+ this.reconnectConfig.currentAttempt++;
|
|
|
+
|
|
|
+ // 指数退避算法计算重连间隔
|
|
|
+ const delay = Math.min(
|
|
|
+ this.reconnectConfig.baseInterval *
|
|
|
+ Math.pow(
|
|
|
+ this.reconnectConfig.multiplier,
|
|
|
+ this.reconnectConfig.currentAttempt - 1
|
|
|
+ ),
|
|
|
+ this.reconnectConfig.maxInterval
|
|
|
+ );
|
|
|
|
|
|
console.log(
|
|
|
- `重新连接中... (尝试 ${this.reconnectAttempts}/${this.maxReconnectAttempts})`
|
|
|
+ `将在 ${delay}ms 后尝试第 ${this.reconnectConfig.currentAttempt} 次重连`
|
|
|
);
|
|
|
|
|
|
setTimeout(() => {
|
|
|
- this.connect(localStorage.uuid);
|
|
|
+ if (!this.isConnected) {
|
|
|
+ this.connect(this.uuid);
|
|
|
+ }
|
|
|
this.lockConnection = false;
|
|
|
- }, this.reconnectInterval);
|
|
|
+ }, delay);
|
|
|
},
|
|
|
// 重连
|
|
|
disconnect() {
|
|
@@ -233,7 +281,7 @@ export const useWebSocketStore = defineStore("webSocketStore", {
|
|
|
this.peer.close();
|
|
|
this.peer = null;
|
|
|
}
|
|
|
- this.reconnectAttempts = 0;
|
|
|
+ this.heartCheck.retryCount = 0;
|
|
|
},
|
|
|
|
|
|
// 发送WebRTC消息
|
|
@@ -246,7 +294,9 @@ export const useWebSocketStore = defineStore("webSocketStore", {
|
|
|
|
|
|
reader.onload = (event) => {
|
|
|
try {
|
|
|
- const messagePB = MessageType.decode(new Uint8Array(event.target?.result));
|
|
|
+ const messagePB = MessageType.decode(
|
|
|
+ new Uint8Array(event.target?.result)
|
|
|
+ );
|
|
|
const message = MessageType.toObject(messagePB, {
|
|
|
longs: String,
|
|
|
enums: String,
|
|
@@ -257,7 +307,7 @@ export const useWebSocketStore = defineStore("webSocketStore", {
|
|
|
handleMessageHook(message, this);
|
|
|
|
|
|
// 调用所有回调函数
|
|
|
- this.onMessageCallbacks.forEach(cb => {
|
|
|
+ this.onMessageCallbacks.forEach((cb) => {
|
|
|
try {
|
|
|
cb(message);
|
|
|
} catch (e) {
|
|
@@ -287,7 +337,9 @@ export const useWebSocketStore = defineStore("webSocketStore", {
|
|
|
},
|
|
|
|
|
|
removeOnMessageCallback(cb) {
|
|
|
- this.onMessageCallbacks = this.onMessageCallbacks.filter(item => item !== cb);
|
|
|
+ this.onMessageCallbacks = this.onMessageCallbacks.filter(
|
|
|
+ (item) => item !== cb
|
|
|
+ );
|
|
|
},
|
|
|
},
|
|
|
});
|