4
\$\begingroup\$

This is a chat using Node.js, socket.io and MongoDB for storage.

I'd appreciate any feedback on what can be improved. I understand that this allows for non-unique usernames to be used, and it's currently a JavaScript prompt, however this is simply a demonstration for entering a username to test the functionality.

index.html

<!DOCTYPE html>
<html>
 <head>
 <title>Chat</title>
 <link rel="stylesheet" href="css/main.css">
 </head>
 <body>
 <div class="chat">
 <div class="chat-messages"></div>
 <textarea placeholder="Type your message"></textarea>
 </div>
 <script src="node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js"></script>
 <script>
 (function() {
 var socket = io.connect('http://127.0.0.1:8080'),
 name = prompt('Enter your name');
 // Listen for output from server
 socket.on('output', function(data) {
 var messages = document.querySelector('.chat .chat-messages');
 if(data.length) {
 // Loop results
 for(var x = 0; x < data.length; x = x + 1) {
 var message = document.createElement('div');
 message.setAttribute('class', 'chat-message');
 message.innerText = data[x].name + ': ' + data[x].message;
 // Prepend
 messages.appendChild(message);
 messages.insertBefore(message, messages.firstChild);
 }
 }
 });
 // Listen for keydown
 document.querySelector('.chat textarea').addEventListener('keydown', function(event) {
 var self = this;
 // Is enter down (without shift being held)?
 if(event.which === 13 && event.shiftKey === false) {
 if(name) {
 // Send message
 socket.emit('input', {
 name: name,
 message: self.value
 });
 self.value = '';
 }
 event.preventDefault();
 }
 });
 })();
 </script>
 </body>
</html>

server.js

var mongo = require('mongodb').MongoClient,
 client = require('socket.io').listen(8080).sockets;
client.on('connection', function(socket) {
 // Connect to MongoDB
 mongo.connect('mongodb://127.0.0.1/chat', function(err, db) {
 if(err) throw err;
 var col = db.collection('messages');
 // Emit all messages
 col.find().limit(100).sort({_id: 1}).toArray(function(err, res) {
 if(err) throw err;
 socket.emit('output', res);
 });
 // Wait for input
 socket.on('input', function(data) {
 col.insert({name: data.name, message: data.message}, function(err, docs) {
 // Emit latest message to all clients
 client.emit('output', [data]);
 });
 });
 });
});

main.css (not as important here)

body,
textarea {
 font: 13px "Trebuchet MS", sans-serif;
}
.chat {
 max-width:300px;
}
.chat-messages,
.chat textarea {
 border:1px solid #bbb;
}
.chat-messages {
 width:100%;
 height:300px;
 overflow-y:scroll;
 padding:10px;
}
.chat-message {
 margin-bottom:10px;
}
.chat textarea {
 border-top:0;
 margin:0;
 max-width:100%;
 width:100%;
 padding:10px;
}
.chat textarea:focus {
 outline:none;
}
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Jan 25, 2014 at 20:20
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

You should only open one connection to mongodb. Otherwise if you have 10 users connected on your chat, you'll have 10 opened connections to mongodb.

var mongo = require('mongodb').MongoClient;
var sio = require('socket.io');
mongo.connect('mongodb://127.0.0.1/chat', function(err, db) {
 if(err) throw err;
 var messages = db.collection('messages');
 client = sio.listen(8080).sockets;
 client.on('connection', function(socket) {
 messages.find().limit(100).sort({_id: 1}).toArray(function(err, res) {
 if(err) throw err;
 socket.emit('output', res);
 });
 socket.on('input', function(data) {
 messages.insert({name: data.name, message: data.message}, function(err, docs) {
 client.emit('output', [data]);
 });
 });
 });
});

From there, I would split the code into small functions. One could be call onInputMessage and looks something like.

var onInputMessage = function(data) {
 message.insert({name: data.name, message: data.message}, function(err, docs) {
 client.emit('output', [data]);
};

So that you can call it like this socket.on('input', onInputMessage);

answered Mar 16, 2014 at 23:22
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.