You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
255 lines
6.7 KiB
JavaScript
255 lines
6.7 KiB
JavaScript
5 years ago
|
// Create dictionaries for tracking hosts, clients, and rooms
|
||
|
let hosts = {};
|
||
|
let clients = {};
|
||
|
let rooms = {};
|
||
|
|
||
|
////////////
|
||
|
// Required for secure server
|
||
|
const fs = require('fs');
|
||
|
|
||
|
const options = {
|
||
|
key: fs.readFileSync('key.pem'),
|
||
|
cert: fs.readFileSync('cert.pem')
|
||
|
};
|
||
|
|
||
|
// Setup express web server and listen on port 3000
|
||
|
let express = require('express');
|
||
|
let app = express();
|
||
|
let port = Number(process.env.PORT || 3000);
|
||
|
let server = require('https').createServer(options, app);
|
||
|
server.listen(port);
|
||
|
|
||
|
app.use(express.static('public'));
|
||
|
console.log("My socket server is running on port " + port);
|
||
|
|
||
|
////////////
|
||
|
// Start socket.io
|
||
|
let socket = require('socket.io');
|
||
|
|
||
|
// Connect it to the web server
|
||
|
let io = socket(server);
|
||
|
|
||
|
////////////
|
||
|
// Setup a connection
|
||
|
io.sockets.on('connection', newConnection);
|
||
|
function newConnection(socket) {
|
||
|
|
||
|
// Inform incoming connection of its ID
|
||
|
console.log('\n' + socket.id + ' is attempting connection...');
|
||
|
socket.emit('id', socket.id);
|
||
|
|
||
|
socket.on('test', function (data) {
|
||
|
console.log('TEST');
|
||
|
});
|
||
|
|
||
|
// Process a request to join.
|
||
|
socket.on('join', function (data) {
|
||
|
|
||
|
// If request is from a client...
|
||
|
if (data.name == 'client') {
|
||
|
|
||
|
console.log("Verifying client...");
|
||
|
|
||
|
// If the roomId field is not null
|
||
|
if (data.roomId != null) {
|
||
|
|
||
|
// Search existing roomIds for a match
|
||
|
console.log("Searching for existing room ID...");
|
||
|
if (rooms[data.roomId] != null) {
|
||
|
|
||
|
// Add client to room with all connected clients
|
||
|
socket.join(data.name);
|
||
|
|
||
|
// Add client and corresponding data to clients dictionary
|
||
|
// by socket ID
|
||
|
clients[socket.id] = {
|
||
|
type: data.name,
|
||
|
roomId: data.roomId
|
||
|
}
|
||
|
|
||
|
// Add client to its own room and to host room by room ID
|
||
|
socket.join([socket.id, data.roomId]);
|
||
|
console.log('Client added to room '+data.roomId+'.\tNumber of clients: ' + Object.keys(clients).length);
|
||
|
|
||
|
// Send match confirmation back to client
|
||
|
socket.emit("found", {status: true});
|
||
|
}
|
||
|
else {
|
||
|
// Notify client of failure to match
|
||
|
socket.emit("found", {status: false});
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (data.name == 'host') {
|
||
|
// If the attempted connection is from a host...
|
||
|
|
||
|
// Store a transmitted room ID if it exists, otherwise
|
||
|
// generate a random gemstone name as room ID.
|
||
|
let roomId = null;
|
||
|
if (data.roomId === null || data.roomId === 'undefined') {
|
||
|
roomId = makeIdFromList();
|
||
|
}
|
||
|
else {
|
||
|
roomId = data.roomId;
|
||
|
}
|
||
|
|
||
|
// Add client and corresponding data to devices dictionary
|
||
|
// by socket ID
|
||
|
let hostData = {
|
||
|
type: data.name,
|
||
|
roomId: roomId
|
||
|
};
|
||
|
|
||
|
hosts[socket.id] = hostData;
|
||
|
rooms[roomId] = socket.id;
|
||
|
|
||
|
// Add host to "host" room, its own room by room ID, and to a room
|
||
|
// with its clients by room ID.
|
||
|
socket.join([data.name, 'host:'+hostData.roomId, hostData.roomId]);
|
||
|
|
||
|
// Send clients room ID back to host
|
||
|
socket.emit("hostConnect", hostData);
|
||
|
|
||
|
console.log('Host added with room ID of ' + hostData.roomId + '.\tNumber of hosts: ' + Object.keys(hosts).length);
|
||
|
}
|
||
|
else {
|
||
|
console.log('warning: data type not recognized.')
|
||
|
}
|
||
|
})
|
||
|
|
||
|
//// Process device disconnects.
|
||
|
socket.on('disconnect', function () {
|
||
|
console.log('\n' + socket.id + ' has been disconnected!');
|
||
|
|
||
|
if (clients[socket.id] != null) {
|
||
|
// If the device is a client, delete it
|
||
|
delete clients[socket.id];
|
||
|
console.log('Client removed.\tNumber of clients: ' + Object.keys(clients).length);
|
||
|
|
||
|
// Notify hosts that client has disconnected.
|
||
|
socket.in('host').emit('clientDisconnect', {id: socket.id});
|
||
|
}
|
||
|
else if (hosts[socket.id] != null) {
|
||
|
// If the device is a host, delete it
|
||
|
let roomId = hosts[socket.id].roomId;
|
||
|
delete hosts[socket.id];
|
||
|
console.log('Host with ID ' + roomId + ' removed.\tHumber of hosts: ' + Object.keys(hosts).length);
|
||
|
|
||
|
// Remove corresponding room
|
||
|
let key = getKeyByValue(rooms, socket.id);
|
||
|
if (key != null) {
|
||
|
delete rooms[key];
|
||
|
}
|
||
|
|
||
|
// TODO: add handling for all clients connected to host when host
|
||
|
// is disconnected.
|
||
|
}
|
||
|
})
|
||
|
|
||
|
//// Process client connects.
|
||
|
socket.on('clientConnect', onClientConnect);
|
||
|
|
||
|
function onClientConnect(data) {
|
||
|
if (rooms[data.roomId] != null) {
|
||
|
console.log('clientConnect message received from ' + socket.id + ' for room ' + data.roomId + ".");
|
||
|
socket.in('host:'+data.roomId).emit('clientConnect', {id: socket.id, roomId: data.roomId});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//// Reroute data sent between clients and hosts
|
||
|
socket.on('sendData', sendData);
|
||
|
|
||
|
function sendData(data) {
|
||
|
let packet = {...data};
|
||
|
packet.id = socket.id;
|
||
|
|
||
|
// If room ID is valid...
|
||
|
if (rooms[data.roomId] != null) {
|
||
|
if (clients[socket.id] != null) {
|
||
|
// And if device is a client, send to corresponding host
|
||
|
socket.in('host:'+data.roomId).emit('receiveData', packet);
|
||
|
}
|
||
|
else if (hosts[socket.id] != null) {
|
||
|
// And if device is a host, send to corresponding clients
|
||
|
socket.broadcast.in(data.roomId).emit('receiveData', packet);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////
|
||
|
// Utility Functions
|
||
|
function searchRoomId(roomId_, array_) {
|
||
|
for (let i = 0; i < array_.length; i++) {
|
||
|
if (array_[i].roomId == roomId_) {
|
||
|
return {
|
||
|
item: array_[i],
|
||
|
index: i
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function getKeyByValue(object, value) {
|
||
|
return Object.keys(object).find(key => object[key] === value);
|
||
|
}
|
||
|
|
||
|
////////////
|
||
|
// Gemstone room ID generator
|
||
|
const roomNames =
|
||
|
["agate",
|
||
|
"amber",
|
||
|
"amethyst",
|
||
|
"barite",
|
||
|
"beryl",
|
||
|
"bloodstone",
|
||
|
"coral",
|
||
|
"crystal",
|
||
|
"diamond",
|
||
|
"emerald",
|
||
|
"fluorite",
|
||
|
"garnet",
|
||
|
"goldstone",
|
||
|
"jade",
|
||
|
"jasper",
|
||
|
"moonstone",
|
||
|
"onyx",
|
||
|
"opal",
|
||
|
"pearl",
|
||
|
"peridot",
|
||
|
"quahog",
|
||
|
"quartz",
|
||
|
"ruby",
|
||
|
"sapphire",
|
||
|
"sardonyx",
|
||
|
"sunstone",
|
||
|
"tigereye",
|
||
|
"topaz",
|
||
|
"turquoise",
|
||
|
"zircon"]
|
||
|
|
||
|
const roomIds = randomNoRepeats(roomNames);
|
||
|
|
||
|
function randomNoRepeats(array) {
|
||
|
let copy = array.slice(0);
|
||
|
return function() {
|
||
|
if (copy.length < 1) { copy = array.slice(0); }
|
||
|
let index = Math.floor(Math.random() * copy.length);
|
||
|
let item = copy[index];
|
||
|
copy.splice(index, 1);
|
||
|
return {id: item, length: copy.length};
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function makeIdFromList() {
|
||
|
for (let i = 0; i < roomNames.length; i++) {
|
||
|
let text = roomIds().id;
|
||
|
let room = searchRoomId(text, hosts);
|
||
|
if (room == null) {
|
||
|
return text;
|
||
|
}
|
||
|
}
|
||
|
console.log(hosts.length + " hosts detected. No names available.");
|
||
|
return null;
|
||
|
}
|