var WebSocketServer = require('websocket').server; var http = require('http'); var fs = require('fs'); var people = {}; var connectionDict = {}; var rooms = {}; var numberOfConnections = 0; var roster = {}; var settings = { websocketPort: 1337, refreshRate : 5000, autoCall : true, acceptNewUsers : false } fs.readFile(process.argv[2] || './settings.json', function(err, data) { if (err) { console.log('No settings.json found ('+err+'). Using default settings'); } else { settings = JSON.parse(data.toString('utf8', 0, data.length)); } console.log(settings); }); fs.readFile('data/people.json', 'utf8', function (err, data) { if (err) throw err; var obj = JSON.parse(data.toString('utf8', 0, data.length)); roster.people = obj; for(var i=0; i< obj.length; i ++){ people[obj[i].id] = 'off'; }; console.log('Loaded ' + obj.length + ' people from people.json file'); }); fs.readFile('data/rooms.json', 'utf8', function (err, data) { if (err) throw err; var obj = JSON.parse(data.toString('utf8', 0, data.length)); roster.rooms = obj; console.log('Loaded ' + obj.length + ' rooms from rooms.json file'); }); var server = http.createServer(function(request, response) { // process HTTP request. Since we're writing just WebSockets serve we don't have to implement anything. }).listen(settings.websocketPort, function() { console.log('Socket server is listening on port ' + settings.websocketPort); }); wsServer = new WebSocketServer({ httpServer: server }); setInterval(sendPresence, settings.refreshRate); // This callback function is called every time someone tries to connect to the WebSocket server // if the type of message is presence, it will send the broadcast. If the type is room, it will send the offer type as multicast, // if from and to field are defined, and connection.name that maches to exists, it will send the unicast. // Otherwise, it will send the broadcast. wsServer.on('request', function(request) { numberOfConnections ++; console.log('Connection from origin ' + request.origin); var connection = request.accept(null, request.origin); console.log('Connection address ' + connection.remoteAddress); console.log('Number of connections ' + numberOfConnections); connection.on('message', function(message) { if (message.type === 'utf8') { // process WebSocket message console.log('Received Message ' + message.utf8Data); //parse the message msg = JSON.parse(message.utf8Data); var type = msg.type; var from = msg.from; var to = msg.to; var name; //accept only messages that are authorized, in simple case, we assume that the //first call is the presence with a name of the caller if(type !== 'presence' && connection.name === undefined){ console.log('connection not allowed, name not provided'); return; } //after presence message, socket connection is 'named', only such connections participate later. if(type === 'presence'){ name = msg.name; if(people[name] === undefined && !settings.acceptNewUsers){ console.log('Unknown user not allowed'); return; } var status = msg.status; if(status === 'on'){ connection.name = name; connectionDict[name] = connection; console.log('adding '+ name) people[name] = 'on'; if(settings.sendRoster){ connection.send(JSON.stringify({type: "roster", people: roster.people, rooms: roster.rooms})); } } else { remove(name); } } else if(type === 'room'){ if(rooms[to] === undefined) rooms[to] = []; console.log('Number of people in the room ' + rooms[to].length); console.log('Sending multicast from ' + from + ": to room "+ to); if(settings.autoCall){ for(var i = 0; i < rooms[to].length; i ++){ var x = rooms[to][i]; if(connectionDict[x] !== undefined){ console.log('Sending offer from ' + from + ": to "+ x); sendOffer(connectionDict[x], from, x); } } } if(rooms[to].indexOf(from) < 0) rooms[to].push(from); return; } else if(to !== undefined && from !== undefined){ if(connectionDict[to] !== undefined && people[to] !== 'off'){ console.log('Sending unicast from ' + from + ":"+ to); connectionDict[to].send(message.utf8Data, sendCallback); } } else { console.log("message couldn't be passed to " + to); } return; } console.log('Sending broadcast from '+ from); // broadcast message to all clients that have name attached for(var client in connectionDict){ if(client !== name){ console.log('Sending data to '+ client); connectionDict[client].send(message.utf8Data, sendCallback); } } }); connection.on('close', function(conn) { console.log('Peer disconnected.'); numberOfConnections --; remove(connection.name); }); }); function sendOffer(connection, _from, _to){ connection.send(JSON.stringify({type: 's-offer', from: _from, to: _to}), sendCallback); } function sendPresence(){ for(var _name in people){ for(var client in connectionDict){ if(people[_name] === 'off'){ console.log('Person '+ _name + '[off] -> ' + client); connectionDict[client].send(JSON.stringify({type: 'presence', name: _name, status: 'off'}), sendCallback); } else if(people[_name] === 'on'){ console.log('Person '+ _name + '[on] -> ' + client); connectionDict[client].send(JSON.stringify({type: 'presence', name: _name, status: 'on'}), sendCallback); } } } for(var room in rooms){ for(var i = 0; i < rooms[room].length; i ++){ var client = rooms[room][i]; if(connectionDict[client] !== undefined){ console.log('Room '+ room + ' -> ' + client); connectionDict[client].send(JSON.stringify({type: 'presence', name: room, status: 'on', room: true}), sendCallback); } } } } function remove(name){ if(name !== undefined && name !== null){ console.log('removing '+ name); people[name] = 'off'; delete connectionDict[name]; } } function sendCallback(err) { if (err){ console.error("send() error: " + err); } }