Add to my chat nodejs express another my function - node.js

I have a basic chat working with NodeJS, express, and socket.io. I'm trying to add my own simple javascript function to the index.html. When I send message to other connected users, my function LoadRect() is draw a square but only on my web page. I want THE SAME square to be displayed on the other users screens with message. The message has random coordinates x, y, and random color (massege, x, y, c). Help me please. (Sorry for my english.)
index.html
<script src="/socket.io/socket.io.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script>
var x;
var y;
var c;
function LoadRect() {
var e = document.createElement("div");
e.className = "rect";
document.body.appendChild(e);
e.appendChild(document.createTextNode("Square"));
e = e.style;
e.width = e.height='100px';
e.position = "absolute";
x = Math.floor(Math.random()*400+200)+'px';
y = Math.floor(Math.random()*400)+'px';
c = '#'+(Math.random()*0xFFFFFF<<0).toString(16);
e.left = x;
e.top = y;
e.background = c;
}
var socket = io.connect('http://localhost:8181');
socket.on('connect', function(){
socket.emit('adduser', prompt("What's your name?", "Guest"));
});
socket.on('updatechat', function (username, data) {
$('#conversation').append('<b>' + username + ':</b> '+ data + '</br>');
});
socket.on('updateusers', function(data) {
$('#users').empty();
$.each(data, function(key, value) {
$('#users').append('<div>' + key + '</div>');
});
});
$(function(){
$('#datasend').click( function() {
var message = $('#data').val();
$('#data').val('');
//LoadRect();
LoadRect();
socket.emit('sendchat', message, x, y, c);
});
$('#data').keypress(function(e) {
if(e.which == 13) {
$(this).blur();
$('#datasend').focus().click();
}
});
});
</script>
<b>USERS</b>
<div id="users"></div>
<div id="conversation"></div>
<input id="data" />
<input type="button" id="datasend" value="send" />
app.js
var express = require('express')
, app = express()
, http = require('http')
, server = http.createServer(app)
, io = require('socket.io').listen(server);
server.listen(8181);
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
var usernames = {};
io.sockets.on('connection', function (socket) {
socket.on('sendchat', function (data, x, y, c) {
io.sockets.emit('updatechat', socket.username, data + ' [x=' + x + '; y=' + y + '; c=' + c +']');
});
socket.on('adduser', function(username){
socket.username = username;
usernames[username] = username;
socket.emit('updatechat', 'SERVER', ' connected');
socket.broadcast.emit('updatechat', 'SERVER', username + ', hello');
io.sockets.emit('updateusers', usernames);
});
socket.on('disconnect', function(){
delete usernames[socket.username];
io.sockets.emit('updateusers', usernames);
socket.broadcast.emit('updatechat', 'SERVER', socket.username + ', bye');
});
});

Related

Get the list of connected users/client in Socket.io

