index.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. import { ROLES, CODEMEG, EVENT, FROMTYPE } from "../../enum/index.js";
  2. import { getCurrentUser, updateUser, removeRoomAllUsers, getAllRoomUsers, updateRoomUser } from "../../service/userService.js";
  3. // import { watchRoomService } from "../../service/watchRoomService.js";
  4. import { setRoomConfig, getRoomConfig, updateRoomConfigByKey, isRoomMaster } from "../../service/roomConfigService.js";
  5. import { RoomAssistant } from "./assistant.js";
  6. import { Notify } from "./notify.js";
  7. import { BasicController } from "../basicController.js";
  8. export class RoomController extends BasicController {
  9. constructor(...args) {
  10. super(...args);
  11. this.roomAssistant = new RoomAssistant(this.socket, this.redisCli, this);
  12. this.notify = new Notify(this.socket, this.redisCli, this);
  13. this.roomId = null;
  14. this.sessionId = null;
  15. this.userId = null;
  16. this.roomConfigId = null;
  17. this.debugger = true;
  18. this.user = {
  19. sig: null,
  20. roomId: null,
  21. userId: null,
  22. sceneNum: null,
  23. isClient: null,
  24. avatar: "",
  25. role: null,
  26. userLimitNum: null,
  27. sceneNumber: null,
  28. order: 2,
  29. from: null,
  30. assistantId: null,
  31. onlineStatus: 0,
  32. voiceStatus: 0,
  33. enableTalk: null,
  34. };
  35. }
  36. // 以小程序user信息作为主要信息
  37. async currentUser() {
  38. const data = await getCurrentUser(this.userId, FROMTYPE.MiniAPP);
  39. const user = data ? JSON.parse(data) : this.user;
  40. return user;
  41. }
  42. async run() {
  43. this.logger.info("socket conetcted has start!");
  44. try {
  45. await this.init();
  46. this.initBaseAction();
  47. this.roomMasterAutoRejoin();
  48. this.roomAssistant.watchRoomExpired();
  49. // setInterval(async () => {
  50. // if ([FROMTYPE.Bridge].includes(Number(this.user.from))) {
  51. // const AllRoomUsers = await getAllRoomUsers(this.roomId);
  52. // this.socket.broadcast.to(this.roomId).emit(EVENT.roomStatus, {
  53. // roomsPerson: AllRoomUsers,
  54. // });
  55. // console.log("定时测试", this.roomId);
  56. // }
  57. // }, 10000);
  58. } catch (error) {
  59. this.logger.error("roomController::run::error", error);
  60. }
  61. }
  62. async init() {
  63. let user = this.socket.handshake.query;
  64. this.logger.info("init-user-query:", this.socket.handshake.query);
  65. if (user) {
  66. this.user = Object.assign({}, user);
  67. this.user.sig = this.getSig(this.user.userId);
  68. const oneSceneNum = this.user.sceneNumber || this.user.sceneNum;
  69. const { userId, roomId } = this.user;
  70. await this.initParams(userId, roomId, oneSceneNum);
  71. let order;
  72. switch (this.user.role) {
  73. case "leader":
  74. order = 0;
  75. break;
  76. case "assistant":
  77. order = 1;
  78. break;
  79. case "customer":
  80. order = 2;
  81. break;
  82. default:
  83. order = 2;
  84. break;
  85. }
  86. const userObj = { ...this.user, onlineStatus: 1, isConnected: true, order };
  87. const assistantId = this.roomAssistant.getRoomAssistant(this.roomId);
  88. if (assistantId && this.userId !== assistantId && !this.isHoster(this.user.role)) {
  89. this.logger.info("已存在默认助手变更:" + "room助手ID:" assistantId +"userId: " + this.userId);
  90. userObj.role = "customer";
  91. }
  92. this.logger.info("update-user-info:", userObj);
  93. updateUser(this.userId, userObj);
  94. // this.sysUsers.push(this.user);
  95. // 只有来源于小程序用户信息才记录到redis
  96. if (this.isHoster(this.user.role)) {
  97. if ([FROMTYPE.MiniAPP].includes(Number(this.user.from))) {
  98. const roomConfig = getRoomConfig(this.roomId);
  99. const checkoutMaster = await isRoomMaster(this.roomId, this.userId);
  100. const isNoExistMaster = "masterId" in roomConfig;
  101. // console.log("checkoutMaster-isNoExistMaster", checkoutMaster, !isNoExistMaster);
  102. if (checkoutMaster || !isNoExistMaster) {
  103. console.log("房主进入记录信息::: checkoutMaster: %s, isNoExistMaster: %s ,roomId %s", checkoutMaster, !isNoExistMaster, this.roomId);
  104. const roomConfig = {
  105. masterId: this.userId,
  106. userLimitNum: this.user.userLimitNum,
  107. enableTalk: this.user.enableTalk === "true" ? true : false,
  108. };
  109. console.log("roomConfig", roomConfig);
  110. // console.log("roomConfig", roomConfig);
  111. await setRoomConfig(this.roomId, roomConfig);
  112. }
  113. }
  114. }
  115. // 加入
  116. console.log("roomId", this.roomId);
  117. this.socket.join(this.roomId);
  118. } else {
  119. this.logger.info("user-query-不存在 :", this.socket.handshake.query);
  120. this.socket.disconnect();
  121. }
  122. }
  123. async initParams(userId, roomId, oneSceneNum) {
  124. this.userId = `user:${userId}`;
  125. this.syncId = `sync:${oneSceneNum}:${userId}`;
  126. this.sessionId = `session:${oneSceneNum}:${userId}`;
  127. const uRoomId = await this.roomAssistant.prepearRoom(this.sessionId, roomId);
  128. // this.roomId = `room:${uRoomId}_${oneSceneNum}`;
  129. this.roomId = `room:${oneSceneNum}:${uRoomId}`;
  130. this.user.roomId = uRoomId;
  131. this.roomConfigId = `config:${this.roomId}`;
  132. return Promise.resolve(true);
  133. }
  134. initBaseAction() {
  135. // 通知 baseView 减少大量通知
  136. this.socket.on(EVENT.webSyncAction, (data) => {
  137. // socket.broadcast.to(roomUniqueId).emit(EVENT.webSyncAction, data);
  138. try {
  139. if ([FROMTYPE.base].includes(Number(this.user.from))) {
  140. this.socket.broadcast.to(this.roomId).emit(EVENT.webSyncAction, data);
  141. }
  142. } catch (error) {
  143. this.logger.error("roomController::EVENT.webSyncAction", error);
  144. }
  145. });
  146. // 转发action
  147. this.socket.on(EVENT.action, (data) => {
  148. try {
  149. this.logger.debug("room-action", this.roomId, this.socket.rooms.has(this.roomId), JSON.stringify(data));
  150. if (this.socket.rooms.has(this.roomId)) {
  151. this.socket.broadcast.to(this.roomId).emit(EVENT.action, data);
  152. } else {
  153. this.logger.error("action 事件不在房间内", this.user);
  154. }
  155. } catch (error) {
  156. this.logger.error("roomController::EVENT.action", error);
  157. }
  158. });
  159. this.socket.on(EVENT.startCall, async () => {
  160. const user = await this.currentUser();
  161. this.roomAssistant.startCall(this.roomId, this.userId, user);
  162. // console.log("startCall-from", this.user.from);
  163. if (this.isHoster(this.user.role)) {
  164. // 以startCall做为真正的进入房间
  165. await updateRoomConfigByKey(this.roomId, "isStart", true);
  166. }
  167. });
  168. this.socket.on(EVENT.stopCall, () => {
  169. this.roomAssistant.stopCall(this.roomId, this.userId, this.user);
  170. if (this.isHoster(this.user.role)) {
  171. // 以stopCall断开做为真正的退出房间
  172. this.roomAssistant.destoryRoom(this.sessionId, this.roomConfigId);
  173. }
  174. });
  175. this.socket.on(EVENT.changeRoomEnableTalk, async (data) => {
  176. // this._roomsConfig[roomId].enableTalk = data;
  177. try {
  178. const roomConfig = await getRoomConfig(this.roomId);
  179. roomConfig.enableTalk = data;
  180. await setRoomConfig(this.roomId, roomConfig);
  181. this.logger.info("changeRoomEnableTalk", JSON.stringify(data));
  182. this.socket.broadcast.to(this.roomId).emit(EVENT.changeRoomEnableTalk, roomConfig);
  183. } catch (error) {
  184. this.logger.error("event:changeRoomEnableTalk", error);
  185. }
  186. });
  187. this.socket.on(EVENT.changeOnlineStatus, async (data) => {
  188. try {
  189. const user = await this.currentUser();
  190. user.onlineStatus = data.status;
  191. await updateRoomUser(this.roomId, this.userId, user);
  192. let actionName = Number(this.user.onlineStatus) === 1 ? "inRoom" : "leaveRoom";
  193. this.logger.info("changeOnlineStatus", JSON.stringify(user));
  194. const AllRoomUsers = await getAllRoomUsers(this.roomId);
  195. this.socket.broadcast.to(this.roomId).emit(EVENT.roomPersonChange, {
  196. roomsPerson: AllRoomUsers,
  197. actionName,
  198. user: user,
  199. });
  200. } catch (error) {
  201. this.logger.error("event:changeOnlineStatus", error);
  202. }
  203. });
  204. /**
  205. * 踢人管理
  206. */
  207. this.socket.on(EVENT.kickUser, async ({ data, from }) => {
  208. try {
  209. const userId = `user:${data.userId}`;
  210. const roomId = `room:${data.sceneNumber}:${data.roomId}`;
  211. const currentUser = await getCurrentUser(userId, FROMTYPE.MiniAPP);
  212. const user = JSON.parse(currentUser);
  213. // 被踢人不能是hoster
  214. console.log("user", JSON.stringify(user));
  215. if (user && !this.isHoster(user.role)) {
  216. console.log("currentUser.role", user.role);
  217. const isKick = await this.roomAssistant.kickPersion(roomId, userId);
  218. if (isKick) {
  219. const AllRoomUsers = await getAllRoomUsers(roomId);
  220. console.log("kickUser-AllRoomUsers", AllRoomUsers.length);
  221. this.logger.info("kickUser", currentUser, userId, roomId);
  222. // 通知管理
  223. this.socket.emit(EVENT.someOneLeaveRoom, {
  224. user: user,
  225. roomsPerson: AllRoomUsers,
  226. });
  227. // 通知房间人员变动
  228. this.socket.broadcast.to(roomId).emit(EVENT.someOneLeaveRoom, {
  229. user: user,
  230. roomsPerson: AllRoomUsers,
  231. });
  232. // 如果踢人后 如何通知?
  233. this.socket.broadcast.to(roomId).emit(EVENT.beKicked, data);
  234. }
  235. } else {
  236. const nickname = user.nickname || "";
  237. this.logger.warn(nickname + "是房主,不能被踢!!");
  238. }
  239. } catch (error) {
  240. console.error("error", error);
  241. }
  242. });
  243. /**
  244. * 设置助手
  245. */
  246. this.socket.on("setAssistant", async ({ data, from }) => {
  247. const userId = `user:${data.userId}`;
  248. const roomId = `room:${data.sceneNumber}:${data.roomId}`;
  249. console.log("设置助手", userId, roomId);
  250. this.roomAssistant.setAssistant(roomId, userId, data.cancel);
  251. });
  252. /**
  253. * 设置MIC权
  254. */
  255. this.socket.on("setUserhasMic", async ({ data, from, isAllowMic }) => {
  256. const userId = `user:${data.userId}`;
  257. const roomId = `room:${data.sceneNumber}:${data.roomId}`;
  258. console.log("设置MIC权", userId, roomId, data.isAllowMic);
  259. this.roomAssistant.setMicRight(roomId, userId, data.isAllowMic);
  260. });
  261. if (this.debugger) {
  262. this.socket.onAny((event, data) => {
  263. if (event !== "webSyncAction") {
  264. // console.log(`onAny:get ${event}, data:${JSON.stringify(data)}`);
  265. this.logger.info(`onAny:get ${event}, data:${JSON.stringify(data)}`);
  266. }
  267. });
  268. }
  269. }
  270. async roomMasterAutoRejoin() {
  271. try {
  272. const sessionExist = await this.redisCli.exists(this.sessionId);
  273. const roomConfig = await getRoomConfig(this.roomId);
  274. if (sessionExist > 0 && roomConfig.isStart && roomConfig.isStart === "true") {
  275. const AllRoomUsers = await getAllRoomUsers(this.roomId);
  276. // 房主
  277. if (this.isHoster(this.user.role)) {
  278. console.log("自动接连", this.roomId, this.user.from);
  279. this.socket.join(this.roomId);
  280. this.socket.emit("autoReJoin", {
  281. user: this.user,
  282. roomsPerson: AllRoomUsers,
  283. roomId: this.user.roomId,
  284. });
  285. }
  286. //TODO someOneInRoom是用来触发语音与更新房间状态
  287. // setTimeout(() => {
  288. // this.socket.emit("someOneInRoom", {
  289. // user: this.user,
  290. // roomsPerson: AllRoomUsers,
  291. // });
  292. // });
  293. }
  294. } catch (error) {
  295. this.logger.error("room::roomMasterAutoRejoin", error);
  296. }
  297. }
  298. }