let WebSocketServer = require('ws').Server; let UUID = require('node-uuid'); let http = require('http'); let events = require('events'); let util = require('util'); let errorCb = function (rtc) { return function (error) { if (error) { rtc.emit("error", error); } }; }; function SkyRTC() { this.sockets = []; this.rooms = {}; // 加入房间 this.on('__join', function (data, socket) { let ids = [], i, m, room = data.room || "__default", curSocket, curRoom, curHost; console.log("房间" + room + "里有" + this.sockets.length + "人"); var socket_index = this.sockets.indexOf(socket) this.sockets[socket_index].role = data.role ? data.role : "host"; socket.role = data.role ? data.role : "host"; curRoom = this.rooms[room] = this.rooms[room] || []; var guestCount = 0; for (i = 0, m = curRoom.length; i < m; i++) { curSocket = curRoom[i]; if (curSocket.role === "guest") { guestCount = guestCount + 1; } } console.log("guestCount = " + guestCount); if (guestCount >= 3 && data.role === "guest") { socket.send(JSON.stringify({ "eventName": "_peers", "data": { "connections": [], "you": socket.id, "yourole": data.role ? data.role : "host", "code":-1, "message":"通话人数已达上限,无法加入", "host":'' } }), errorCb); socket.close(); return; } for (i = 0, m = curRoom.length; i < m; i++) { curSocket = curRoom[i]; if (curSocket.id === socket.id) { curSocket.role = data.role ? data.role : "host"; continue; } ids.push(curSocket.id); curSocket.send(JSON.stringify({ "eventName": "_new_peer", "data": { "socketId": socket.id, "role" : data.role ? data.role : "host" } }), errorCb); if (curSocket.role === "host") { curHost = curSocket.id; } } curRoom.push(socket); socket.room = room; if (socket.role === "host") { curHost = socket.id; } socket.send(JSON.stringify({ "eventName": "_peers", "data": { "connections": ids, "you": socket.id, "yourole": data.role ? data.role : "host", "code":0, "message":"成功", "host":curHost } }), errorCb); this.emit('new_peer', socket, room); //console.log(this.sockets); if (socket.role === "host") { // 通知后台,梯屏已进入房间 const options = { // hostname: 'elevator.inspuriit.com', hostname: '127.0.0.1', // port: 80, port: 8081, path: '/admin/joinroom/callback/' + room, method: 'GET', }; const req = http.request(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { console.log(data); }); }); req.end(); } }); this.on('__ice_candidate', function (data, socket) { var soc = this.getSocket(data.socketId); if (soc) { soc.send(JSON.stringify({ "eventName": "_ice_candidate", "data": { "id": data.id, "label": data.label, "sdpMLineIndex" :data.label, "candidate": data.candidate, "socketId": socket.id } }), errorCb); this.emit('ice_candidate', socket, data); } }); this.on('__offer', function (data, socket) { var soc = this.getSocket(data.socketId); if (soc) { soc.send(JSON.stringify({ "eventName": "_offer", "data": { "sdp": data.sdp, "socketId": socket.id } }), errorCb); } this.emit('offer', socket, data); }); this.on('__answer', function (data, socket) { var soc = this.getSocket(data.socketId); if (soc) { soc.send(JSON.stringify({ "eventName": "_answer", "data": { "sdp": data.sdp, "socketId": socket.id } }), errorCb); this.emit('answer', socket, data); } }); // 发起邀请 this.on('__invite', function (data) { }); // 回应数据 this.on('__ack', function (data) { }); // 状态变更--废弃 this.on('__status_update', function (data, socket) { let ids = [], i, m, room = data.room || "__default", curSocket, curRoom, curHost; console.log("__status_update,房间" + room + "里有" + this.sockets.length + "人"); curRoom = this.rooms[room] = this.rooms[room] || []; for (i = 0, m = curRoom.length; i < m; i++) { curSocket = curRoom[i]; if (curSocket.id === socket.id) { continue; } curSocket.send(JSON.stringify({ "eventName": "__status_update", "data": data }), errorCb); } }); this.on('__state_response', function (data, socket) { let ids = [], i, m, room = data.room || "__default", curSocket, curRoom, curHost; console.log("__state_response,房间" + room + "里有" + this.sockets.length + "人"); curRoom = this.rooms[room] = this.rooms[room] || []; for (i = 0, m = curRoom.length; i < m; i++) { curSocket = curRoom[i]; if (curSocket.id === data.to) { curSocket.send(JSON.stringify({ "eventName": "__state_response", "data": data }), errorCb); } } //this.emit('new_peer', socket, room); }); // 状态变更--废弃结束 this.on('__heartbeat', function (data, socket) { socket.send(JSON.stringify({ "eventName": "__heartbeat", "data": data }), errorCb); }); this.on('__state', function (data, socket) { let ids = [], i, m, room = socket.room || "__default", curSocket, curRoom, curHost; console.log("__state," + room + "里有" + this.sockets.length + "人"); curRoom = this.rooms[room] = this.rooms[room] || []; for (i = 0, m = curRoom.length; i < m; i++) { curSocket = curRoom[i]; if (curSocket.id === socket.id) { continue; } console.log("data.to=" + data.to); if (!data.to || data.to === curSocket.id) { curSocket.send(JSON.stringify({ "eventName": "__state", "data": data }), errorCb); } } }); } util.inherits(SkyRTC, events.EventEmitter); SkyRTC.prototype.addSocket = function (socket) { this.sockets.push(socket); }; SkyRTC.prototype.removeSocket = function (socket) { var i = this.sockets.indexOf(socket), room = socket.room; this.sockets.splice(i, 1); if (room) { i = this.rooms[room].indexOf(socket); this.rooms[room].splice(i, 1); if (this.rooms[room].length === 0) { delete this.rooms[room]; } if (socket.role === "host") { // 通知后台,梯屏已退出房间 const options = { // hostname: 'elevator.inspuriit.com', hostname: '127.0.0.1', // port: 80, port: 8081, path: '/admin/exitroom/callback/' + room, method: 'GET', }; const req = http.request(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { console.log(data); }); }); req.end(); } } }; SkyRTC.prototype.broadcast = function (data, errorCb) { var i; for (i = this.sockets.length; i--;) { this.sockets[i].send(data, errorCb); } }; SkyRTC.prototype.broadcastInRoom = function (room, data, errorCb) { var curRoom = this.rooms[room], i; if (curRoom) { for (i = curRoom.length; i--;) { curRoom[i].send(data, errorCb); } } }; SkyRTC.prototype.getRooms = function () { let rooms = [], room; for (room in this.rooms) rooms.push(room); return rooms; }; SkyRTC.prototype.getSocket = function (socketId) { let i, curSocket; if (!this.sockets) { return; } for (i = this.sockets.length; i--;) { curSocket = this.sockets[i]; if (socketId === curSocket.id) { return curSocket; } } }; function noop() {} function heartbeat() { console.log('heartbeat, socketid=' + this.id) this.isAlive = true; } SkyRTC.prototype.init = function (socket) { let that = this; socket.id = UUID.v4(); socket.isAlive = true; socket.on('pong', heartbeat); const interval = setInterval(function ping() { if (socket.isAlive === false) { console.log('timeout, socketid=' + socket.id) return socket.close(); } socket.isAlive = false; socket.ping(noop); }, 10000); // console.log(socket); that.addSocket(socket); //为新连接绑定事件处理器 socket.on('message', function (data) { console.log(data); let json = JSON.parse(data); if (json.eventName) { that.emit(json.eventName, json.data, socket); } else { that.emit("socket_message", socket, data); } }); //连接关闭后从SkyRTC实例中移除连接,并通知其他连接 socket.on('close', function () { clearInterval(interval); let i, m, room = socket.room, curRoom; if (room) { curRoom = that.rooms[room]; for (i = curRoom.length; i--;) { if (curRoom[i].id === socket.id) { continue; } curRoom[i].send(JSON.stringify({ "eventName": "_remove_peer", "data": { "socketId": socket.id, "role": socket.role } }), errorCb); console.log("发送到" + curRoom[i].id + " -> " + JSON.stringify({ "eventName": "_remove_peer", "data": { "socketId": socket.id, "role": socket.role } })); } } that.removeSocket(socket); that.emit('remove_peer', socket.id, that); console.log("房间" + room + "里还剩下" + that.sockets.length + "人"); }); that.emit('new_connect', socket); }; module.exports.listen = function (server) { let SkyRTCServer; if (typeof server === 'number') { SkyRTCServer = new WebSocketServer({ port: server }); } else { SkyRTCServer = new WebSocketServer({ server: server }); } SkyRTCServer.rtc = new SkyRTC(); errorCb = errorCb(SkyRTCServer.rtc); SkyRTCServer.on('connection', function (socket) { this.rtc.init(socket); }); return SkyRTCServer; };