You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

212 lines
6.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// common/websocket-manager.js
import * as wsApi from './wssocket';
import * as msgType from './messageType';
import * as enums from './enums';
class WebSocketManager {
constructor() {
if (WebSocketManager.instance) return WebSocketManager.instance;
WebSocketManager.instance = this;
// 状态标志
this.isInit = false;
this.isExit = false;
this.reconnecting = false;
this.audioTip = null;
this.WS_URL=this.$wsUrl
// Store 引用(需外部注入)
this.chatStore = null;
this.userId=null;
// 事件监听器(供页面注册)
this.messageListeners = [];
}
/**
* 初始化 WebSocket 管理器
* @param {Object} stores - 各个 store 实例
* @param {string} accessToken - 用户 token
*/
init(stores, accessToken) {
if (this.isInit) return;
this.chatStore = stores.chatStore;
this.userId=stores.userId;
this.isExit = false;
this.reconnecting = false;
// 加载本地数据并启动 WebSocket
this.loadStore()
.then(() => {
this.initWebSocket(accessToken);
this.isInit = true;
})
.catch((e) => {
console.error(e);
this.exit();
});
}
initWebSocket(accessToken) {
wsApi.connect(this.WS_URL, accessToken);
wsApi.onConnect(() => {
if (this.reconnecting) {
this.onReconnectWs();
} else {
// 首次连接,拉取离线消息
this.pullPrivateOfflineMessage(this.chatStore.privateMsgMaxId).catch(() => {});
this.pullGroupOfflineMessage(this.chatStore.groupMsgMaxId).catch(() => {});
}
});
wsApi.onMessage((cmd, msgInfo) => {
// 分发原始消息给外部监听器
this.messageListeners.forEach(listener => listener(cmd, msgInfo));
// 内部业务处理
if (cmd == 2) {
// 异地登录
uni.showModal({
content: '您已在其他地方登录,将被强制下线',
showCancel: false,
});
this.exit();
} else if (cmd == 3) {
this.handlePrivateMessage(msgInfo);
} else if (cmd == 4) {
this.handleGroupMessage(msgInfo);
} else if (cmd == 5) {
this.handleSystemMessage(msgInfo);
}
});
wsApi.onClose((res) => {
console.log("ws断开", res);
this.reconnect(accessToken);
});
}
/**
* 重新连接token 刷新后调用)
* @param {string} accessToken
*/
reconnect(accessToken) {
if (this.isExit) return;
this.reconnecting = true;
wsApi.reconnect(this.WS_URL, accessToken);
}
/**
* 关闭连接并退出登录
*/
exit() {
console.log("WebSocket exit");
this.isExit = true;
wsApi.close(3099);
// uni.removeStorageSync("loginInfo");
// uni.reLaunch({ url: "/pages/login/login" });
this.unloadStore();
}
/**
* 注册消息监听器(页面可用来接收新消息通知)
* @param {Function} listener - (cmd, msgInfo) => {}
*/
addMessageListener(listener) {
if (typeof listener === 'function') {
this.messageListeners.push(listener);
}
}
/**
* 移除消息监听器
*/
removeMessageListener(listener) {
const index = this.messageListeners.indexOf(listener);
if (index !== -1) this.messageListeners.splice(index, 1);
}
// ============= 私有方法 =============
// 视频通话相关(可根据需要保留或删除)
handleRtcPrivate(msg) {
// #ifdef MP-WEIXIN
// return; // 小程序不支持
// // #endif
// let delayTime = 100;
// if (msg.type === enums.MESSAGE_TYPE.RTC_CALL_VOICE || msg.type === enums.MESSAGE_TYPE.RTC_CALL_VIDEO) {
// const mode = msg.type === enums.MESSAGE_TYPE.RTC_CALL_VIDEO ? "video" : "voice";
// const pages = getCurrentPages();
// const curPage = pages[pages.length - 1].route;
// if (curPage !== "pages/chat/chat-private-video") {
// const friend = this.loadFriendInfo(msg.selfSend ? msg.recvId : msg.sendId);
// const friendInfo = encodeURIComponent(JSON.stringify(friend));
// uni.navigateTo({
// url: `/pages/chat/chat-private-video?mode=${mode}&friend=${friendInfo}&isHost=false`,
// });
// delayTime = 500;
// }
// }
// setTimeout(() => {
// uni.$emit('WS_RTC_PRIVATE', msg);
// }, delayTime);
}
handleRtcGroup(msg) {
// #ifdef MP-WEIXIN
return;
// #endif
let delayTime = 100;
if (msg.type === enums.MESSAGE_TYPE.RTC_GROUP_SETUP) {
const pages = getCurrentPages();
const curPage = pages[pages.length - 1].route;
if (curPage !== "pages/chat/chat-group-video") {
const userInfos = encodeURIComponent(msg.content);
const inviterId = msg.sendId;
const groupId = msg.groupId;
uni.navigateTo({
url: `/pages/chat/chat-group-video?groupId=${groupId}&isHost=false&inviterId=${inviterId}&userInfos=${userInfos}`,
});
delayTime = 500;
}
}
setTimeout(() => {
uni.$emit('WS_RTC_GROUP', msg);
}, delayTime);
}
playAudioTip() {
// 音频播放实现(如需)
// this.audioTip = uni.createInnerAudioContext();
// this.audioTip.src = "/static/audio/tip.wav";
// this.audioTip.play();
}
async refreshToken(loginInfo) {
// if (!loginInfo || !loginInfo.refreshToken) {
// throw new Error("No refreshToken");
// }
// const newLoginInfo = await http({
// url: '/refreshToken',
// method: 'PUT',
// header: { refreshToken: loginInfo.refreshToken },
// });
// uni.setStorageSync("loginInfo", newLoginInfo);
// return newLoginInfo;
}
}
// 导出单例
const wsManager = new WebSocketManager();
export default wsManager;