ChatRooms/index.js

180 lines
4.6 KiB
JavaScript

// Global logging toggles
// const fileLogging = false;
const consoleLogging = true;
// Imports
// const fs = require('fs');
const http = require('http');
const express = require('express');
// Global server setup
const app = express();
const clientPath = __dirname+'/../html';
console.log('Serving static from ' + clientPath);
app.use(express.json());
app.use(express.static(clientPath));
const server = http.createServer(app);
// Check if string is already in array
function isStringUnique(arr, str) {
let match = true;
for (const s of arr)
if (s === str) {
match = false;
break;
}
return match;
}
// Generate the partial ID after username
function generatePartialID() {
return Math.floor(Math.random()*10000).toString().padStart(4, '0');
}
// User data
const users = [];
// Incoming user connection
app.post('/connect', (req, res) => {
// Generate id, save user
const { name } = req.body;
let id = generatePartialID();
const name_id = users.map(u => `${u.name}#${u.id}`);
while (!isStringUnique(name_id, `${name}#${id}`))
id = generatePartialID();
users.push({
socket: req.socket,
date: new Date(),
chats: {},
name,
id
});
// Log connection, send back id
if (consoleLogging)
console.log(`User with ID '${name}#${id}' connected.`);
res.status(200).json({ id });
});
// User has disconnected
app.post('/disconnect', (req, res) => {
const { name, id } = req.body;
for (let i = 0; i < users.length; i++)
if (users[i].name === name && users[i].id === id) {
// If id is valid, delete all user data
if (consoleLogging)
console.log(`User with ID '${name}#${id}' disconnected.`);
users.splice(i, 1);
break;
}
// Confirm disconnect
res.status(200).send();
});
// User wants to measure ping
app.get('/ping', (req, res) => {
res.status(200).send();
});
// User wants to change name
app.post('/nickname', (req, res) => {
const { oldName, name, id } = req.body;
// Check if name is taken, if not, append id until unique
const name_id = users.map(u => `${u.name}#${u.id}`);
let currentID = id;
while (!isStringUnique(name_id, `${name}#${currentID}`))
currentID = generatePartialID();
// Change username
for (const u of users)
if (u.name === oldName && u.id === id) {
if (consoleLogging)
console.log(`(Re-)named user with ID '${oldName}#${id}'.`);
u.name = name;
u.id = currentID;
break;
}
// Confirm renaming
res.status(200).json({ id: currentID });
});
// User is pulling messages
app.post('/getChat', (req, res) => {
const { name, id } = req.body;
// Go through users' chats, retrieve messages, save by username
let chats = {};
const fullName = `${name}#${id}`;
for (const u of users)
if (fullName in u.chats) {
const len = u.chats[fullName].length;
if (len > 0)
chats[`${u.name}#${u.id}`] = u.chats[fullName].splice(0, len);
}
// No chat messages were found
if (Object.keys(chats).length === 0) {
res.status(204).send();
return;
}
// Log if messages were delivered
if (consoleLogging)
console.log(`Delivered messages to user with ID '${fullName}'.`);
// Send back data
res.status(200).json(chats);
});
// User sent new message
app.post('/message', (req, res) => {
const { name, id, recipient, message } = req.body;
// Search for senders' name, save message
for (const u of users)
if (u.name === name && u.id === id) {
if (!u.chats[recipient])
u.chats[recipient] = [];
u.chats[recipient].push(message);
break;
}
// Log message for debugging
if (consoleLogging)
console.log(`User '${name}#${id}' sent message '${message}'.`);
// Confirm process
res.status(200).send();
});
// User requesting all names
app.get('/getNames', (req, res) => {
if (consoleLogging)
console.log('Some user requested all names.');
res.status(200).json(users.map(u => {
return {
name: u.name,
id: u.id
};
}));
});
// Internal server error
server.on('error', err => {
console.error('Internal server error', err);
});
// Server has closed
server.on('close', () => {
console.log('Shutting down server ...');
});
// Listen on port 3000 for webserver connection
server.listen(3000, () => {
console.log('Server running on port 3000');
});