// 房间行为助手 import { EVENT, CODEMEG, FROMTYPE } from "../../enum/index.js"; import { getCurrentUser, updateUser, removeRoomAllUsers, getAllRoomUsers, updateRoomUser } from "../../service/userService.js"; import { setRoomConfig, getRoomConfig, isRoomMaster } from "../../service/roomConfigService.js"; import { subClient } from "../../connection/redis.js"; const prefix = process.env.REDIS_PREFIX || "chat"; const getInKey = (realKey) => { return `${prefix}:${realKey}`; }; export class RoomAssistant { constructor(socket, redis, room) { this.socket = socket; this.redis = redis; this.roomId = null; this.room = room; } async prepearRoom(roomSessionId, roomId) { const uRoomId = await this.redis.get(getInKey(roomSessionId)); const mergeRoomId = uRoomId || roomId; this.roomId = mergeRoomId; this.room.logger.info("prepearRoom", roomSessionId, this.roomId); await this.redis.set(getInKey(roomSessionId), mergeRoomId); return Promise.resolve(this.roomId); } async destoryRoom(roomSessionId, roomConfigId) { this.room.logger.info("destoryRoom", roomSessionId, roomConfigId); await this.redis.del(getInKey(roomSessionId)); await this.redis.del(getInKey(roomConfigId)); this.disconnect(); return Promise.resolve(true); } /** * kickPersion LEADER or assistant 房主或助手 */ async kickPersion(roomId, userId) { console.log("kickPersion", roomId, userId); getInKey(roomId) try { const hasJoin = await this.redis.HVALS( getInKey(roomId), userId); // const blackListId = "" if (hasJoin.length > 0) { await this.redis.hDel(getInKey(roomId), userId); return Promise.resolve(true); } else { return Promise.resolve(false); } } catch (error) { return Promise.resolve(false); } } /** * 设置助手 LEADER(权限) 房主或助手 * @param {*} roomId * @param {*} userId */ async setAssistant(roomId, userId, cancel) { try { const userRes = await getCurrentUser(roomId, userId, FROMTYPE.MiniAPP); const user = JSON.parse(userRes); const roomConfigRes = await getRoomConfig(roomId); if (this.room.userId == userId) { console.log("不能设置自己为助理!"); return; } const role = cancel ? "customer" : "assistant"; // assistant是助手,customer是普通角色,操作role会好些 const userObj = Object.assign({}, user, { role: role, order: 1 }); const roomObj = Object.assign({}, roomConfigRes, { assistantId: user.userId }); // console.log("setAssistant", userObj, roomObj); // console.error("roomObj", roomObj); await updateRoomUser(roomId, userId, userObj); // // 更新roomConfig 设置助手id await setRoomConfig(roomId, roomObj); const AllRoomUsers = await getAllRoomUsers(roomId); // 同房间的其他人重置 const resetOther = Array.from(AllRoomUsers) .filter((i) => i.role !== "leader" && i.userId !== userObj.userId) .map((roomer) => { const userKey = `user:${roomer.userId}`; const unsetUserObj = Object.assign({}, roomer, { role: "customer", order: 2 }); // console.log("同房间的其他人重置", userKey, unsetUserObj); return updateRoomUser(roomId, userKey, unsetUserObj); }); //总处理完成 Promise.all(resetOther).then(() => { this.room.notify.notifyBeAssistant(roomId, userObj, this.room.userId); }); // console.log("AllRoomUsers", AllRoomUsers); // callback(user); } catch (error) { this.room.logger.error("setAssistant:error", error); } } /** * 设置MIC权 LEADER(权限) 房主或助手 * 主要 * @param {*} roomId * @param {*} userId */ async setMicRight(roomId, userId, isAllowMic) { try { const userRes = await getCurrentUser(roomId, userId, FROMTYPE.MiniAPP); const user = JSON.parse(userRes); const roomConfigRes = await getRoomConfig(roomId); // if (this.room.userId == userId && this.room.isHoster(this.room.user.role)) { // console.log("房主不用设置自己的MIC!"); // return; // } const reveseMic = Number(isAllowMic) === 0 ? 1 : 0; console.log("设置MIC权当前用户:: %s 新MIC权", user, reveseMic); const userObj = Object.assign({}, user, { isAllowMic: reveseMic }); const roomObj = Object.assign({}, roomConfigRes, { allowMicId: user.userId }); await updateRoomUser(roomId, userId, userObj); await setRoomConfig(roomId, roomObj); const AllRoomUsers = await getAllRoomUsers(roomId); // 已存在的设置为false const resetOther = Array.from(AllRoomUsers) .filter((i) => i.role !== "leader" && i.userId !== userObj.userId) .map((roomer) => { const userKey = `user:${roomer.userId}`; const unsetUserObj = Object.assign({}, roomer, { isAllowMic: 0 }); return updateRoomUser(roomId, userKey, unsetUserObj); }); Promise.all(resetOther).then(() => { this.room.notify.notifyBeHasMic(roomId, userObj, this.room.userId); }); } catch (error) { this.room.logger.error("setMicRight::error", error); } } /** * 创建房间 LEADER or assistant 房主或助手 * @param {*string} roomId * @param {*string} userId * @param {*Object} user */ async buildRoom(roomId, userId, user) { const hasJoin = await this.redis.HVALS(getInKey(roomId), userId); if (hasJoin.length === 0) { await this.redis.hSet(getInKey(roomId), userId, JSON.stringify(user)); } } /** * 关闭房间 * @param {*} roomId */ async removeRoom(roomId) { this.room.logger.info("removeRoom", { roomId }); await this.redis.del(getInKey(roomId)); } /** * 加入房间 * @param {*} roomId * @param {*} userId * @param {*} user */ async joinRoom(roomId, userId, user) { const hasRoom = await this.redis.exists(getInKey(roomId)); const isJoinRoom = await this.redis.hExists(getInKey(roomId), userId); if (hasRoom) { await this.redis.hSet(getInKey(roomId), userId, JSON.stringify(user)); } else { this.room.logger.error("不存在房间", roomId); } if (!isJoinRoom) { this.room.logger.info("加入房间 :", { userId, roomId, user }); this.socket.join(roomId); const AllRoomUsers = await getAllRoomUsers(roomId); const roomConfig = await getRoomConfig(roomId); this.socket.broadcast.emit(EVENT.roomIn, { user, roomsPerson: AllRoomUsers, roomsConfig: roomConfig, }); } else { this.room.logger.info(`已加入房间 :`, { userId }); } } /** * 离开房间 * @param {*} roomId * @param {*} userId * @param {*} user */ async leaveRoom(roomId, userId, user) { try { await this.redis.hDel(getInKey(roomId), userId); this.room.logger.info("离开房间", userId, AllRoomUsers); const AllRoomUsers = await getAllRoomUsers(roomId); const roomConfig = await getRoomConfig(roomId); this.socket.broadcast.to(roomId).emit(EVENT.roomOut, { user, roomsPerson: AllRoomUsers, roomsConfig: roomConfig, }); this.socket.broadcast.to(roomId).emit(EVENT.someOneLeaveRoom, { user, roomsPerson: AllRoomUsers, }); await this.socket.leave(roomId); } catch (error) { console.log("leaveRoom::error", error); } } /** * 房主关闭房间 * @param {*} clientRoom * @param {*} userUniqueId * @param {*} roomUniqueId */ async closeRoom(roomId, userId, user) { try { this.room.logger.info("房主关闭房间", userId); console.log("isInRoom", this.socket.rooms.has(roomId)); this.socket.broadcast.to(roomId).emit(EVENT.roomClose, { code: 3002, msg: CODEMEG[3002] }); await removeRoomAllUsers(roomId); this.socket.leave(roomId); } catch (error) { this.room.logger.error("RoomAssistant::closeRoom", error); } } /** * 呼叫房间 * @param {*} roomId * @param {*} userId * @param {*} user */ async startCall(roomId, userId, user) { try { if (!this.room.isHoster(user.role)) { this.room.logger.info("不是房主", JSON.stringify(user)); await this.joinRoom(roomId, userId, user); } else { const hasRoom = await this.redis.hVals(getInKey(roomId)); if (hasRoom.length === 0) { this.room.logger.info("房主主动创建房间 :", { roomId, userId }); await this.buildRoom(roomId, userId, user); } else { //TODO const checkIsRoomMaster = await isRoomMaster(roomId, userId); console.log("isRoomMaster", checkIsRoomMaster); if (checkIsRoomMaster) { this.room.logger.info("房主已存在房间 :", { roomId, userId, from: user.from }); await this.joinRoom(roomId, userId, user); // this.notifyUserJitter(roomId); } else { this.room.logger.error("存在非法房主", userId); } } } user.isInRoom = true; const AllRoomUsers = await getAllRoomUsers(roomId); const roomConfig = await getRoomConfig(roomId); await updateRoomUser(roomId, userId, user); this.room.logger.info("roomId", roomId); this.room.logger.info("AllRoomUsers", AllRoomUsers.length); this.socket.emit(EVENT.roomIn, { user, roomsPerson: AllRoomUsers, roomsConfig: roomConfig, }); this.socket.broadcast.to(roomId).emit(EVENT.someOneInRoom, { user, roomsPerson: AllRoomUsers, }); } catch (error) { this.room.logger.error("assistant::startCall:", error); } } async notifyUserJitter(roomId, userId) { const AllRoomUsers = await getAllRoomUsers(roomId); const roomConfig = await getRoomConfig(roomId); const currentUser = await getCurrentUser(userId, FROMTYPE.MiniAPP); const user = JSON.parse(currentUser); await updateRoomUser(roomId, userId, user); this.room.logger.info("notifyUserJitter", roomId, AllRoomUsers.length); this.socket.emit(EVENT.roomIn, { user, roomsPerson: AllRoomUsers, roomsConfig: roomConfig, }); this.socket.broadcast.to(roomId).emit(EVENT.someOneInRoom, { user, roomsPerson: AllRoomUsers, }); } /** * 通知房间人员变动 */ async notifyUsersChange(roomId, user) { const AllRoomUsers = await getAllRoomUsers(roomId); // const roomConfig = await getRoomConfig(roomId); this.room.logger.info("notifyUsersChange", roomId, AllRoomUsers.length); this.socket.broadcast.to(roomId).emit(EVENT.roomPersonChange, { user: user, // actionName: "outRoom", roomsPerson: AllRoomUsers, }); } /** * 关闭呼叫房间 * @param {*} roomId * @param {*} userId * @param {*} user */ stopCall(roomId, userId, user) { if (!this.room.isHoster(user.role)) { this.leaveRoom(roomId, userId, user); } else { this.closeRoom(roomId, userId, user); } } // 主动断开 async disconnect() { const syncId = this.room.syncId; const roomId = this.room.roomId; const userId = this.room.userId; this.socket.leave(syncId); this.socket.leave(roomId); await this.redis.del(getInKey(syncId)); await this.redis.del(getInKey(userId)); } // RoomSessionId 房间有效时间 setRoomUnlimit(roomSessionId) { return this.redis.expire(getInKey(roomSessionId), -1); } setRoomAvailableBySeconds(roomSessionId, seconds) { return this.redis.expire(getInKey(roomSessionId), seconds); } setRoomAvailableByHours(roomSessionId, hours) { return this.redis.expire(getInKey(roomSessionId), 60 * 60 * hours); } watchRoomExpired(callback) { subClient.subscribe("__keyevent@0__:expired", this.watchRoomExpiredFn); } async watchRoomExpiredFn(key) { console.log("key=> ", key); } unWatchRoomExpired() { subClient.unsubscribe("__keyevent@0__:expired", this.watchRoomExpiredFn); } }