Node.js / Socket Chat - Userlist - javascript

I have been following a tutorial and a github (https://github.com/mmukhin/psitsmike_example_2) on how to make a multi room simple chat app. I'm fairly new to this.
I am trying to modify it to list the usernames in the right hand side under the room list. But it's not working, it doesn't seem to be throwing any errors though?
I have done the following:
index.html
I have added the following code to the original:
<div id="roomusers"></div>
and
socket.on('updateroomusers', function(roomusers) {
$("#roomusers").empty();
$.each(roomusers, function (key, value) {
$('#roomusers').append('’+value+”);
});
});
This is the original
<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 socket = io.connect('http://localhost:8080');
// on connection to server, ask for user's name with an anonymous callback
socket.on('connect', function(){
// call the server-side function 'adduser' and send one parameter (value of prompt)
socket.emit('adduser', prompt("What's your name?"));
});
// listener, whenever the server emits 'updatechat', this updates the chat body
socket.on('updatechat', function (username, data) {
$('#conversation').append('<b>'+username + '> </b> ' + data + '<br>');
});
// listener, whenever the server emits 'updaterooms', this updates the room the client is in
socket.on('updaterooms', function(rooms, current_room) {
$('#rooms').empty();
$.each(rooms, function(key, value) {
if(value == current_room){
$('#rooms').append('<div>' + value + '</div>');
}
else {
$('#rooms').append('<div>' + value + '</div>');
}
});
});
function switchRoom(room){
socket.emit('switchRoom', room);
}
// on load of page
$(function(){
// when the client clicks SEND
$('#datasend').click( function() {
var message = $('#data').val();
$('#data').val('');
// tell server to execute 'sendchat' and send along one parameter
socket.emit('sendchat', message);
});
// when the client hits ENTER on their keyboard
$('#data').keypress(function(e) {
if(e.which == 13) {
$(this).blur();
$('#datasend').focus().click();
}
});
});
socket.on('updateroomusers', function(roomusers) {
$("#roomusers").empty();
$.each(roomusers, function (key, value) {
$('#roomusers').append('’+value+”);
});
});
</script>
<div style="float:left;width:100px;border-right:1px solid black;height:300px;padding:10px;overflow:scroll-y;">
<b>ROOMS</b>
<div id="rooms"></div>
<b>USERS</b>
<div id="roomusers"></div>
</div>
<div style="float:left;width:300px;height:250px;overflow:scroll-y;padding:10px;">
<div id="conversation"></div>
<input id="data" style="width:200px;" />
<input type="button" id="datasend" value="send" />
</div>
And the app.js (everything between the comments
/////////**** Userlist Start ***********///////
and
/////////**** Userlist End***********/////// is code I added
var express = require('express')
, app = express()
, http = require('http')
, server = http.createServer(app)
, io = require('socket.io').listen(server);
server.listen(8080);
// routing
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
// usernames which are currently connected to the chat
var usernames = {};
// rooms which are currently available in chat
var rooms = ['room1','room2','room3'];
io.sockets.on('connection', function (socket) {
// when the client emits 'adduser', this listens and executes
socket.on('adduser', function(username){
// store the username in the socket session for this client
socket.username = username;
// store the room name in the socket session for this client
socket.room = 'room1';
// add the client's username to the global list
usernames[username] = username;
// send client to room 1
socket.join('room1');
// echo to client they've connected
socket.emit('updatechat', 'SERVER', 'you have connected to room1');
// echo to room 1 that a person has connected to their room
socket.broadcast.to('room1').emit('updatechat', 'SERVER', username + ' has connected to this room');
socket.emit('updaterooms', rooms, 'room1');
/////////**** Userlist Start ***********///////
// get all the clients in ‘room1′
var clients = io.sockets.clients('room1');
// loop through clients in ‘room1′ and add their usernames to the roomusers array
for(var i = 0; i < clients.length; i++) {
roomusers[roomusers.length] = clients[i].username;
/////////**** Userlist End ***********///////
}
// broadcast to everyone in room 1 the usernames of the clients connected.
io.sockets.to('room1').emit('updateroomusers',roomusers);
});
// 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.in(socket.room).emit('updatechat', socket.username, data);
});
socket.on('switchRoom', function(newroom){
socket.leave(socket.room);
socket.join(newroom);
socket.emit('updatechat', 'SERVER', 'you have connected to '+ newroom);
// sent message to OLD room
socket.broadcast.to(socket.room).emit('updatechat', 'SERVER', socket.username+' has left this room');
// update socket session room title
socket.room = newroom;
socket.broadcast.to(newroom).emit('updatechat', 'SERVER', socket.username+' has joined this room');
socket.emit('updaterooms', rooms, newroom);
});
// when the user disconnects.. perform this
socket.on('disconnect', function(){
// remove the username from global usernames list
delete usernames[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');
socket.leave(socket.room);
});
});

Related

426 Status: WebSockets with Node.js

Im currently switching my application from using Socket.io to HTML5 WebSockets. I'm assuming that my problem lies within the first couple lines of both the client and server. My browser keeps on replying with a 426 (Upgrade Required) status when I test my app on localhost. Please shed some light on my problem...
Server Code
"use strict";
var session = require('./chat-session'),
serveStatic = require('serve-static'),
server = require('http').createServer(),
WebSocketServer = require('ws').Server,
wss = new WebSocketServer({server: server, port: 8181}),
express = require('express'),
app = express();
// Sockets with real-time data
// io = require('socket.io').listen(server),
// mongoose = require('mongoose');
app.use(express.static(__dirname + '/public')); // used for external files on client
let storage = session.default; // cache object for storage
// Routing refers to determining how an application responds to a client request to a particular endpoint
app.get('/', function(req, res){
res.sendFile(__dirname + '/public/index.html');
});
wss.on('connection', function(client){
client.on('join', (name) => {
client.nickname = name;
// check to see if nickname has been taken, if so, give random name
if(storage.users.indexOf(client.nickname) !== -1) {client.nickname = randomName();}
// tell all chatters that a new user has entered the room
client.broadcast.emit("enter", "* " + client.nickname + " * has connected");
storage.users.forEach((user) => {
client.emit('add chatter', user);
});
client.broadcast.emit('add chatter', client.nickname);
storage.channels.general.messages.forEach((message) => {
client.emit("message", message.name + ": " + message.data, 'general');
});
storage.users.push(client.nickname);
});
client.on('message', (message, room) => {
var nickname = client.nickname;
client.broadcast.emit("message", nickname + ": " + message, room);
client.emit("me", message); // send message to self
storeMessage(nickname, message, room); // store the message in chat-session
console.log(nickname + ' said: ' + message + " in room " + room);
});
// When client switches between tabs (rooms)
client.on('switch', (room) => {
storage.channels[room].messages.forEach((message) => {
if (message.name === client.nickname) {
client.emit("me", message.data, room);
} else {
client.emit("message", message.name + ": " + message.data, room);
}
});
});
// client.on('disconnect', () => {
// client.emit('disconnect', "client")
// });
});
//const PORT = 8080;
//server.listen(PORT);
Client Code
// var server = io.connect("http://localhost:8080"); // connect to server
var server = new WebSocketServer("ws://localhost:8181");
var curRoom = $('.nav .active').attr('id'); // cache current room
server.on('connect', function(data){
nickname = prompt("What is your nickname?");
//while(nickname) TODO:make sure client cannot choose null
server.emit('join', nickname); // notify the server of the users nickname
});
//server.on('disconnect', function(data){
// server.emit('disconnect');
//});
// new chatter enters room
server.on('enter', function(data){
$('#messages').append($('<li style="background:#33cc33; color:white">').text(data));
});
// connected users section
server.on('add chatter', function(name){
var chatter = $('<li style="color:white; font-size:22px">' + name + '</li>').data('name', name);
$('#users').append(chatter);
});
// users' send message
server.on('message', function(message, room){
// only emit message to other users if they are in same channel
if (curRoom === room) {
$('#messages').append($('<li style="display:table; box-shadow: 6px 3px 8px grey;">').text(message));
play(); // invoke function to play sound to other clients
console.log('sound played here');
}
});
// differentiate how the client sees their message
server.on('me', function(message){
$('#messages').append($('<li style="background:#0066ff; color:white; display:table; box-shadow: 6px 3px 8px grey;">').text(message));
});
// Client submits message
$('#chat_form').submit(function(e){
var message = $("#chat_input").val();
server.emit('message', message, curRoom);
$('#chat_input').val(''); // Make input box blank for new message
return false; // prevents refresh of page after submit
});
Http 426 means that you are trying to connect unsupported web-socket version .
You can check in the client headers for supported version .
Refer to RFC for more detail
https://www.rfc-editor.org/rfc/rfc6455#section-4.2.2

socket.io rooms repeating same message per client

I'm using rooms to send a 'private' message to a client and it works however the message being sent is duplicated by the number of clients I have and I believe this is because of my .on('message') since this is still triggering for every client but only emitting to the correct client (but multiple times..)
server
io.sockets.on('connection', function(socket {
socket.on('join', function(data)
{
console.log('enter');
socket.join(data.user);
});
var rClient = redis.createClient();
rClient.subscribe('messagex');
rClient.on('message', function(channel, message) {
io.in(message.user).emit('messagex', {content: message.content});
});
socket.on('disconnect', function() {
rClient.quit();
});
});
receiver client
<script>
var username = prompt("test");
var socket = io.connect('http://localhost:8100');
socket.emit('join', {user: username});
socket.on('messagex', function(data) {
$('#messages').append('<p>' + data.content + '</p>');
});
So I have 3 clients (each with different users/rooms open) at the receiver page and I send a message from the sender to say user user1, then I will only receive the message on user1 client but it will receive 3 of the same message each time and the number of times duplicated seems to be the number of clients I have..
try this
subscribe.unsubscribe(channel);
when connection disconnect unsubscribe
io.sockets.on('connection', function(socket {
socket.on('join', function(data)
{
console.log('enter');
socket.join(data.user);
});
var rClient = redis.createClient();
rClient.subscribe('messagex');
rClient.on('message', function(channel, message) {
io.in(message.user).emit('messagex', {content: message.content});
});
socket.on('disconnect', function() {
rClient.unsubscribe('messagex');
rClient.quit();
});
});
I think you are using two channel at same time redis and socket.io, You have to make single channel i.e. socket.io only then there is no need make redis channel means no need to add pub/sub method when you transferring data through emit/on.

Socket.io (1.x) .to(room) not working, but works without

I'm building a simple messaging server and it works perfect using the socket.broadcast.emit() however if you use the socket.broadcast.in(room).emit() it dose not connect up. I've include the server code and client code below.
server
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var Parse = require('parse').Parse;
var room;
app.get('/', function(req, res){
res.sendfile('index.html');
});
// When a new connection is launched
io.on('connection', function(socket){
console.log('user connected: '+socket.id);
//========== INIT connection =========
// once a client has connected, we expect to get a ping from them saying what room
// they want to join
socket.on('room', function(data) {
room = data;
socket.join(room);
console.log(' + User: '+socket.id+' - joined Room: ['+room+']');
console.log(' + User: '+socket.id+' - has Rooms: ['+socket.rooms+']');
// Display all sockets connected to room
inRoom(room);
});
//======== Delegates messages ========
socket.on('message_send', function(data){
var JSONdata = JSON.parse(data);
var room_l = JSONdata.chat_id;
var msg = JSONdata.message;
console.log('Room: ' + room_l + ' - Message: ' + msg);
// Send message
//io.emit('message_received', msg);
//socket.broadcast.emit('message_received', msg);
io.in('TZRfM7V5HH').emit('message_recieved', msg);
//io.to(room_l).emit('message_received', msg);
// Save message to parse
parseSAVE(data);
});
});
Client
<script>
var socket = io();
var msg = $('#m').val();
var room = 'TZRfM7V5HH';
$( document ).ready(function() {
socket.emit('room',room);
socket.emit('message_send', '{"chat_id":"'+room+'","message":"yoyoyo shits to hype"}');
});
$('form').submit(function(){
$msg = $('#m').val();
socket.emit('message_send', '{"chat_id":"'+room+'","message":"'+$msg+'"}');
$('#messages').append($('<li>').text($msg));
$('#m').val('');
return false;
});
socket.on('message_received', function(msg){
$('#messages').append($('<li>').text(msg));
});
</script>
I have been playing around with this all week and I cant seem to figure out whats wrong with my implementation, any help or pointers would be greatly appreciated!

express.session.MemoryStore not returning session?

It was really easy setting up sessions and using them in PHP. But my website needs to deal with WebSockets. I am facing problem to set up sessions in node.js. I can easily push data without using sessions and it would work fine but when more than one tab is opened the new socket.id is created and previously opened tabs won't function properly. So I have been working on sessions and had problem accessing session store, its logging session not grabbed. I have tried with session.load as well but no luck
How do I get session object and use it in a way that opening other tabs wouldn't affect the functionality and push data from server to client on all tabs?
var express=require('express');
var http = require('http');
var io = require('socket.io');
var cookie = require("cookie");
var connect = require("connect"),
MemoryStore = express.session.MemoryStore,
sessionStore = new MemoryStore();
var app = express();
app.configure(function () {
app.use(express.cookieParser());
app.use(express.session({store: sessionStore
, secret: 'secret'
, key: 'express.sid'}));
app.use(function (req, res) {
res.end('<h2>Hello, your session id is ' + req.sessionID + '</h2>');
});
});
server = http.createServer(app);
server.listen(3000);
sio = io.listen(server);
var Session = require('connect').middleware.session.Session;
sio.set('authorization', function (data, accept) {
// check if there's a cookie header
if (data.headers.cookie) {
// if there is, parse the cookie
data.cookie = connect.utils.parseSignedCookies(cookie.parse(data.headers.cookie),'secret');
// note that you will need to use the same key to grad the
// session id, as you specified in the Express setup.
data.sessionID = data.cookie['express.sid'];
sessionStore.get(data.sessionID, function (err, session) {
if (err || !session) {
// if we cannot grab a session, turn down the connection
console.log("session not grabbed");
accept('Error', false);
} else {
// save the session data and accept the connection
console.log("session grabbed");
data.session = session;
accept(null, true);
}
});
} else {
// if there isn't, turn down the connection with a message
// and leave the function.
return accept('No cookie transmitted.', false);
}
// accept the incoming connection
accept(null, true);
});
sio.sockets.on('connection', function (socket) {
console.log('A socket with sessionID ' + socket.handshake.sessionID
+ ' connected!');
});
Take a look at this article: Session-based Authorization with Socket.IO
Your code works fine, but need 2 improvements to do what you want (send session data to clients from server):
it extracts sessionID during authorization only
it extracts session data from store by this sessionID during connection where you can send data from server to clients in an interval.
Here's the improved code:
var express = require('express');
var connect = require('connect');
var cookie = require('cookie');
var sessionStore = new express.session.MemoryStore();
var app = express();
app.use(express.logger('dev'));
app.use(express.cookieParser());
app.use(express.session({store: sessionStore, secret: "secret", key: 'express.sid'}));
// web page
app.use(express.static('public'));
app.get('/', function(req, res) {
var body = '';
if (req.session.views) {
++req.session.views;
} else {
req.session.views = 1;
body += '<p>First time visiting? view this page in several browsers :)</p>';
}
res.send(body + '<p>viewed <strong>' + req.session.views + '</strong> times.</p>');
});
var sio = require('socket.io').listen(app.listen(3000));
sio.set('authorization', function (data, accept) {
// check if there's a cookie header
if (data.headers.cookie) {
// if there is, parse the cookie
var rawCookies = cookie.parse(data.headers.cookie);
data.sessionID = connect.utils.parseSignedCookie(rawCookies['express.sid'],'secret');
// it checks if the session id is unsigned successfully
if (data.sessionID == rawCookies['express.sid']) {
accept('cookie is invalid', false);
}
} else {
// if there isn't, turn down the connection with a message
// and leave the function.
return accept('No cookie transmitted.', false);
}
// accept the incoming connection
accept(null, true);
});
sio.sockets.on('connection', function (socket) {
//console.log(socket);
console.log('A socket with sessionID ' + socket.handshake.sessionID + ' connected!');
// it sets data every 5 seconds
var handle = setInterval(function() {
sessionStore.get(socket.handshake.sessionID, function (err, data) {
if (err || !data) {
console.log('no session data yet');
} else {
socket.emit('views', data);
}
});
}, 5000);
socket.on('disconnect', function() {
clearInterval(handle);
});
});
Then you can have a client page under public/client.html at http://localhost:3000/client.html to see the session data populated from http://localhost:3000:
<html>
<head>
<script src="/socket.io/socket.io.js" type="text/javascript"></script>
<script type="text/javascript">
tick = io.connect('http://localhost:3000/');
tick.on('data', function (data) {
console.log(data);
});
tick.on('views', function (data) {
document.getElementById('views').innerText = data.views;
});
tick.on('error', function (reason){
console.error('Unable to connect Socket.IO', reason);
});
tick.on('connect', function (){
console.info('successfully established a working and authorized connection');
});
</script>
</head>
<body>
Open the browser console to see tick-tocks!
<p>This session is viewed <b><span id="views"></span></b> times.</p>
</body>

When namespacing I receive a "cannot GET error" displayed in browser

I'm using namespaces to differentiate between version of my socket.io chat app, and I'm having trouble with a "cannot GET error displayed in browser."
I plan on continually updating a chat app I made in a basic socket.io tutorial, and I want to be able to launch any version of it at any time. I'm going to do this by the use of namespaces. When I launch my app in browser at the location myserverlocation/v0.0.1 to access version 0.0.1 of my app, I get an error that states cannot GET '/v0.0.1'.
This is my server code:
var app = require('express')(),
server = require('http').Server(app),
io = require('socket.io').listen(server),
chat = io.of('/v0.0.1');
server.listen(80);
// routing
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
// usernames which are currently connected to the chat
var usernames = {};
chat.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);
});
// when the client emits 'adduser', this listens and executes
socket.on('adduser', function(username) {
// we store the username in the socket session for this client
socket.username = username;
// add the client's username to the global list
usernames[username] = username;
// 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', username + ' has connected');
// update the list of users in chat, client-side
io.sockets.emit('updateusers', usernames);
});
// when the user disconnects.. perform this
socket.on('disconnect', function() {
// remove the username from global usernames list
delete usernames[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');
});
});
And this is my client code:
<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 socket = io.connect('myserverlocation');
var chat = socket.of('/v0.0.1');
// on connection to server, ask for user's name with an anonymous callback
chat.on('connect', function(){
// call the server-side function 'adduser' and send one parameter (value of prompt)
chat.emit('adduser', prompt("What's your name?"));
});
// listener, whenever the server emits 'updatechat', this updates the chat body
chat.on('updatechat', function(username, data) {
$('#conversation').append('<b>' + username + ':</b> ' + data + '<br>');
});
// listener, whenever the server emits 'updateusers', this updates the username list
chat.on('updateusers', function(data) {
$('#users').empty();
$.each(data, function(key, value) {
$('#users').append('<div>' + key + '</div>');
});
});
// on load of page
$(function(){
// when the client clicks SEND
$('#datasend').click( function() {
var message = $('#data').val();
$('#data').val('');
// tell server to execute 'sendchat' and send along one parameter
chat.emit('sendchat', message);
});
// when the client hits ENTER on their keyboard
$('#data').keypress(function(e) {
if(e.which == 13) {
$(this).blur();
$('#datasend').focus().click();
}
});
});
</script>
<div style="float:left;width:100px;border-right:1px solid black;height:300px;padding:10px;overflow:scroll-y;">
<b>USERS</b>
<div id="users"></div>
</div>
<div style="float:left;width:300px;height:250px;overflow:scroll-y;padding:10px;">
<div id="conversation"></div>
<input id="data" style="width:200px;" />
<input type="button" id="datasend" value="send" />
</div>
My chat app works fine without the use of namespaces, at myserverlocation/. I cannot figure out why I keep getting this error. After some investigation I think my usage of io.of() is incorrect, but I cannot seem to fix the problem. I'm not sure if my problem lies in the server code, the client code, or both.
Edit: After more investigation, I think my problem lies in the follow segment of code (though I could be mistaken):
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
Edit2: The problem did in fact lie in the code segment above. I should have been sending my whole /Chat directory as static content instead of using res.sendfile() to send one file. I will formally answer my own question when stackoverflow lets me (I have to wait 8 hours to answer my own question).
I managed to find what my problem was. The problem lied in the following section of code:
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
I was sending one particular file upon connection to my server, when I should be sending my entire /Chat directory as static content. This way, I can chose what version of my chat app I would like to launch. I managed to do this by changing a few lines of code in my server code:
var express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io').listen(server);
server.listen(80);
// Chat directory
app.use(express.static('/home/david/Chat'));

Categories

Resources