const network = require('./network') 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" let userCount = 0 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, () => { console.log(user, user.nickname && decodeURIComponent(user.nickname)) }) 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, } } if (roomType === "1v1" && sortRoomUser(this._roomPerson.get(roomId)).length > 2) { setTimeout(() => { socket.emit("roomInFail", { type: "full", msg: "房间人数已满", }) }, 1000) return this } 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], }) } userCount++ console.log("在线人数1:" + userCount) network.autoUpdate(userCount) }) 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) }) let roomPerson = this._roomPerson.get(roomId) let __roomPerson = updateRoomUser(roomPerson, user) let actionName = "" socket.broadcast .to(roomId) .emit(EVENT.roomPersonChange, { roomsPerson: sortRoomUser(__roomPerson), actionName, user, }) }) } // 开始通话 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) } userCount-- console.log("在线人数2:" + userCount) network.autoUpdate(userCount) }) 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) } console.log("重连") }) 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 }