// 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;