import { ROLES, CODEMEG, EVENT, FROMTYPE } from "../../enum/index.js"; import { getCurrentUser, updateUser, removeRoomAllUsers, getAllRoomUsers, updateRoomUser, removeRoomUser, isUserInRoom } from "../../service/userService.js"; // import { watchRoomService } from "../../service/watchRoomService.js"; import { setRoomConfig, getRoomConfig, updateRoomConfigByKey, isRoomMaster } from "../../service/roomConfigService.js"; import { RoomAssistant } from "./assistant.js"; import { Notify } from "./notify.js"; import { BasicController } from "../basicController.js"; export class RoomController extends BasicController { constructor(...args) { super(...args); this.roomAssistant = new RoomAssistant(this.socket, this.redisCli, this); this.notify = new Notify(this.socket, this.redisCli, this); this.roomId = null; this.sessionId = null; this.userId = null; this.roomConfigId = null; this.debugger = true; this.user = { sig: null, roomId: null, userId: null, sceneNum: null, isClient: null, avatar: "", role: null, userLimitNum: null, sceneNumber: null, order: 2, from: null, assistantId: null, onlineStatus: 0, voiceStatus: 0, isAssistant: 0, enableTalk: null, oid: null, // openid }; } // 以小程序user信息作为主要信息 async currentUser() { const data = await getCurrentUser(this.userId, FROMTYPE.MiniAPP); const user = data ? JSON.parse(data) : this.user; return user; } async run() { this.logger.info("socket conetcted has start!"); try { await this.init(); this.initBaseAction(); this.roomMasterAutoRejoin(); this.roomAssistant.watchRoomExpired(); // setInterval(async () => { // if ([FROMTYPE.Bridge].includes(Number(this.user.from))) { // const AllRoomUsers = await getAllRoomUsers(this.roomId); // this.socket.broadcast.to(this.roomId).emit(EVENT.roomStatus, { // roomsPerson: AllRoomUsers, // }); // console.log("定时测试", this.roomId); // } // }, 10000); } catch (error) { this.logger.error("roomController::run::error", error); } } async init() { let user = this.socket.handshake.query; this.logger.info("init-user-query:", this.socket.handshake.query); if (user) { this.user = Object.assign({}, user); this.user.sig = this.getSig(this.user.userId); const oneSceneNum = this.user.sceneNumber || this.user.sceneNum; const { userId, roomId } = this.user; await this.initParams(userId, roomId, oneSceneNum); //role的顺序 let order = 2; if (this.user.role === "leader") { order = 0; } if (this.user.role === "customer" && Number(this.user.isAssistant) === 1) { order = 1; } const userObj = { ...this.user, onlineStatus: 1, isConnected: true, order }; const assistantId = await this.roomAssistant.getRoomAssistant(this.roomId); if (!this.isHoster(this.user.role) && assistantId) { console.log("assistantId", assistantId); console.log("this.userId", this.user.userId); this.logger.info("房间已存助手", assistantId, this.roomId); userObj.isAssistant = Number(this.user.userId) === Number(assistantId) ? 1 : 0; userObj.order = Number(this.user.userId) === Number(assistantId) ? 1 : 2; // if (assistantId) { // this.logger.info("已存在默认助手变更:" + "room助手ID: " + assistantId + " userId: " + this.user.userId); // } } // if (assistantId && Number(this.userId) !== Number(assistantId) && !this.isHoster(this.user.role)) { // userObj.role = "customer"; // } this.logger.info("update-user-info:", userObj); updateUser(this.userId, userObj); // 将更新同步一份到process this.user = userObj; // this.sysUsers.push(this.user); // 只有来源于小程序用户信息才记录到redis if (this.isHoster(this.user.role)) { if ([FROMTYPE.MiniAPP].includes(Number(this.user.from))) { const roomConfig = getRoomConfig(this.roomId); const checkoutMaster = await isRoomMaster(this.roomId, this.userId); const isNoExistMaster = "masterId" in roomConfig; // console.log("checkoutMaster-isNoExistMaster", checkoutMaster, !isNoExistMaster); if (checkoutMaster || !isNoExistMaster) { console.log("房主进入记录信息::: checkoutMaster: %s, isNoExistMaster: %s ,roomId %s", checkoutMaster, !isNoExistMaster, this.roomId); const roomConfig = { masterId: this.userId, userLimitNum: this.user.userLimitNum, enableTalk: this.user.enableTalk === "true" ? true : false, }; console.log("roomConfig", roomConfig); // console.log("roomConfig", roomConfig); await setRoomConfig(this.roomId, roomConfig); } } } // 加入 console.log("roomId", this.roomId); this.socket.join(this.roomId); const isInRoom = await isUserInRoom(this.roomId, this.userId); console.log("测试-强制上线", isInRoom, this.roomId, this.userId); if (isInRoom) { if (Number(isInRoom.onlineStatus) === 0) { console.log("在房间人员掉线人员,强制上线!", isInRoom); this.roomAssistant.setOnlineStatus(this.roomId, this.userId, isInRoom); } } } else { this.logger.info("user-query-不存在 :", this.socket.handshake.query); this.socket.disconnect(); } } async initParams(userId, roomId, oneSceneNum) { this.userId = `user:${userId}`; this.syncId = `sync:${oneSceneNum}:${userId}`; this.sessionId = `session:${oneSceneNum}:${userId}`; const uRoomId = await this.roomAssistant.prepearRoom(this.sessionId, roomId); // this.roomId = `room:${uRoomId}_${oneSceneNum}`; this.roomId = `room:${oneSceneNum}:${uRoomId}`; this.user.roomId = uRoomId; this.roomConfigId = `config:${this.roomId}`; return Promise.resolve(true); } initBaseAction() { // 通知 baseView 减少大量通知 this.socket.on(EVENT.webSyncAction, (data) => { // socket.broadcast.to(roomUniqueId).emit(EVENT.webSyncAction, data); try { if ([FROMTYPE.base].includes(Number(this.user.from))) { this.socket.broadcast.to(this.roomId).emit(EVENT.webSyncAction, data); } } catch (error) { this.logger.error("roomController::EVENT.webSyncAction", error); } }); // 转发action this.socket.on(EVENT.action, (data) => { try { this.logger.debug("room-action", this.roomId, this.socket.rooms.has(this.roomId), JSON.stringify(data)); if (this.socket.rooms.has(this.roomId)) { this.socket.broadcast.to(this.roomId).emit(EVENT.action, data); } else { this.logger.error("action 事件不在房间内", this.user); } } catch (error) { this.logger.error("roomController::EVENT.action", error); } }); this.socket.on(EVENT.startCall, async () => { const user = await this.currentUser(); this.roomAssistant.startCall(this.roomId, this.userId, user); // console.log("startCall-from", this.user.from); if (this.isHoster(this.user.role)) { // 以startCall做为真正的进入房间 await updateRoomConfigByKey(this.roomId, "isStart", true); } }); this.socket.on(EVENT.stopCall, () => { setTimeout(() => { console.log("EVENT.stopCall-delay"); this.roomAssistant.stopCall(this.roomId, this.userId, this.user); if (this.isHoster(this.user.role)) { // 以stopCall断开做为真正的退出房间 this.roomAssistant.destoryRoom(this.sessionId, this.roomConfigId); } }, 1000); }); this.socket.on(EVENT.changeRoomEnableTalk, async (data) => { // this._roomsConfig[roomId].enableTalk = data; try { const roomConfig = await getRoomConfig(this.roomId); roomConfig.enableTalk = data; await setRoomConfig(this.roomId, roomConfig); this.logger.info("changeRoomEnableTalk", JSON.stringify(data)); this.socket.broadcast.to(this.roomId).emit(EVENT.changeRoomEnableTalk, roomConfig); } catch (error) { this.logger.error("event:changeRoomEnableTalk", error); } }); this.socket.on(EVENT.changeOnlineStatus, async (data) => { try { const user = await this.currentUser(); user.onlineStatus = Number(data.status); await updateRoomUser(this.roomId, this.userId, user); this.user = user; //更新一份 let actionName = Number(user.onlineStatus) === 1 ? "inRoom" : "leaveRoom"; this.logger.info("changeOnlineStatus", JSON.stringify(user)); const AllRoomUsers = await getAllRoomUsers(this.roomId); this.socket.broadcast.to(this.roomId).emit(EVENT.roomPersonChange, { roomsPerson: AllRoomUsers, actionName, user: user, }); } catch (error) { this.logger.error("event:changeOnlineStatus", error); } }); /** * 踢人管理 */ this.socket.on(EVENT.kickUser, async ({ data, from }) => { // 要前端断线才可以踢人 try { const userId = `user:${data.userId}`; const roomId = `room:${data.sceneNumber}:${data.roomId}`; const currentUser = await getCurrentUser(userId, FROMTYPE.MiniAPP); const user = JSON.parse(currentUser); // 被踢人不能是hoster console.log("user", JSON.stringify(user)); if (user && !this.isHoster(user.role)) { console.log("currentUser.role", user.role); // 如果踢人后 如何通知? this.socket.broadcast.to(roomId).emit(EVENT.beKicked, data); // 被踢人是助手 const assistantId = await this.roomAssistant.getRoomAssistant(this.roomId); if (assistantId == data.userId) { const roomConfig = await getRoomConfig(roomId); if (roomConfig.assistantId) { delete roomConfig.assistantId; } await setRoomConfig(roomId, roomConfig); } setTimeout(async () => { const isKick = await this.roomAssistant.kickPersion(roomId, userId); if (isKick) { const AllRoomUsers = await getAllRoomUsers(roomId); console.log("kickUser-AllRoomUsers", AllRoomUsers.length); this.logger.info("kickUser", currentUser, userId, roomId); // 通知管理 this.socket.emit(EVENT.someOneLeaveRoom, { user: user, roomsPerson: AllRoomUsers, }); // 通知房间人员变动 this.socket.broadcast.to(roomId).emit(EVENT.someOneLeaveRoom, { user: user, roomsPerson: AllRoomUsers, }); } }, 2000); } else { const nickname = user.nickname || ""; this.logger.warn(nickname + "是房主,不能被踢!!"); } } catch (error) { console.error("error", error); } }); /** * 设置助手 */ this.socket.on("setAssistant", async ({ data, from }) => { const userId = `user:${data.userId}`; const roomId = `room:${data.sceneNumber}:${data.roomId}`; console.log("设置助手", userId, roomId); this.roomAssistant.setAssistant(roomId, userId, data.cancel); }); /** * 设置MIC权 */ this.socket.on("setUserhasMic", async ({ data, from, isAllowMic }) => { const userId = `user:${data.userId}`; const roomId = `room:${data.sceneNumber}:${data.roomId}`; console.log("设置MIC权", userId, roomId, data.isAllowMic); this.roomAssistant.setMicRight(roomId, userId, data.isAllowMic); }); if (this.debugger) { this.socket.onAny((event, data) => { // if (event !== "webSyncAction") { // console.log(`onAny:get ${event}, data:${JSON.stringify(data)}`); this.logger.info(`onAny:get ${event}, data:${JSON.stringify(data)}`); // } }); } } async roomMasterAutoRejoin() { try { const sessionExist = await this.redisCli.exists(this.sessionId); const roomConfig = await getRoomConfig(this.roomId); if (sessionExist > 0 && roomConfig.isStart && roomConfig.isStart === "true") { const AllRoomUsers = await getAllRoomUsers(this.roomId); // 房主 if (this.isHoster(this.user.role)) { console.log("自动接连", this.roomId, this.user.from); this.socket.join(this.roomId); this.socket.emit("autoReJoin", { user: this.user, roomsPerson: AllRoomUsers, roomId: this.user.roomId, }); //TODO someOneInRoom是用来触发语音与更新房间状态 } //TODO someOneInRoom是用来触发语音与更新房间状态 // setTimeout(() => { // this.socket.emit("someOneInRoom", { // user: this.user, // roomsPerson: AllRoomUsers, // }); // }); } } catch (error) { this.logger.error("room::roomMasterAutoRejoin", error); } } }