assistant.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. // 房间行为助手
  2. import { EVENT, CODEMEG, FROMTYPE } from "../../enum/index.js";
  3. import { getCurrentUser, updateUser, removeRoomAllUsers, getAllRoomUsers, updateRoomUser } from "../../service/userService.js";
  4. import { setRoomConfig, getRoomConfig, isRoomMaster } from "../../service/roomConfigService.js";
  5. import { subClient } from "../../connection/redis.js";
  6. const prefix = process.env.REDIS_PREFIX || "chat";
  7. const getInKey = (realKey) => {
  8. return `${prefix}:${realKey}`;
  9. };
  10. export class RoomAssistant {
  11. constructor(socket, redis, room) {
  12. this.socket = socket;
  13. this.redis = redis;
  14. this.roomId = null;
  15. this.room = room;
  16. }
  17. async prepearRoom(roomSessionId, roomId) {
  18. const uRoomId = await this.redis.get(getInKey(roomSessionId));
  19. const mergeRoomId = uRoomId || roomId;
  20. this.roomId = mergeRoomId;
  21. this.room.logger.info("prepearRoom", roomSessionId, this.roomId);
  22. await this.redis.set(getInKey(roomSessionId), mergeRoomId);
  23. return Promise.resolve(this.roomId);
  24. }
  25. async destoryRoom(roomSessionId, roomConfigId) {
  26. this.room.logger.info("destoryRoom", roomSessionId, roomConfigId);
  27. await this.redis.del(getInKey(roomSessionId));
  28. await this.redis.del(getInKey(roomConfigId));
  29. this.disconnect();
  30. return Promise.resolve(true);
  31. }
  32. /**
  33. * kickPersion LEADER or assistant 房主或助手
  34. */
  35. async kickPersion(roomId, userId) {
  36. console.log("kickPersion", roomId, userId);
  37. getInKey(roomId)
  38. try {
  39. const hasJoin = await this.redis.HVALS( getInKey(roomId), userId);
  40. // const blackListId = ""
  41. if (hasJoin.length > 0) {
  42. await this.redis.hDel(getInKey(roomId), userId);
  43. return Promise.resolve(true);
  44. } else {
  45. return Promise.resolve(false);
  46. }
  47. } catch (error) {
  48. return Promise.resolve(false);
  49. }
  50. }
  51. /**
  52. * 设置助手 LEADER(权限) 房主或助手
  53. * @param {*} roomId
  54. * @param {*} userId
  55. */
  56. async setAssistant(roomId, userId, cancel) {
  57. try {
  58. const userRes = await getCurrentUser(roomId, userId, FROMTYPE.MiniAPP);
  59. const user = JSON.parse(userRes);
  60. const roomConfigRes = await getRoomConfig(roomId);
  61. if (this.room.userId == userId) {
  62. console.log("不能设置自己为助理!");
  63. return;
  64. }
  65. const role = cancel ? "customer" : "assistant";
  66. // assistant是助手,customer是普通角色,操作role会好些
  67. const userObj = Object.assign({}, user, { role: role, order: 1 });
  68. const roomObj = Object.assign({}, roomConfigRes, { assistantId: user.userId });
  69. // console.log("setAssistant", userObj, roomObj);
  70. // console.error("roomObj", roomObj);
  71. await updateRoomUser(roomId, userId, userObj);
  72. // // 更新roomConfig 设置助手id
  73. await setRoomConfig(roomId, roomObj);
  74. const AllRoomUsers = await getAllRoomUsers(roomId);
  75. // 同房间的其他人重置
  76. const resetOther = Array.from(AllRoomUsers)
  77. .filter((i) => i.role !== "leader" && i.userId !== userObj.userId)
  78. .map((roomer) => {
  79. const userKey = `user:${roomer.userId}`;
  80. const unsetUserObj = Object.assign({}, roomer, { role: "customer", order: 2 });
  81. // console.log("同房间的其他人重置", userKey, unsetUserObj);
  82. return updateRoomUser(roomId, userKey, unsetUserObj);
  83. });
  84. //总处理完成
  85. Promise.all(resetOther).then(() => {
  86. this.room.notify.notifyBeAssistant(roomId, userObj, this.room.userId);
  87. });
  88. // console.log("AllRoomUsers", AllRoomUsers);
  89. // callback(user);
  90. } catch (error) {
  91. this.room.logger.error("setAssistant:error", error);
  92. }
  93. }
  94. /**
  95. * 设置MIC权 LEADER(权限) 房主或助手
  96. * 主要
  97. * @param {*} roomId
  98. * @param {*} userId
  99. */
  100. async setMicRight(roomId, userId, isAllowMic) {
  101. try {
  102. const userRes = await getCurrentUser(roomId, userId, FROMTYPE.MiniAPP);
  103. const user = JSON.parse(userRes);
  104. const roomConfigRes = await getRoomConfig(roomId);
  105. // if (this.room.userId == userId && this.room.isHoster(this.room.user.role)) {
  106. // console.log("房主不用设置自己的MIC!");
  107. // return;
  108. // }
  109. const reveseMic = Number(isAllowMic) === 0 ? 1 : 0;
  110. console.log("设置MIC权当前用户:: %s 新MIC权", user, reveseMic);
  111. const userObj = Object.assign({}, user, { isAllowMic: reveseMic });
  112. const roomObj = Object.assign({}, roomConfigRes, { allowMicId: user.userId });
  113. await updateRoomUser(roomId, userId, userObj);
  114. await setRoomConfig(roomId, roomObj);
  115. const AllRoomUsers = await getAllRoomUsers(roomId);
  116. // 已存在的设置为false
  117. const resetOther = Array.from(AllRoomUsers)
  118. .filter((i) => i.role !== "leader" && i.userId !== userObj.userId)
  119. .map((roomer) => {
  120. const userKey = `user:${roomer.userId}`;
  121. const unsetUserObj = Object.assign({}, roomer, { isAllowMic: 0 });
  122. return updateRoomUser(roomId, userKey, unsetUserObj);
  123. });
  124. Promise.all(resetOther).then(() => {
  125. this.room.notify.notifyBeHasMic(roomId, userObj, this.room.userId);
  126. });
  127. } catch (error) {
  128. this.room.logger.error("setMicRight::error", error);
  129. }
  130. }
  131. /**
  132. * 创建房间 LEADER or assistant 房主或助手
  133. * @param {*string} roomId
  134. * @param {*string} userId
  135. * @param {*Object} user
  136. */
  137. async buildRoom(roomId, userId, user) {
  138. const hasJoin = await this.redis.HVALS(getInKey(roomId), userId);
  139. if (hasJoin.length === 0) {
  140. await this.redis.hSet(getInKey(roomId), userId, JSON.stringify(user));
  141. }
  142. }
  143. /**
  144. * 关闭房间
  145. * @param {*} roomId
  146. */
  147. async removeRoom(roomId) {
  148. this.room.logger.info("removeRoom", { roomId });
  149. await this.redis.del(getInKey(roomId));
  150. }
  151. /**
  152. * 加入房间
  153. * @param {*} roomId
  154. * @param {*} userId
  155. * @param {*} user
  156. */
  157. async joinRoom(roomId, userId, user) {
  158. const hasRoom = await this.redis.exists(getInKey(roomId));
  159. const isJoinRoom = await this.redis.hExists(getInKey(roomId), userId);
  160. if (hasRoom) {
  161. await this.redis.hSet(getInKey(roomId), userId, JSON.stringify(user));
  162. } else {
  163. this.room.logger.error("不存在房间", roomId);
  164. }
  165. if (!isJoinRoom) {
  166. this.room.logger.info("加入房间 :", { userId, roomId, user });
  167. this.socket.join(roomId);
  168. const AllRoomUsers = await getAllRoomUsers(roomId);
  169. const roomConfig = await getRoomConfig(roomId);
  170. this.socket.broadcast.emit(EVENT.roomIn, {
  171. user,
  172. roomsPerson: AllRoomUsers,
  173. roomsConfig: roomConfig,
  174. });
  175. } else {
  176. this.room.logger.info(`已加入房间 :`, { userId });
  177. }
  178. }
  179. /**
  180. * 离开房间
  181. * @param {*} roomId
  182. * @param {*} userId
  183. * @param {*} user
  184. */
  185. async leaveRoom(roomId, userId, user) {
  186. try {
  187. await this.redis.hDel(getInKey(roomId), userId);
  188. this.room.logger.info("离开房间", userId, AllRoomUsers);
  189. const AllRoomUsers = await getAllRoomUsers(roomId);
  190. const roomConfig = await getRoomConfig(roomId);
  191. this.socket.broadcast.to(roomId).emit(EVENT.roomOut, {
  192. user,
  193. roomsPerson: AllRoomUsers,
  194. roomsConfig: roomConfig,
  195. });
  196. this.socket.broadcast.to(roomId).emit(EVENT.someOneLeaveRoom, {
  197. user,
  198. roomsPerson: AllRoomUsers,
  199. });
  200. await this.socket.leave(roomId);
  201. } catch (error) {
  202. console.log("leaveRoom::error", error);
  203. }
  204. }
  205. /**
  206. * 房主关闭房间
  207. * @param {*} clientRoom
  208. * @param {*} userUniqueId
  209. * @param {*} roomUniqueId
  210. */
  211. async closeRoom(roomId, userId, user) {
  212. try {
  213. this.room.logger.info("房主关闭房间", userId);
  214. console.log("isInRoom", this.socket.rooms.has(roomId));
  215. this.socket.broadcast.to(roomId).emit(EVENT.roomClose, { code: 3002, msg: CODEMEG[3002] });
  216. await removeRoomAllUsers(roomId);
  217. this.socket.leave(roomId);
  218. } catch (error) {
  219. this.room.logger.error("RoomAssistant::closeRoom", error);
  220. }
  221. }
  222. /**
  223. * 呼叫房间
  224. * @param {*} roomId
  225. * @param {*} userId
  226. * @param {*} user
  227. */
  228. async startCall(roomId, userId, user) {
  229. try {
  230. if (!this.room.isHoster(user.role)) {
  231. this.room.logger.info("不是房主", JSON.stringify(user));
  232. await this.joinRoom(roomId, userId, user);
  233. } else {
  234. const hasRoom = await this.redis.hVals(getInKey(roomId));
  235. if (hasRoom.length === 0) {
  236. this.room.logger.info("房主主动创建房间 :", { roomId, userId });
  237. await this.buildRoom(roomId, userId, user);
  238. } else {
  239. //TODO
  240. const checkIsRoomMaster = await isRoomMaster(roomId, userId);
  241. console.log("isRoomMaster", checkIsRoomMaster);
  242. if (checkIsRoomMaster) {
  243. this.room.logger.info("房主已存在房间 :", { roomId, userId, from: user.from });
  244. await this.joinRoom(roomId, userId, user);
  245. // this.notifyUserJitter(roomId);
  246. } else {
  247. this.room.logger.error("存在非法房主", userId);
  248. }
  249. }
  250. }
  251. user.isInRoom = true;
  252. const AllRoomUsers = await getAllRoomUsers(roomId);
  253. const roomConfig = await getRoomConfig(roomId);
  254. await updateRoomUser(roomId, userId, user);
  255. this.room.logger.info("roomId", roomId);
  256. this.room.logger.info("AllRoomUsers", AllRoomUsers.length);
  257. this.socket.emit(EVENT.roomIn, {
  258. user,
  259. roomsPerson: AllRoomUsers,
  260. roomsConfig: roomConfig,
  261. });
  262. this.socket.broadcast.to(roomId).emit(EVENT.someOneInRoom, {
  263. user,
  264. roomsPerson: AllRoomUsers,
  265. });
  266. } catch (error) {
  267. this.room.logger.error("assistant::startCall:", error);
  268. }
  269. }
  270. async notifyUserJitter(roomId, userId) {
  271. const AllRoomUsers = await getAllRoomUsers(roomId);
  272. const roomConfig = await getRoomConfig(roomId);
  273. const currentUser = await getCurrentUser(userId, FROMTYPE.MiniAPP);
  274. const user = JSON.parse(currentUser);
  275. await updateRoomUser(roomId, userId, user);
  276. this.room.logger.info("notifyUserJitter", roomId, AllRoomUsers.length);
  277. this.socket.emit(EVENT.roomIn, {
  278. user,
  279. roomsPerson: AllRoomUsers,
  280. roomsConfig: roomConfig,
  281. });
  282. this.socket.broadcast.to(roomId).emit(EVENT.someOneInRoom, {
  283. user,
  284. roomsPerson: AllRoomUsers,
  285. });
  286. }
  287. /**
  288. * 通知房间人员变动
  289. */
  290. async notifyUsersChange(roomId, user) {
  291. const AllRoomUsers = await getAllRoomUsers(roomId);
  292. // const roomConfig = await getRoomConfig(roomId);
  293. this.room.logger.info("notifyUsersChange", roomId, AllRoomUsers.length);
  294. this.socket.broadcast.to(roomId).emit(EVENT.roomPersonChange, {
  295. user: user,
  296. // actionName: "outRoom",
  297. roomsPerson: AllRoomUsers,
  298. });
  299. }
  300. /**
  301. * 关闭呼叫房间
  302. * @param {*} roomId
  303. * @param {*} userId
  304. * @param {*} user
  305. */
  306. stopCall(roomId, userId, user) {
  307. if (!this.room.isHoster(user.role)) {
  308. this.leaveRoom(roomId, userId, user);
  309. } else {
  310. this.closeRoom(roomId, userId, user);
  311. }
  312. }
  313. // 主动断开
  314. async disconnect() {
  315. const syncId = this.room.syncId;
  316. const roomId = this.room.roomId;
  317. const userId = this.room.userId;
  318. this.socket.leave(syncId);
  319. this.socket.leave(roomId);
  320. await this.redis.del(getInKey(syncId));
  321. await this.redis.del(getInKey(userId));
  322. }
  323. // RoomSessionId 房间有效时间
  324. setRoomUnlimit(roomSessionId) {
  325. return this.redis.expire(getInKey(roomSessionId), -1);
  326. }
  327. setRoomAvailableBySeconds(roomSessionId, seconds) {
  328. return this.redis.expire(getInKey(roomSessionId), seconds);
  329. }
  330. setRoomAvailableByHours(roomSessionId, hours) {
  331. return this.redis.expire(getInKey(roomSessionId), 60 * 60 * hours);
  332. }
  333. watchRoomExpired(callback) {
  334. subClient.subscribe("__keyevent@0__:expired", this.watchRoomExpiredFn);
  335. }
  336. async watchRoomExpiredFn(key) {
  337. console.log("key=> ", key);
  338. }
  339. unWatchRoomExpired() {
  340. subClient.unsubscribe("__keyevent@0__:expired", this.watchRoomExpiredFn);
  341. }
  342. }