fashilong.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. var server = require("http").createServer();
  2. const TLSSigAPIv2 = require('tls-sig-api-v2')
  3. const appids = require('./../config/appid')
  4. const api = new TLSSigAPIv2.Api(appids.fashilong.appid, appids.fashilong.key)
  5. const PORT = 3031
  6. const LEADER = 'leader'
  7. function getSig(userId) {
  8. return api.genSig(userId, 86400)
  9. }
  10. const EVENT = {
  11. someOneInRoom: 'someOneInRoom', // 有人进入房间
  12. someOneLeaveRoom: 'someOneLeaveRoom', // 有人离开房间
  13. startCall: 'startCall', // 开始通话
  14. stopCall: 'stopCall', // 结束通话
  15. webSyncAction: 'webSyncAction', // 通知h5的事件
  16. clientSyncAction: 'clientSyncAction', // 通知非H5的事件
  17. action: 'action', // 通知所有连接设备的事件
  18. roomClose: 'roomClose', // 房间已结束/房主已离开
  19. roomIn: 'roomIn', // 通知设备成功进入房间
  20. changeVoiceStatus: 'changeVoiceStatus', // 通知某设备语音状态
  21. changeOnlineStatus: 'changeOnlineStatus', // 通知某设备的在线状态
  22. roomPersonChange: 'roomPersonChange', // 房间人数变化事件
  23. changeRoomEnableTalk: 'changeRoomEnableTalk' // 改变房间是否可通话的配置
  24. }
  25. const CODEMAP = {
  26. 3001: '房间已被解散',
  27. 3002: '房主主动解散'
  28. }
  29. module.exports = class WebSocketServer {
  30. constructor() {
  31. this._pageMap = new Map();
  32. this._roomIDS = new Map();
  33. this._roomPerson = new Map()
  34. this._roomsConfig = {}
  35. }
  36. create() {
  37. this.io = require("socket.io")(server, {
  38. path: "/fsl-node",
  39. serveClient: false,
  40. // below are engine.IO options
  41. pingInterval: 10000,
  42. pingTimeout: 5000,
  43. cookie: false,
  44. });
  45. server.listen(PORT, { origins: "*" });
  46. this.io.on("connection", (socket) => {
  47. let user = socket.handshake.query
  48. const { roomId, userId, sceneNum, isClient, role, userLimitNum, roomType } = user
  49. const webRoomId = `${roomId}_${sceneNum}_web`
  50. const clientRoom = `${userId}${roomId}`
  51. // 加入客户端与H5单独的通讯房间
  52. socket.join(clientRoom, () => {})
  53. socket.on(EVENT.clientSyncAction, (data) => {
  54. console.log(data, 'clientSyncAction')
  55. socket.broadcast.to(clientRoom).emit(EVENT.clientSyncAction, data)
  56. })
  57. socket.on(EVENT.changeVoiceStatus, data => {
  58. let _roomPerson = this._roomPerson.get(roomId) || []
  59. user.voiceStatus = data.status
  60. _roomPerson.forEach(item => {
  61. if (item.userId === user.userId) {
  62. item.voiceStatus = user.voiceStatus
  63. }
  64. })
  65. this._roomPerson.set(roomId, _roomPerson)
  66. socket.broadcast.to(roomId).emit(EVENT.changeVoiceStatus, { roomsPerson: sortRoomUser(_roomPerson) })
  67. })
  68. // 房主,保存房间配置
  69. if (isClient && role === LEADER && !this._roomsConfig[roomId]) {
  70. console.log('in', user)
  71. this._roomsConfig[roomId] = {
  72. userLimitNum,
  73. enableTalk: user.enableTalk
  74. }
  75. }
  76. // 1v1保存房主
  77. if (roomType === '1v1' && !this._roomsConfig[roomId]) {
  78. console.log(roomType, roomId, user)
  79. this._roomsConfig[roomId] = {
  80. leaderId: userId
  81. }
  82. }
  83. if (roomType === '1v1' && sortRoomUser(this._roomPerson.get(roomId)).length > 2) {
  84. setTimeout(() => {
  85. socket.emit('roomInFail', {
  86. type: 'full',
  87. msg: '房间人数已满'
  88. })
  89. }, 1000)
  90. return this
  91. }
  92. socket.on(EVENT.changeRoomEnableTalk, data => {
  93. this._roomsConfig[roomId].enableTalk = data
  94. socket.broadcast.to(roomId).emit(EVENT.changeRoomEnableTalk, this._roomsConfig[roomId])
  95. })
  96. // 若有房间人数限制
  97. if (userLimitNum && this._roomPerson.get(roomId) && sortRoomUser(this._roomPerson.get(roomId)).length >= userLimitNum) {
  98. setTimeout(() => {
  99. socket.emit('roomInFail', { type: 'full', msg: '房间人数已满' })
  100. }, 1000)
  101. return this
  102. }
  103. let is1v1 = false
  104. if (this._roomsConfig[roomId]) {
  105. is1v1 = this._roomsConfig[roomId].leaderId === userId
  106. }
  107. console.log(this._roomsConfig[roomId], userId, !is1v1, user.role !== LEADER, (this._roomPerson.get(roomId) && !this._roomPerson.get(roomId).find(item => item.role === LEADER)))
  108. // 非房主进来房间,判断房间是否存在,以及房间内是否有房主,若无则通知房间已关闭
  109. if (!is1v1 && user.role !== LEADER && ((this._roomPerson.get(roomId) && !this._roomPerson.get(roomId).find(item => item.role === LEADER)) || (!this._roomPerson.get(roomId)))) {
  110. setTimeout(() => {
  111. socket.emit(EVENT.roomClose, { code: 3001, msg: CODEMAP[3001] })
  112. }, 1000)
  113. return this
  114. }
  115. // 加入所有连接数的通讯房间
  116. socket.join(roomId, () => {
  117. // 只有h5才能加入H5端的房间
  118. if (!isClient) {
  119. let roomsPerson = this._roomPerson.get(roomId) || []
  120. if (userId) {
  121. user.sig = getSig(userId)
  122. }
  123. let clientPerson = this._roomPerson.get(clientRoom) || []
  124. clientPerson.forEach(item => {
  125. if (item.userId === user.userId && item.avatar) {
  126. user.avatar = item.avatar
  127. user.voiceStatus = item.voiceStatus
  128. user.onlineStatus = item.onlineStatus
  129. user.nickname = decodeURIComponent(item.nickname)
  130. }
  131. })
  132. roomsPerson.push(user)
  133. this._roomPerson.set(roomId, roomsPerson)
  134. } else {
  135. // 通知客户端的房间配置
  136. let roomsPerson = this._roomPerson.get(roomId) || []
  137. socket.emit(EVENT.roomIn, { user, roomsPerson: sortRoomUser(roomsPerson), roomsConfig: this._roomsConfig[roomId] })
  138. }
  139. })
  140. let clientPerson = this._roomPerson.get(clientRoom) || []
  141. if (isClient) {
  142. clientPerson.push(user)
  143. this._roomPerson.set(clientRoom, clientPerson)
  144. }
  145. if (!isClient) {
  146. socket.join(webRoomId, () => {
  147. // let roomsPerson = this._roomPerson.get(roomId) || []
  148. // socket.broadcast.to(roomId).emit(EVENT.someOneInRoom, { user, roomsPerson: sortRoomUser(roomsPerson) })
  149. })
  150. }
  151. // 开始通话
  152. socket.on(EVENT.startCall, () => {
  153. if (!isClient) {
  154. let roomsPerson = this._roomPerson.get(roomId) || []
  155. // 返回h5房间内的信息
  156. socket.emit(EVENT.roomIn, { user, roomsPerson: sortRoomUser(roomsPerson), roomsConfig: this._roomsConfig[roomId] })
  157. // 判断是否某些情况断线重连
  158. if (!user.isInRoom) {
  159. socket.broadcast.to(roomId).emit(EVENT.someOneInRoom, { user, roomsPerson: sortRoomUser(roomsPerson) })
  160. }
  161. user.isInRoom = true
  162. updateRoomUser(roomsPerson, user)
  163. }
  164. })
  165. socket.on(EVENT.changeOnlineStatus, data => {
  166. user.onlineStatus = data.status
  167. let roomPerson = this._roomPerson.get(roomId)
  168. let __roomPerson = updateRoomUser(roomPerson, user)
  169. let actionName = user.onlineStatus ? 'inRoom' : 'leaveRoom'
  170. socket.broadcast.to(roomId).emit(EVENT.roomPersonChange, { roomsPerson: sortRoomUser(__roomPerson), actionName, user })
  171. })
  172. socket.on(EVENT.stopCall, () => {
  173. socket.leave(roomId)
  174. console.log(role, user, 'stopCall')
  175. if (role === LEADER) {
  176. socket.broadcast.to(roomId).emit(EVENT.roomClose, { code: 3002, msg: CODEMAP[3002] })
  177. delete this._roomsConfig[roomId]
  178. }
  179. let roomsPerson = this._roomPerson.get(roomId) || []
  180. roomsPerson = removeRoomUser(roomsPerson, user)
  181. this._roomPerson.set(roomId, roomsPerson)
  182. socket.broadcast.to(roomId).emit(EVENT.someOneLeaveRoom, { user, roomsPerson: sortRoomUser(roomsPerson) })
  183. user.isInRoom = false
  184. updateRoomUser(roomsPerson, user)
  185. })
  186. socket.on(EVENT.webSyncAction, (data) => {
  187. socket.broadcast.to(webRoomId).emit(EVENT.webSyncAction, data)
  188. })
  189. socket.on(EVENT.action, (data) => {
  190. socket.broadcast.to(roomId).emit(EVENT.action, data)
  191. })
  192. socket.on("disconnect", (reason) => {
  193. socket.leave(roomId)
  194. if (!isClient) {
  195. let roomsPerson = this._roomPerson.get(roomId) || []
  196. roomsPerson = removeRoomUser(roomsPerson, user)
  197. this._roomPerson.set(roomId, roomsPerson)
  198. // socket.broadcast.to(roomId).emit(EVENT.someOneLeaveRoom, { user, roomsPerson })
  199. socket.leave(webRoomId)
  200. socket.leave(roomId)
  201. }
  202. })
  203. socket.on('reconnect', () => {
  204. socket.join(roomId)
  205. if (!isClient) {
  206. let roomsPerson = this._roomPerson.get(roomId) || []
  207. roomsPerson.push(user)
  208. this._roomPerson.set(roomId, roomsPerson)
  209. socket.join(webRoomId)
  210. socket.join(roomId)
  211. }
  212. })
  213. socket.on("error", function(reason) {
  214. console.log("异常关闭", reason)
  215. })
  216. return this;
  217. })
  218. }
  219. close() {
  220. this.server.disconnect(true);
  221. }
  222. };
  223. function removeRoomUser(roomsPerson, user) {
  224. for (let i = 0; i < roomsPerson.length; i++) {
  225. if (roomsPerson[i].userId === user.userId) {
  226. roomsPerson.splice(i, 1)
  227. }
  228. }
  229. return roomsPerson
  230. }
  231. // 过滤房间内相同的人
  232. function sortRoomUser(roomsPerson) {
  233. if (!roomsPerson) return []
  234. const res = new Map()
  235. return roomsPerson.filter((a) => !res.has(a.userId) && res.set(a.userId, 1))
  236. }
  237. function updateRoomUser(roomsPerson, user) {
  238. if (!roomsPerson) return []
  239. roomsPerson.forEach(item => {
  240. if (item.userId === user.userId) {
  241. item = Object.assign(item, user)
  242. }
  243. })
  244. return roomsPerson
  245. }