426 Status: WebSockets with Node.js - javascript

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

Related

Unable to close tcp socket on event error at node server when client is not gracefully disconnects

I have writen a simple javascript chat application using tcp socket on node.js.
It works fine on local server (Ubuntu 16.04, Node version 8.7), but when deployed at live server (Debian OS, Node version 8.7), application is not working properly.
Problem is that when client's internet disconnects abruptly, or application is crushed, node server does not enter event-error, to remove the client from lobby. If client ends the socket connection gracefully, server calls event-end, event-disconnect, or event-close to remove the socket from lobby and close the socket as well.
NOTE: No issue is faced when same code runs on local server. On local server, when disconnection is abrupt, code enters in "error" event and removes the client from lobby list.
Kindly, help me out, as I might be missing some thing.
var tls = require('tls');
var fs = require('fs');
net = require('net');
var options = {
key : fs.readFileSync('/root/server.key'),
cert : fs.readFileSync('/root/server.cert')
};
// Keep track of devices
var clients = [];
var ip = [,];
var server = tls.createServer(options, function (socket) {
// Identify device
socket.name = socket.remoteAddress + ":" + socket.remotePort
socket.on('uncaughtException', function(er) {
console.error(er.stack);
socket.exit(1);
});
// Remove device from the list when connection dropped
socket.on('error', function(error_inappropriate) {
console.log('Device_Left: ', socket.name);
clients.splice(clients.indexOf(socket), 1);
console.log('Warning:', " " + socket.name + " inappropriate_con_closed. " + error_inappropriate.message);
});
socket.on('close', function() {
console.log('Event:', 'CLOSE event triggered, connection closed');
clients.splice(clients.indexOf(socket), 1);
});
socket.on('disconnect', function() {
console.log('Warning:', 'DISCONNECT event triggered, device disconnected');
clients.splice(clients.indexOf(socket), 1);
});
socket.on('end', function () {
clients.splice(clients.indexOf(socket), 1);
broadcast(socket.name + " left the chat.\n");
});
// Handle incoming messages from devices
socket.on('data', function (data) {
broadcast(socket.name + "says: " + data);
});
// Send a message to all devices
function broadcast(message, sender) {
clients.forEach(function (client) {
// Don't want to send it to sender
if (client === sender) return;
client.write(message);
});
}
}).listen(443);

Client can not see updated data when connects to server application

I'm using node.js to read data from socket on my web application (server). I receive data and make some changes on webpage (ex: change the color of polyline) but when a client after that changes connects, cannot see the changed color unless a new data is sent to server! So how client can see the previous changes which were on server?
here is my code
app.js
var http = require('http');
var express = require('express'),
app = module.exports.app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server); //pass a http.Server instance
server.listen(3000); //listen on port 80
app.use(express.static('public'));
app.get('/', function(req, res) {
res.sendFile(__dirname + '/index.html');
});
//var app = require('http').createServer(handler);
//var io = require('socket.io').listen(app);
var fs = require('fs');
var mySocket = 0;
//app.listen(3000); //Which port are we going to listen to?
function handler (req, res) {
fs.readFile(__dirname + '/index.html', //Load and display outputs to the index.html file
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
io.sockets.on('connection', function (socket) {
console.log('Webpage connected'); //Confirmation that the socket has connection to the webpage
mySocket = socket;
});
//UDP server on 41181
var dgram = require("dgram");
var server = dgram.createSocket("udp4");
server.on("message", function (msg, rinfo) {
console.log("Broadcasting Message: " + msg); //Display the message coming from the terminal to the command line for debugging
if (mySocket != 0) {
mySocket.emit('field', "" + msg);
mySocket.broadcast.emit('field', "" + msg); //Display the message from the terminal to the webpage
}
});
server.on("listening", function () {
var address = server.address(); //IPAddress of the server
console.log("UDP server listening to " + address.address + ":" + address.port);
});
server.bind(41181);
index.html
<html>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://192.168.1.14:3000');
socket.on('field', function (data) {
console.log(data);
$("#field").html(data);
switch(data)
{
case "1":
$("#path1").css("stroke", "red");
$("#progress1").css("backgroundColor", "red");
break;
}
});
</script>
<body>
<polyline id="path1" points="600,270 560,262 460,270 440,300" style="fill:none;stroke:green;stroke-width:3" />
</body>
</html>
On connection you have to emit already existing changes to socket client.
var myMessage;
io.sockets.on('connection', function (socket) {
console.log('Webpage connected'); //Confirmation that the socket has connection to the webpage
mySocket = socket;
mySocket.emit('field', "" + myMessage); // <<-- like this
server.on("message", function (msg, rinfo) {
console.log("Broadcasting Message: " + msg); //Display the message coming from the terminal to the command line for debugging
if (mySocket != 0) {
myMessage = msg;
mySocket.emit('field', "" + msg);
mySocket.broadcast.emit('field', "" + msg); //Display the message from the terminal to the webpage
}
});
});

Node.js / Socket Chat - Userlist

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);
});
});

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>

Categories

Resources