var server = require("http").createServer(); const TLSSigAPIv2 = require('tls-sig-api-v2') const appids = require('./../config/appid') const api = new TLSSigAPIv2.Api(appids.fashilong.appid, appids.fashilong.key) const PORT = 3031 const LEADER = 'leader' function getSig(userId) { return api.genSig(userId, 86400) } const EVENT = { someOneInRoom: 'someOneInRoom', // 有人进入房间 someOneLeaveRoom: 'someOneLeaveRoom', // 有人离开房间 startCall: 'startCall', // 开始通话 stopCall: 'stopCall', // 结束通话 webSyncAction: 'webSyncAction', // 通知h5的事件 clientSyncAction: 'clientSyncAction', // 通知非H5的事件 action: 'action', // 通知所有连接设备的事件 roomClose: 'roomClose', // 房间已结束/房主已离开 roomIn: 'roomIn', // 通知设备成功进入房间 changeVoiceStatus: 'changeVoiceStatus', // 通知某设备语音状态 changeOnlineStatus: 'changeOnlineStatus', // 通知某设备的在线状态 roomPersonChange: 'roomPersonChange', // 房间人数变化事件 changeRoomEnableTalk: 'changeRoomEnableTalk' // 改变房间是否可通话的配置 } const CODEMAP = { 3001: '房间已被解散', 3002: '房主主动解散' } module.exports = class WebSocketServer { constructor() { this._pageMap = new Map(); this._roomIDS = new Map(); this._roomPerson = new Map() this._roomsConfig = {} } create() { this.io = require("socket.io")(server, { path: "/fsl-node", serveClient: false, // below are engine.IO options pingInterval: 10000, pingTimeout: 5000, cookie: false, }); server.listen(PORT, { origins: "*" }); this.io.on("connection", (socket) => { let user = socket.handshake.query const { roomId, userId, sceneNum, isClient, role, userLimitNum, roomType } = user const webRoomId = `${roomId}_${sceneNum}_web` const clientRoom = `${userId}${roomId}` // 加入客户端与H5单独的通讯房间 socket.join(clientRoom, () => {}) socket.on(EVENT.clientSyncAction, (data) => { console.log(data, 'clientSyncAction') socket.broadcast.to(clientRoom).emit(EVENT.clientSyncAction, data) }) socket.on(EVENT.changeVoiceStatus, data => { let _roomPerson = this._roomPerson.get(roomId) || [] user.voiceStatus = data.status _roomPerson.forEach(item => { if (item.userId === user.userId) { item.voiceStatus = user.voiceStatus } }) this._roomPerson.set(roomId, _roomPerson) socket.broadcast.to(roomId).emit(EVENT.changeVoiceStatus, { roomsPerson: sortRoomUser(_roomPerson) }) }) // 房主,保存房间配置 if (isClient && role === LEADER && !this._roomsConfig[roomId]) { console.log('in', user) this._roomsConfig[roomId] = { userLimitNum, enableTalk: user.enableTalk } } // 1v1保存房主 if (roomType === '1v1' && !this._roomsConfig[roomId]) { console.log(roomType, roomId, user) this._roomsConfig[roomId] = { leaderId: userId } } socket.on(EVENT.changeRoomEnableTalk, data => { this._roomsConfig[roomId].enableTalk = data socket.broadcast.to(roomId).emit(EVENT.changeRoomEnableTalk, this._roomsConfig[roomId]) }) // 若有房间人数限制 if (userLimitNum && this._roomPerson.get(roomId) && sortRoomUser(this._roomPerson.get(roomId)).length >= userLimitNum) { setTimeout(() => { socket.emit('roomInFail', { type: 'full', msg: '房间人数已满' }) }, 1000) return this } let is1v1 = false if (this._roomsConfig[roomId]) { is1v1 = this._roomsConfig[roomId].leaderId === userId } console.log(this._roomsConfig[roomId], userId, !is1v1, user.role !== LEADER, (this._roomPerson.get(roomId) && !this._roomPerson.get(roomId).find(item => item.role === LEADER))) // 非房主进来房间,判断房间是否存在,以及房间内是否有房主,若无则通知房间已关闭 if (!is1v1 && user.role !== LEADER && ((this._roomPerson.get(roomId) && !this._roomPerson.get(roomId).find(item => item.role === LEADER)) || (!this._roomPerson.get(roomId)))) { setTimeout(() => { socket.emit(EVENT.roomClose, { code: 3001, msg: CODEMAP[3001] }) }, 1000) return this } // 加入所有连接数的通讯房间 socket.join(roomId, () => { // 只有h5才能加入H5端的房间 if (!isClient) { let roomsPerson = this._roomPerson.get(roomId) || [] if (userId) { user.sig = getSig(userId) } let clientPerson = this._roomPerson.get(clientRoom) || [] clientPerson.forEach(item => { if (item.userId === user.userId && item.avatar) { user.avatar = item.avatar user.voiceStatus = item.voiceStatus user.onlineStatus = item.onlineStatus user.nickname = decodeURIComponent(item.nickname) } }) roomsPerson.push(user) this._roomPerson.set(roomId, roomsPerson) } else { // 通知客户端的房间配置 let roomsPerson = this._roomPerson.get(roomId) || [] socket.emit(EVENT.roomIn, { user, roomsPerson: sortRoomUser(roomsPerson), roomsConfig: this._roomsConfig[roomId] }) } }) let clientPerson = this._roomPerson.get(clientRoom) || [] if (isClient) { clientPerson.push(user) this._roomPerson.set(clientRoom, clientPerson) } if (!isClient) { socket.join(webRoomId, () => { // let roomsPerson = this._roomPerson.get(roomId) || [] // socket.broadcast.to(roomId).emit(EVENT.someOneInRoom, { user, roomsPerson: sortRoomUser(roomsPerson) }) }) } // 开始通话 socket.on(EVENT.startCall, () => { if (!isClient) { let roomsPerson = this._roomPerson.get(roomId) || [] // 返回h5房间内的信息 socket.emit(EVENT.roomIn, { user, roomsPerson: sortRoomUser(roomsPerson), roomsConfig: this._roomsConfig[roomId] }) // 判断是否某些情况断线重连 if (!user.isInRoom) { socket.broadcast.to(roomId).emit(EVENT.someOneInRoom, { user, roomsPerson: sortRoomUser(roomsPerson) }) } user.isInRoom = true updateRoomUser(roomsPerson, user) } }) socket.on(EVENT.changeOnlineStatus, data => { user.onlineStatus = data.status let roomPerson = this._roomPerson.get(roomId) let __roomPerson = updateRoomUser(roomPerson, user) let actionName = user.onlineStatus ? 'inRoom' : 'leaveRoom' socket.broadcast.to(roomId).emit(EVENT.roomPersonChange, { roomsPerson: sortRoomUser(__roomPerson), actionName, user }) }) socket.on(EVENT.stopCall, () => { socket.leave(roomId) console.log(role, user, 'stopCall') if (role === LEADER) { socket.broadcast.to(roomId).emit(EVENT.roomClose, { code: 3002, msg: CODEMAP[3002] }) delete this._roomsConfig[roomId] } let roomsPerson = this._roomPerson.get(roomId) || [] roomsPerson = removeRoomUser(roomsPerson, user) this._roomPerson.set(roomId, roomsPerson) socket.broadcast.to(roomId).emit(EVENT.someOneLeaveRoom, { user, roomsPerson: sortRoomUser(roomsPerson) }) user.isInRoom = false updateRoomUser(roomsPerson, user) }) socket.on(EVENT.webSyncAction, (data) => { socket.broadcast.to(webRoomId).emit(EVENT.webSyncAction, data) }) socket.on(EVENT.action, (data) => { socket.broadcast.to(roomId).emit(EVENT.action, data) }) socket.on("disconnect", (reason) => { socket.leave(roomId) if (!isClient) { let roomsPerson = this._roomPerson.get(roomId) || [] roomsPerson = removeRoomUser(roomsPerson, user) this._roomPerson.set(roomId, roomsPerson) // socket.broadcast.to(roomId).emit(EVENT.someOneLeaveRoom, { user, roomsPerson }) socket.leave(webRoomId) socket.leave(roomId) } }) socket.on('reconnect', () => { socket.join(roomId) if (!isClient) { let roomsPerson = this._roomPerson.get(roomId) || [] roomsPerson.push(user) this._roomPerson.set(roomId, roomsPerson) socket.join(webRoomId) socket.join(roomId) } }) socket.on("error", function(reason) { console.log("异常关闭", reason) }) return this; }) } close() { this.server.disconnect(true); } }; function removeRoomUser(roomsPerson, user) { for (let i = 0; i < roomsPerson.length; i++) { if (roomsPerson[i].userId === user.userId) { roomsPerson.splice(i, 1) } } return roomsPerson } // 过滤房间内相同的人 function sortRoomUser(roomsPerson) { if (!roomsPerson) return [] const res = new Map() return roomsPerson.filter((a) => !res.has(a.userId) && res.set(a.userId, 1)) } function updateRoomUser(roomsPerson, user) { if (!roomsPerson) return [] roomsPerson.forEach(item => { if (item.userId === user.userId) { item = Object.assign(item, user) } }) return roomsPerson }