I need to get a list of connected users or clients from socket.io for real time chat.
List of connected user image
I managed to display a list of client who connect to my route/API (localhost:3003/chat). Who ever access this route (authorize or not) will be displayed as shown in the picture. My problem is on initial access or if you try to refresh the browser the client will not see the currently connected users or history of client connections.
This is my sample code for socket.io for server side,
module.exports.initializeSocketIO = (io) => {
io.on('connection', (socket) => {
socket.on('connectedUser', (users) =>{
socket.name = users;
io.emit('connectedUser', users);
console.log(users + ' has joined the chat.');
});
socket.on('disconnect', (user) => {
io.emit('disconnect', user);
console.log(socket.name + ' has left the chat.');
});
socket.on('chatMessage', (from, msg) => {
io.emit('chatMessage', from, msg);
console.log('Message From: ' + from + '\n -' + msg);
});
socket.on('showTypingUser', (user) => {
io.emit('showTypingUser', user);
});
});
};
This is my sample code for socket.io for client side
var socket = io();
socket.on('connectedUser', function(users){
var name = $('#currentUser').val();
var me = $('#user').val(name);
socket.name = users;
if(users != me){
$('#connectedUser').append('<tr><td>' + '<b>' + users + '</b>' + ' has
joined the discussion. </td></tr>' );
}
});
socket.on('chatMessage', function(from, msg){
var me = $('#user').val();
var color = (from == me) ? 'green' : '#009afd';
var from = (from == me) ? 'Me' : from;
var date = new Date();
if(from == "Me"){
$('#messages').append('<div class="speech-bubble">' + '<b style="color:' + color + '">' + from + ':</b> ' + msg + ' <span class="pull-right" style="color:gray">' + date.toLocaleString() + '</span>' +'</div>');
} else {
$('#messages').append('<div class="speech-bubble-reply">' + '<b
style="color:' + color + '">' + from + ':</b> ' + msg + ' <span class="pull-right" style="color:gray">' + date.toLocaleString() + '</span>' +'</div>');
}
});
socket.on('showTypingUser', function(user){
var name = $('#currentUser').val();
var me = $('#user').val(name);
if(user != me) {
$('#notifyUser').text(user + ' is typing ...');
}
setTimeout(function(){ $('#notifyUser').text(''); }, 10000);;
});
socket.on('disconnect', function(user){
var name = $('#currentUser').val();
var me = $('#user').val(name);
if(socket.name != name){
$('#connectedUser').append('<tr><td>' + '<b>' + socket.name + '</b>' + ' has left the discussion. </td></tr>' );
}
});
$(document).ready(function(){
var name = $('#currentUser').val();
$('#welcomeMessage').append('<div class="welcome-chat">Welcome to Entrenami Chat</div>')
socket.emit('connectedUser', name);
});
NOTE: I'm using express for my route and controller and EJS for my view. I'm a bit stuck here because I don't know where to look on how to solve my problem.
io.engine.clientsCount return the total count of connected users you can send it to client when a user get connected like this:
io.on('connection', (socket) => {
var total=io.engine.clientsCount;
socket.emit('getCount',total)
});

node.js error upon client disconnect

I'm using node.js and I get the error in the picture every single time a client disconnects (This happens when I just close the tab and I've also tried using socket.disconnect() on both the client and the server side)
here's my code
var io = require('socket.io').listen(4000);
var fs = require('fs');
io.sockets.on('connection', function(socket) {
socket.on('login', function(info)
{
fs.readFile("chatLog.txt", function(err, data)
{
if(err)
{
return console.error(err);
}
socket.emit('incomingMessage', data.toString());
});
socket.broadcast.emit('newUser', info);
});
socket.on('message', function(content) {
console.log(content);
io.sockets.emit('incomingMessage', content);
});
socket.on('logout', function(name)
{
socket.broadcast.emit('incomingMessage', "user: " + name + " has logged out");
//socket.disconnect();
});
});
can anyone tell me how to disconnect without having the server crash with that error?
client side HTML:
<html>
<head>
<!-- This is the websocket SERVER -->
<script src="http://localhost:4000/socket.io/socket.io.js"></script>
<script src="client.js"></script>
</head>
<body>
<div id="loginDiv">
username: <input type="text" id = "userName"><br>
<input type = "button" id="login" value = "login" onClick="login()">
</div>
<div id="logoutDiv" style="visibility:hidden">
<input type = "button" id = "messageRedir" value = "send message" onClick= "gotoMessage()">
<input type = "button" id = "logout" value = "logout" onClick="logout()">
</div>
<div id="sendMessage" style="visibility:hidden">
<input type = "text" id="messageBox"><br>
<input type = "button" value="send message" onClick="sendMessage()">
<input type = "button" value = "cancel" onClick="back">
</div>
<div id="msg"></div>
</body>
</html>
Client side JS:
var userName = null;
var socket = null;
function login()
{
socket = io.connect('http://localhost:4000');
userName = document.getElementById('userName').value;
document.getElementById("loginDiv").style.visibility = "hidden";
document.getElementById("logoutDiv").style.visibility = "visible";
socket.emit('login', userName+ ' has connected');
// Attach event handler for event fired by server
socket.on('incomingMessage', function(data) {
var elem = document.getElementById('msg');
console.log(data);
elem.innerHTML = data + "<br>" + elem.innerHTML; // append data that we got back
});
socket.on('newUser', function(data) {
var elem = document.getElementById('msg');
console.log(data);
elem.innerHTML = data + "<br>" + elem.innerHTML; // append data that we got back
});
}
function logout()
{
document.getElementById("loginDiv").style.visibility = "visible";
document.getElementById("logoutDiv").style.visibility = "hidden";
document.getElementById('msg').innerHTML = "";
socket.emit('logout', userName);
socket.disconnect();
socket = null;
}
function gotoMessage()
{
document.getElementById("loginDiv").style.visibility = "hidden";
document.getElementById("msg").style.visibility = "hidden";
document.getElementById("sendMessage").visibility = "visible";
}
function back()
{
document.getElementById("loginDiv").style.visibility = "visible";
document.getElementById("msg").style.visibility = "visible";
document.getElementById("sendMessage").visibility = "hidden";
}
function sendMessage()
{
var mess = document.getElementById('messageBox').value;
socket.emit('message', mess);
}
The problem is most likely in the logout function where you are using the socket (that is no longer active) to emit an event. You should use io.sockets.emit instead. I have some suggestions.
Instead of using the socket.emit('logout', username) event on the client side, use the built in logout event that gets fired when the user close the browser. That event is disconnect. You don't need to pass the username with each request either. You only need to pass it once with the login event. Then you can store the username on the server as a property of the socket.
Client Side
function login()
{
socket = io.connect('http://localhost:4000');
userName = document.getElementById('userName').value;
document.getElementById("loginDiv").style.visibility = "hidden";
document.getElementById("logoutDiv").style.visibility = "visible";
// just send the username
socket.emit('login', userName);
// Attach event handler for event fired by server
socket.on('incomingMessage', function(data) {
var elem = document.getElementById('msg');
console.log(data);
elem.innerHTML = data + "<br>" + elem.innerHTML; // append data that we got back
});
socket.on('newUser', function(data) {
var elem = document.getElementById('msg');
console.log(data);
elem.innerHTML = data + "<br>" + elem.innerHTML; // append data that we got back
});
}
function logout()
{
document.getElementById("loginDiv").style.visibility = "visible";
document.getElementById("logoutDiv").style.visibility = "hidden";
document.getElementById('msg').innerHTML = "";
socket.disconnect();
socket = null;
}
Server Side
io.sockets.on('connection', function(socket) {
socket.on('login', function(uxname)
{
// store username variable as property of the socket connection
// this way we can handle the disconnect message later
this.username = uxname;
fs.readFile("chatLog.txt", function(err, data)
{
if(err)
{
return console.error(err);
}
socket.emit('incomingMessage', data.toString());
});
socket.broadcast.emit('newUser', uxname);
});
socket.on('message', function(content) {
console.log(content);
io.sockets.emit('incomingMessage', content);
});
socket.on('disconnect', function(){
// don't use socket.broadcast.emit. at this point the socket is destroyed and you cant call events on it. That is most likely why you have the error.
// use io.sockets.emit instead
io.sockets.emit('incomingMessage', "user: " + this.username + " has logged out")
});
});

NodeJS - socket.broadcast.to not emitting inside nested listeners

I'm trying to emit messsage to specific rooms, once the "joinedRoom' listener is triggered by the client, the code works fine if I place my code outside the joinedRoom listeners, otherwise it does nothing.
Code:
app.get('/room/:room/user/:user', function(req, res){
var room = {
username: req.params.user,
roomname: req.params.room
};
res.render('room', room);
});
var users = {};
io.sockets.on('connection', function (socket) {
socket.on('joinedRoom', function(roomData){
socket.username = roomData.username;
socket.room = roomData.roomname;
console.log("Roomname: " + socket.room);
console.log("Username: " + socket.username);
socket.join(socket.room);
socket.broadcast.to(socket.room).emit('newUser', socket.username);
socket.on('disconnect', function(){
socket.broadcast.emit('userLeft', socket.username);
socket.leave(socket.room);
console.log('Connection id: ' + socket.id);
});
});
});
I saw the docs and some sample code it everything seeems to be correct (when it comes simply to syntax) am I missing something simple here?
Thanks!
EDIT
Client code:
var socket, roomname, ioRoom;
var socket = io.connect('http://localhost:3000');
socket.on('enterRoom', function(roomname){
console.log("ENTERED ROOM: " + roomname);
});
socket.on('newUser', function(username){
pushUserName(username);
pushUserStatus(username, ' has joined the room <br/>')
});
socket.on('newRoom', function(data){
alert(data)
});
socket.on('userLeft', function(username){
pushUserStatus(username, ' has left the room <br/>')
})
function pushUserName(username){
var el = document.getElementById("username");
el.innerHTML += username + '<br/>';
}
function pushUserStatus(username, message){
var el = document.getElementById("joined");
el.innerHTML += username + message;
}

Socket.io broadcast to not working

I have the following code:
var room = "1";
var chat = io.connect("localhost:3700/");
self.chat = chat;
chat.on("connection", function(socket){
socket.emit("room", room);
socket.on('message', function (data) {
self.receiveMessage(data);
});
});
chat.broadcast.to(room).emit('send',"HEllo");
receiveMessage:
receiveMessage: function(data){
var $elem = $("#chat1");
var $content = $elem.find(".messageText");
if(data.message) {
messages.push(data);
var html = '';
for(var i=0; i<messages.length; i++) {
html += '<b>' + (messages[i].username ? messages[i].username : 'Server') + ': </b>';
html += messages[i].message + '<br />';
}
$content.html(html);
} else {
console.log("There is a problem:", data);
}
}
The line chat.broadcast.to(room).emit('send',"HEllo"); gives me the error:
Uncaught TypeError: Cannot call method 'to' of undefined
What am I doing wrong?
Not really sure but I think you can send a broadcast only on connection.
You can try this:
var room = "1";
var chat = io.connect("localhost:3700/");
self.chat = chat;
chat.on("connection", function(socket){
socket.emit("room", room);
socket.on('message', function (data) {
self.receiveMessage(data);
});
chat.broadcast.to(room).emit('send',"HEllo");
});
Of course you can also send the broadcast in a separate handler, i.e.:
var room = "1";
var chat = io.connect("localhost:3700/");
self.chat = chat;
chat.on("connection", function(socket){
socket.emit("room", room);
socket.on('message', function (data) {
self.receiveMessage(data);
});
socket.on('foo event', function(data) {
chat.broadcast.to(room).emit('send',"HEllo");
}
});

interprocess communication and clustering for a chat with redis and socket.io

I'm creating an advanced chat system with nodejs, socket.io and redis.
The goal is to have a chat system where one joint chat room is for all users but with an extra possibility to get a private chat with a stuff for one-to-one support.
my app.js looks like the following:
/********************************** Required **********************************/
var express = require('express')
, app = express()
, http = require('http')
, server = http.createServer(app)
, io = require('socket.io').listen(server);
var cluster = require('cluster')
, http = require('http')
, numCPUs = require('os').cpus().length;
/* this is for redis integration */
var redis = require('redis')
, RedisStore = require('socket.io/lib/stores/redis')
, pub = redis.createClient()
, sub = redis.createClient()
, client = redis.createClient();
io.set('store', new RedisStore({
redisPub: pub,
redisSub: sub,
redisClient: client
}));
/********************************** Required **********************************/
/********************************** Objects **********************************/
function User(socketID, username, role) {
var _socketID = socketID;
var _username = username;
var _role = role;
var _userObjectList = null;
console.log('user is being created');
this.getSocketID = function() {
return _socketID;
}
this.getUsername = function() {
return _username;
}
this.getRole = function() {
return _role;
}
this.setRole = function(role) {
_role = role;
_userObjectList = new Array();
}
this.addUser = function(userObject) {
_userObjectList[userObject.getUsername()] = userObject;
}
this.getUserCount = function() {
if(_role != Roles.staff)
return -1;
return Object.keys(_userObjectList).length;
}
}
/********************************** Objects **********************************/
/********************************** Static Variables **********************************/
function Roles() {
}
Roles.user = "user";
Roles.staff = "staff";
/********************************** Static Variables **********************************/
/********************************** Variables **********************************/
// usernames which are currently connected to the chat
var usernames = {};
var staff = {};
var socketIDList = {};
var users = new Array();
/********************************** Variables **********************************/
/********************************** Functions **********************************/
function getUsernames() {
return Object.keys(users);
}
function getStaffObjects() {
var objects = new Array();
console.log('getting users ' + Object.keys(users));
for (key in users) {
console.log('testing if ' + key + ' is a staff member');
if(users[key].getRole() == Roles.staff) {
console.log(key + ' is a staff member');
objects[key]=users[key];
}
}
return objects;
}
function isValidUsername(username) {
if(username == null)
return false;
var validation = /^[a-zA-Z]\w{2,20}/g;
return validation.test(username);
}
/********************************** Functions **********************************/
/********************************** Cluster **********************************/
if (cluster.isMaster) {
server.listen(8080);
console.log('listening now');
// Fork workers.
console.log('i am the master');
for (var i = 0; i < numCPUs; i++) {
console.log('forking cluster node ' + i);
cluster.fork();
}
cluster.on('exit', function(worker, code, signal) {
console.log('worker ' + worker.process.pid + ' died');
});
} else {
// Workers can share any TCP connection
// In this case its a HTTP server
console.log('i am worker #' + cluster.worker.id);
http.createServer(function(req, res) {
res.writeHead(200);
res.end("hello world\n");
}).listen(8000);
}
/********************************** Cluster **********************************/
// routing
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
io.sockets.on('connection', function (socket) {
// when the client emits 'sendchat', this listens and executes
socket.on('sendchat', function (data) {
// we tell the client to execute 'updatechat' with 2 parameters
io.sockets.emit('updatechat', socket.username, data);
});
socket.on('pm', function(to, message) {
var id = users[to].getSocketID();
io.sockets.socket(id).emit('updatePrivateChat', socket.username, message);
});
socket.on('staffMessage', function(to, message) {
console.log("message to " + to + ": " + message);
var id = users[to].getSocketID();
io.sockets.socket(id).emit('updateStaffChat', socket.username, message);
});
// when the client emits 'adduser', this listens and executes
socket.on('adduser', function(username){
if(isValidUsername(username) && users[username] == null){ // user does not already exist
// we store the username in the socket session for this client
socket.username = username;
// add the client's username to the global list
users[username] = new User(socket.id, socket.username, Roles.user);
console.log('added user ' + username + '. now we have ' + Object.keys(users).length + " users");
// echo to client they've connected
socket.emit('updatechat', 'SERVER', 'you have connected');
// echo globally (all clients) that a person has connected
socket.broadcast.emit('updatechat', 'SERVER', socket.username + ' has connected');
// update the list of users in chat, client-side
io.sockets.emit('updateusers', getUsernames());
}
else{
socket.emit('usernameExists', username);
}
});
// when the user wants to chat with staff
socket.on('contactStaff', function(){
/***************** search for a free staff ***************/
var member = null;
console.log('user ' + users[socket.username].getUsername() + ' wants to contact staff');
var staffList = getStaffObjects();
if(Object.keys(staffList).length == 0)
console.log('error. no staff available');
else {
var staffNumber = Math.floor(Math.random() * (Object.keys(staffList).length-1));
var i = 0;
console.log("StaffList Length: " + Object.keys(staffList).length);
for(key in staffList) {
if(i == staffNumber) {
member = staffList[key]
staffname = member.getUsername();
break;
}
i++;
}
console.log('adding ' + socket.username + ' to ' + member.getUsername());
member.addUser(users[socket.username]);
console.log('new contact for staff member. ' + member.getUsername() + ' has now ' + member.getUserCount() + ' contacts');
console.log('staffFound: ' + member.getUsername() + ", user: " + socket.username);
io.sockets.socket(users[socket.username].getSocketID()).emit('staffFound', member.getUsername());
io.sockets.socket(users[socket.username].getSocketID()).emit('updateStaffChat', member.getUsername(), "Sie haben einen Mitarbeiter kontaktiert. Was kann ich für Sie tun?");
io.sockets.socket(member.getSocketID()).emit('staffFound', socket.username);
io.sockets.socket(member.getSocketID()).emit('updateStaffChat', socket.username, "Sie wurden von dem Benutzer " + socket.username + " kontaktiert");
}
});
// register a staff member
socket.on('registerAsStaff', function(password){
if(password != "abc")
return false;
var staffname = socket.username;
users[socket.username].setRole(Roles.staff);
console.log('new staff member: ' + socket.username + " with role: " + users[socket.username].getRole());
});
// when the user disconnects.. perform this
socket.on('disconnect', function(){
// remove the username from global usernames list
users[socket.username] = null;
delete users[socket.username];
// update list of users in chat, client-side
io.sockets.emit('updateusers', usernames);
// echo globally that this client has left
socket.broadcast.emit('updatechat', 'SERVER', socket.username + ' has disconnected');
});
});
My problem:
The chat ist working. Clustering itself is working, but of cause I need a correct redis integration. Could anyone help me on how to do that? Is my solution in general a performant solution for a big amount of clients (max. 1000-2000 in the first step)? - I know I will have to benchmark testing and so on, but is there anything you see that would prevent me from doing that?
I also need a solution to have multiple instances lateron. I found that description on http://blog.cloudfoundry.com/2013/01/24/scaling-real-time-apps-on-cloud-foundry-using-node-js-and-redis/. I understand the problem of socket.io with multiple instances, but I don't understand the implementation. Could anybody please provide a short example on how to do this?

Resources