const app = require('express')(); const http = require('http').Server(app); const io = require('socket.io')(http); const convert = require('color-convert'); function randint(min, max) { return min + Math.floor(Math.random() * (max - min)); } function randomColor() { return '#' + convert.hsl.hex([randint(0, 256), randint(50, 200), randint(150, 256)]); } function usernameTaken(list, username) { return Object.values(list).filter(m => m.name.toLowerCase() === username.toLowerCase()).length > 0; } function escapeHtml(unsafe) { return unsafe .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function connectUser(list, socket) { const iid = randint(0, 9999999); const u = { name: 'anonymous#' + ('0000' + randint(0, 9999)).slice(-4), color: randomColor() }; list[iid] = u; console.log(u.name + ' connected'); socket.emit('chat message', { color: '#fff', name: '', text: 'Welcome to the server' }); setTimeout(function () { socket.emit('new name', u.name); socket.emit('new color', u.color); }, 1000); io.emit('chat message', { color: '#fff', name: '', text: '' + escapeHtml(u.name) + ' connected.' }); return iid; } function disconnectUser(list, iid) { const u = list[iid]; if (!u) return; delete list[iid]; console.log(u.name + ' disconnected'); io.emit('chat message', { color: '#fff', name: '', text: '' + escapeHtml(u.name) + ' disconnected.' }); } function userAction(list, iid, socket, msg) { const u = list[iid]; if (!u) { socket.emit('chat message', { color: '#f00', name: '', text: 'You are not registered on the server' }); return; } if (!msg.trim()) return; console.log(u.name + '>' + msg); if (msg[0] === '/') { const arg1 = msg.split(' ')[1]; switch (msg.split(' ')[0]) { case '/help': socket.emit('chat message', { color: '#fff', name: '', text: '' + 'List of commands :
' + '/color (color) : change color (random if blank)
' + '/img [url] : show image
' + '/list : list users
' + '/me : express yourself
' + '/nick [username] : change username
' }); break; case '/color': if (arg1 && /^#[0-9a-fA-F]{3,6}|[a-zA-Z-_]*$/.test(arg1)) { u.color = arg1; } else { u.color = randomColor(); } socket.emit('chat message', { color: '#fff', name: '', text: 'Your new color is ' + escapeHtml(u.color) + '.' }); socket.emit('new color', u.color); break; case '/img': if (!arg1) { socket.emit('chat message', { color: '#f00', name: '', text: 'Please specify url' }); } else { io.emit('chat message', { color: '#fff', name: '', text: '' + escapeHtml(u.name) + '

' + '' + encodeURI(arg1) + '' }); } break; case '/list': const keys = Object.keys(list); let text = keys.length + ' users :'; keys.forEach(function (iid2) { const m = list[iid2]; text += '
' + escapeHtml(m.name) + '' }); socket.emit('chat message', { color: '#fff', name: '', text: text }); break; case '/nick': let name = msg.trim().substr(msg.indexOf(' ') + 1); if (name) { name = name.substr(0, 200); if (!usernameTaken(list, name)) { let oldname = u.name; u.name = name; io.emit('chat message', { color: '#fff', name: '', text: '' + escapeHtml(oldname) + ' is now ' + escapeHtml(u.name) + '.' }); socket.emit('new name', u.name); } else { socket.emit('chat message', { color: '#f00', name: '', text: 'Username already taken' }); } } else { socket.emit('chat message', { color: '#f00', name: '', text: 'Please specify username' }); } break; case '/me': io.emit('chat message', { color: u.color, name: '', text: '*' + escapeHtml(u.name) + ' ' + escapeHtml(msg.trim().substr(msg.indexOf(' ') + 1)) + '*' }); break; default: socket.emit('chat message', { color: '#f00', name: '', text: 'Unknown command ' + msg.split(' ')[0] + '
type /help for list of commands' }); break; } } else { io.emit('chat message', { color: u.color, name: u.name, text: msg.substr(0, 2000) }); } } app.get('/', function (req, res) { res.sendFile(__dirname + '/chat.html'); }); const list = {}; io.on('connection', function (socket) { const iid = connectUser(list, socket); socket.on('disconnect', function () { disconnectUser(list, iid); }); socket.on('chat message', function (msg) { userAction(list, iid, socket, msg); }); }); http.listen(3000, function () { console.log('listening on *:3000'); });