room.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /**
  2. * 直播间男女端共用Manager
  3. */
  4. 'use strict';
  5. const F = require('../common/function');
  6. const C = require('../config');
  7. const _ = require('underscore');
  8. _.str = require('underscore.string');
  9. _.v = require('validator');
  10. const co = require('co');
  11. module.exports = function (app, commonManager) {
  12. let mgr_map = commonManager.mgr_map;
  13. let that = this;
  14. /**
  15. * 进入房间逻辑 添加房间对应redis 推送进入房间通知
  16. * @param uid
  17. * @param socket_id
  18. * @param room_id
  19. */
  20. this.enterRoom = function* (uid, socket_id, room_id) {
  21. let old_socket_list = yield mgr_map.redis.getSocketListByUidAndRoomid(uid, room_id); // 查找当前用户在这个房间的旧socket
  22. for (let i = 0; i < old_socket_list.length; i++) {
  23. yield mgr_map.redis.delRoomSocketList(room_id, old_socket_list[i]); // 删除房间对应旧socket列表记录 socket断开函数也执行
  24. yield mgr_map.redis.delUidRoomSocketList(uid, room_id, old_socket_list[i]); // 删除指定用户+指定房间旧socket列表记录 socket断开函数也执行
  25. }
  26. yield mgr_map.redis.addSocketToRoom(room_id, socket_id);// 添加房间对应socket列表记录
  27. yield mgr_map.redis.addSocketToUidRoom(uid, room_id, socket_id);//添加uid+房间id对应socket列表记录
  28. yield mgr_map.redis.addRoomidToSocket(socket_id, room_id);// 反向记录socket在哪个房间
  29. yield mgr_map.redis.addUidToRoom(room_id, uid);// 添加房间用户列表记录 修改进入时间
  30. let online_num = yield mgr_map.redis.addRoomOnlineNum(room_id); // 增加房间在线人数
  31. // 推送进入房间通知
  32. let room_socket = yield mgr_map.redis.getRoomSocketList(room_id);
  33. let room_info = yield mgr_map.room.getRoomInfo(room_id);
  34. co(that.syncOnlineNum(room_id, uid, online_num, 1));// 同步房间在线人数
  35. let enterRoomWhiteList = yield mgr_map.redis.getEnterRoomWhiteList();
  36. if (!F.isNull(enterRoomWhiteList) && enterRoomWhiteList.indexOf(uid.toString()) >= 0) {}
  37. else yield mgr_map.notice.pushChatRoomMemberIn(room_socket, room_info, uid);
  38. };
  39. /**
  40. * 离开房间删除对应redis 发离开房间通知 删除麦redis 发下麦通知
  41. * @param uid
  42. * @param uniid
  43. * @param room_id
  44. */
  45. this.leaveRoom = function* (uid, socketId, room_id) {
  46. //1 删除下麦
  47. yield mgr_map.roomQueue.delFromRoomQueueByUid(uid, room_id, uid);
  48. //2 离开房间删除对应redis
  49. yield mgr_map.redis.delRoomSocketList(room_id, socketId); // 删除房间对应socket列表记录 socket断开函数也执行
  50. yield mgr_map.redis.delUidRoomSocketList(uid, room_id, socketId); // 删除指定用户+指定房间socket列表记录 socket断开函数也执行
  51. yield mgr_map.redis.delSocketRoomList(socketId, room_id); // 删除socket对应在房间记录 socket断开函数也执行
  52. yield mgr_map.redis.delRoomUserList(room_id, uid); // 删除房间对应用户列表
  53. let online_num = yield mgr_map.redis.addRoomOnlineNum(room_id); // 增加房间在线人数
  54. //3 发离开房间通知
  55. let user_info = yield mgr_map.member.getJavaUserInfo(uid);
  56. if (F.isNull(user_info)) F.throwErrCode(100101);
  57. let room_socket = yield mgr_map.redis.getRoomSocketList(room_id); // 发送离开通知给房间其他用户
  58. co(that.syncOnlineNum(room_id, uid, online_num, 2));// 同步房间在线人数
  59. yield mgr_map.notice.pushLeaveRoomNotice(room_socket, room_id, uid, user_info.nick);
  60. co(mgr_map.extrn.delZegoStream(room_id, uid));
  61. };
  62. this.kickOffRoom = function* (uid, room_id, reason_no = null, reason_msg = null) {
  63. if (F.isNull(reason_no)) {
  64. reason_no = 1;
  65. }
  66. if (F.isNull(reason_msg)) {
  67. reason_msg = F.tipsWithParam(1);
  68. }
  69. let user_info = yield mgr_map.member.getJavaUserInfo(uid);
  70. if (F.isNull(user_info)) {
  71. F.throwErrCode(100101);
  72. }
  73. let socket_list = yield mgr_map.redis.getSocketListByUidAndRoomid(uid, room_id);
  74. if (F.isNull(socket_list)) {
  75. F.throwErrCode(100201);
  76. }
  77. let is_robot = false;
  78. for (let i = 0; i < socket_list.length; i++) {
  79. if (socket_list[i].indexOf("robot_") >= 0) {
  80. is_robot = true;
  81. continue;
  82. } else {
  83. yield that.leaveRoom(uid, socket_list[i], room_id);
  84. }
  85. }
  86. if (!is_robot) yield mgr_map.notice.pushMemberKicked(socket_list, room_id, user_info.account, user_info.nick, user_info.avatar, reason_no, reason_msg);
  87. };
  88. /**
  89. * 剔除房间中所有的成员
  90. * @param room_id
  91. * @param reason_no
  92. * @param reason_msg
  93. */
  94. this.kickOffRoomAllUser = function* (room_id, reason_no = null, reason_msg = null) {
  95. let room_uid_list = yield mgr_map.redis.getRoomUserList(room_id);
  96. for (let i = 0; i < room_uid_list.length; i++) {
  97. co(that.kickOffRoom(room_uid_list[i], room_id, F.isNull(reason_no) ? 3 : reason_no, reason_msg));
  98. }
  99. };
  100. /**
  101. * 离开该用户之前所在的房间
  102. * @param uid
  103. */
  104. this.leavePreRoom = function* (uid) {
  105. let socket_id_list = yield mgr_map.redis.getUserSocketList(uid);
  106. for (let i = 0; i < socket_id_list.length; i++) {
  107. let room_id_list = yield mgr_map.redis.getSocketRoomList(socket_id_list[i]);
  108. for (let j = 0; j < room_id_list.length; j++) {
  109. yield mgr_map.room.leaveRoom(uid, socket_id_list[i], room_id_list[j]);
  110. }
  111. }
  112. };
  113. this.cleanSockAndLeaveRoom = function* (socketId, ctx = {}, page_name = 0, delay_time = 0) {
  114. try {
  115. // 以下处理普通房间
  116. F.addDebugLogs(["im断线房间处理函数:socketId:>", socketId," delay_time:",delay_time]);
  117. yield mgr_map.redis.delUserSocketList(ctx.uid, socketId); // 删除用户socket记录
  118. let room_list = yield mgr_map.redis.getSocketRoomList(socketId); // 获取之前socket在哪些房间
  119. F.addDebugLogs(["socketCleaner data:", ctx.uid, socketId, room_list]);
  120. for (let i = 0; i < room_list.length; i++) {
  121. let room_id = room_list[i];
  122. yield mgr_map.redis.delRoomSocketList(room_id, socketId); // 删除房间对应socket列表记录
  123. yield mgr_map.redis.delUidRoomSocketList(ctx.uid, room_id, socketId); // 删除指定用户+指定房间socket列表记录
  124. yield mgr_map.redis.delSocketRoomList(socketId, room_id); // 删除socket对应在房间记录
  125. }
  126. if (!F.isNull(room_list)) {
  127. // 放入db定时器8秒后执行manager/dbTimer.js 的 socketCleaner 判断是否有新socket过来 如果没有要退出房间 下麦
  128. yield mgr_map.dbTimer.addDBTimer((10-delay_time) * 1000, 'socketCleaner', {
  129. 'uid': ctx.uid,
  130. 'socketId': socketId,
  131. 'room_list': room_list
  132. });
  133. }
  134. // 以下处理大厅
  135. F.addDebugLogs(["err:", "im断线房间处理函数,leavePublicRoom:socketId:>%s", socketId]);
  136. yield mgr_map.publicRoom.leavePublicRoom(ctx.uid, socketId);
  137. } catch (e) {
  138. F.addErrLogs(["abnormalClose error:", e.stack]);
  139. }
  140. };
  141. /**
  142. * im断线处理函数 业务相关逻辑在此处理
  143. * @param socketId socketID
  144. * @returns {*}
  145. */
  146. this.abnormalClose = function* (socketId, ctx = {}, page_name = 0) {
  147. let delay_time = 2;
  148. yield this.cleanSockAndLeaveRoom(socketId,ctx,page_name,0);
  149. yield F.sleep(delay_time*1000); // 延迟2秒
  150. yield this.cleanSockAndLeaveRoom(socketId,ctx,page_name,delay_time); // 再处理一次 以防有正在进房间逻辑
  151. };
  152. this.markChatRoomManager = function* (room_id, account) {
  153. let room_info = yield mgr_map.room.getRoomInfo(room_id);
  154. if (F.isNull(room_info)) {
  155. F.throwErrCode(100200);
  156. }
  157. let isRoomManager = yield mgr_map.validator.isRoomManager(room_id, account);
  158. if (isRoomManager) {
  159. F.throwErrCode(100402);
  160. }
  161. yield mgr_map.redis.setRoomManager(room_id, account);
  162. let member = yield mgr_map.member.getJavaUserInfo(account);
  163. member = yield mgr_map.member.extendMemberInfo(member, room_info);
  164. let room_socket = yield mgr_map.redis.getRoomSocketList(room_id);
  165. co(mgr_map.notice.pushManagerAdd(room_socket, room_id, member));
  166. };
  167. this.removeChatRoomManager = function* (room_id, account) {
  168. let room_info = yield mgr_map.room.getRoomInfo(room_id);
  169. if (F.isNull(room_info)) {
  170. F.throwErrCode(100200);
  171. }
  172. let is_manager = yield mgr_map.validator.isRoomManager(room_id, account);
  173. if (!is_manager) {
  174. F.throwErrCode(100403);
  175. }
  176. yield mgr_map.redis.delRoomManager(room_id, account);
  177. let member = yield mgr_map.member.getJavaUserInfo(account);
  178. member = yield mgr_map.member.extendMemberInfo(member, room_info);
  179. let room_socket = yield mgr_map.redis.getRoomSocketList(room_id);
  180. co(mgr_map.notice.pushManagerRemove(room_socket, room_id, member));
  181. };
  182. /**
  183. * 聊天室黑名单添加通知
  184. * @param room_id 房间ID
  185. * @param account 要加入黑名单uid
  186. * @returns {IterableIterator<*>}
  187. */
  188. this.markChatRoomBlackList = function* (room_id, uid, account) {
  189. let is_blacklist = yield mgr_map.redis.isBlacklist(room_id, account);
  190. if (is_blacklist) {
  191. F.throwErrCode(100400);
  192. }
  193. let member = yield mgr_map.member.getJavaUserInfo(account);
  194. if (F.isNull(member)) {
  195. F.throwErrCode(100404);
  196. }
  197. let black_info = {
  198. 'uid': uid,
  199. 'date': new Date().getTime()
  200. };
  201. //TODO feimat 包装manager函数
  202. yield mgr_map.redis.setRoomBlacklist(room_id, account, black_info);
  203. let room_socket = yield mgr_map.redis.getRoomSocketList(room_id);
  204. co(mgr_map.notice.pushMarkChatRoomBlackListNotice(room_socket, room_id, member));
  205. //TODO feimat 包装manager函数
  206. yield mgr_map.redis.delRoomManager(room_id, account);
  207. co(mgr_map.notice.pushManagerRemove(room_socket, room_id, member));
  208. yield mgr_map.room.kickOffRoom(account, room_id, 2, F.tipsWithParam(2));
  209. // mgr_map.member.kickMember(room_id, account, 2, "拉黑名单踢出");
  210. };
  211. /**
  212. * 聊天室黑名单删除通知
  213. * @param room_id 房间ID
  214. * @param account 要删除黑名单uid
  215. * @returns {IterableIterator<*>}
  216. */
  217. this.removeChatRoomBlackList = function* (room_id, account) {
  218. yield mgr_map.redis.delRoomBlacklist(room_id, account);
  219. };
  220. /**
  221. * 聊天室禁言添加通知
  222. */
  223. this.markChatRoomMute = function* (room_id, uid, account) {
  224. let is_mute = yield mgr_map.redis.isMute(room_id, account);
  225. if (is_mute) {
  226. F.throwErrCode(100406);
  227. }
  228. let member = yield mgr_map.member.getJavaUserInfo(account);
  229. if (F.isNull(member)) {
  230. F.throwErrCode(100404);
  231. }
  232. let mute_info = {
  233. 'uid': uid,
  234. 'date': new Date().getTime()
  235. };
  236. //TODO feimat 包装manager函数
  237. yield mgr_map.redis.setRoomMute(room_id, account, mute_info);
  238. let room_socket = yield mgr_map.redis.getRoomSocketList(room_id);
  239. co(mgr_map.notice.pushMarkChatRoomMuteNotice(room_socket, room_id, member));
  240. };
  241. /**
  242. * 聊天室禁言删除通知
  243. */
  244. this.removeChatRoomMute = function* (room_id, account) {
  245. let member = yield mgr_map.member.getJavaUserInfo(account);
  246. if (F.isNull(member)) {
  247. F.throwErrCode(100404);
  248. }
  249. yield mgr_map.redis.delRoomMute(room_id, account);
  250. let room_socket = yield mgr_map.redis.getRoomSocketList(room_id);
  251. co(mgr_map.notice.pushRemoveChatRoomMuteNotice(room_socket, room_id, member));
  252. };
  253. this.getRoomInfo = function* (room_id) {
  254. let room_info = yield mgr_map.redis.getRoomInfo(room_id);
  255. if (!F.isNull(room_info)) {
  256. room_info.audioChannel = yield mgr_map.redis.getRoomAudioChannel(room_id);
  257. return room_info;
  258. }
  259. let res = yield mgr_map.curl.httpGet(C.java_host, C.java_port, '/room/v3/get', {'roomId': room_id}, null, 'utf8', 'http');
  260. if (res.result) {
  261. let json_res = JSON.parse(res.data);
  262. if (json_res.code != 200) { // 表示业务逻辑报错
  263. F.throwErrCode(100200);
  264. }
  265. room_info = json_res.data;
  266. } else { // 表示http超时或返回非200
  267. F.throwErrCode(100200);
  268. }
  269. room_info.audioChannel = yield mgr_map.redis.getRoomAudioChannel(room_id);
  270. yield mgr_map.redis.setRoomInfo(room_id, room_info);
  271. return room_info;
  272. };
  273. this.createRoomId = function* () {
  274. let incr = yield mgr_map.redis.getNextReqId("room_id"); // 生成下一个房间号
  275. let ranInt = 10 + Math.floor(Math.random() * (99 - 10 + 1));
  276. let room_id = (100000 + incr) * 100 + ranInt;
  277. return room_id;
  278. };
  279. this.syncOnlineNum = function* (room_id, uid, online_num, type) {
  280. F.addDebugLogs(["syncOnlineNum", room_id, uid, online_num, type]);
  281. let room_info = yield mgr_map.room.getRoomInfo(room_id);
  282. if (F.isNull(room_info)) {
  283. F.addDebugLogs(["syncOnlineNum", "/room/online/sync", "空"]);
  284. return;
  285. }
  286. let res = yield mgr_map.curl.httpPost(C.java_host, C.java_port, '/inner/im/v1/receiveRoomOnlineMsg', {
  287. 'roomUid': room_info.uid,
  288. 'uid': uid,
  289. 'onlineNum': online_num,
  290. 'time': new Date().getTime(),
  291. 'type':type
  292. }, null, 'utf8', 'http');
  293. F.addDebugLogs(["syncOnlineNum", "/room/online/sync", res]);
  294. if (!res.result) {
  295. F.addErrLogs("[ 同步房间人数报错 ]", res);
  296. }
  297. };
  298. /**
  299. * 更改声音渠道
  300. * @param audio_channel
  301. * @param room_id
  302. */
  303. this.changeAudioChannel = function* (audio_channel, room_id) {
  304. yield mgr_map.redis.setRoomAudioChannel(audio_channel, room_id);
  305. if (!F.isNull(room_id)) {
  306. yield that.kickOffRoomAllUser(room_id, 3);
  307. return;
  308. }
  309. let roomid_list = yield mgr_map.redis.getRoomIdsByOnlineNum(1);
  310. if (F.isNull(roomid_list)) {
  311. return;
  312. }
  313. for (let i = 0; i < roomid_list.length; i++) {
  314. if (F.isNull(roomid_list[i])) {
  315. continue;
  316. }
  317. co(that.kickOffRoomAllUser(roomid_list[i], 3));
  318. }
  319. };
  320. this.getRoomMemberRole = function* (room_id, uid) {
  321. let room_info = yield mgr_map.room.getRoomInfo(room_id);
  322. if (F.isNull(room_info)) {
  323. F.throwErrCode(100203);
  324. }
  325. let is_creator = room_info.uid == uid;
  326. let is_manager = !F.isNull(yield mgr_map.redis.getRoomManager(room_id, uid));
  327. let is_member = yield mgr_map.validator.isRoomUser(room_id, uid);
  328. let is_blacklist = yield mgr_map.redis.isBlacklist(room_id, uid);
  329. return {
  330. "is_creator": is_creator,
  331. "is_manager": is_manager,
  332. "is_member" : is_member,
  333. "is_blacklist": is_blacklist
  334. }
  335. };
  336. this.kickoffZego = function* (roomid, uid) {
  337. }
  338. };