How to emit event with Socket.io and Node.js? - javascript

I find it hard to emit an event because I don't know much about creating an event/emitting an event with socket IO.
Here is my problem on CASE "/publish":
var app = http.createServer(function (req, res) {
if (req.method == "OPTIONS") {
res.header('Access-Control-Allow-Origin', '*:*');
res.send(200);
} else {
var u = url.parse(req.url,true),
body = '';
req.on('data',function(chunk) {
body += chunk;
});
req.on('end',function() {
if(body) {
var data =JSON.parse(body);
if(data._app_secret && data._app_secret == 'nonexistent') {
switch(u.pathname) {
case '/generateusersecret' :
findTokenByUser(req.headers.host+'_'+data.user_id,function(reply) {
if(reply) {
jsonResponse(res,{userSecret : reply});
} else {
generateToken(req.headers.host + '_' + data.user_id,data.user_id,res);
}
});
break;
case '/getusersecret' :
findTokenByUser(req.headers.host + '_' + data.user_id,function(reply) {
jsonResponse(res,{userSecret : reply});
console.log(reply);
});
break;
case '/publish':
if(data.type == 'notification'){
var newData = {
item_id : data.item_id,
message : data.message,
recipient : data.channel,
itemLink : data.itemLink,
timestamp : data.timestamp,
read : 0
}
notification = JSON.stringify(newData);
// I need to emit my event here
Socket.emit(THE EVENT HERE,notification DATA)
}
break;
default:
jsonResponse(res,{error : "Unknown Command: " + u.pathname});
break
}
} else {
res.writeHead(403, {'Content-Type': 'text/plain'});
res.end('Not authorized');
}
}
});
}
});
app.listen(config.port || 4000, null);
Then I need to listen on:
io.sockets.on('connection'function(socket){
socket.on('THE EVENT HERE',function(NOTIFICATION DATA){
//I NEED TO EMIT ANOTHER EVENT HERE
})
})
Is there a possible way for this? I have to do this because I am using PHP's cURL and I can't emit on client side so I need to emit it on server side.

It seems you need to emit an event from the server-side, this is possible and the main feature from socket.io.
To broadcast to all connected sockets use this code in the /publish endpoint:
io.sockets.emit('event', data);
Socket.io can also broadcast messages to group of sockets, this feature is called rooms.
If you want to send a message to only one socket, you can mark the sockets with an extra property when they connect and then search those sockets in the list of connected sockets.
Complete example:
Server side (server.js):
var http = require('http');
var fs = require('fs');
var server = http.createServer(handler);
var io = require('socket.io').listen(server);
function handler (req, res) {
if (req.url === '/') {
return fs.createReadStream(__dirname + '/index.html').pipe(res);
}
if (req.url === '/publish' && req.method === 'POST') {
//this is what you are looking for:
io.sockets.emit('super event', { message: 'hello' });
//---------------------------------
res.writeHead(200, {
'Location': '/'
});
return res.end('');
}
}
io.sockets.on('connection', function (socket) {
socket.on('publish', function (data) {
//if you need to emit to everyone BUT the socket who emit this use:
//socket.broadcast.emit('super event', data);
//emit to everyone
io.sockets.emit('super event', data);
})
});
server.listen(1080, function () {
console.log('listening on http://localhost:1080');
});
Client side (index.html):
<html>
<head>
</head>
<body>
hello world.
<form action="/publish" method="post">
<input type="submit" value="send a notification"></input>
</form>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('/');
socket.on('super event', function (data) {
console.log(data);
alert('got a message!');
});
</script>
</body>
</html>
Usage
Put these two files in one directories.
npm i socket.io
node server.js
open two tabs in the browser pointing to http://localhost:1080
click the send notification button in one of the tabs

Related

unable to create simple websocket - NodeJS

I am trying to follow this tutorial: https://www.simonewebdesign.it/101-web-socket-protocol-handshake/ for developing simple websocket protocol.
I am visiting localhost:1337/index.html but I get:
This localhost page can’t be found
No web page was found for the web address: http://localhost:1337/index.html
Search Google for localhost 1337 index
HTTP ERROR 404
if I visit this url: file:///C:/Users/.../websocket-demo/index.html
I atleast see the index.html page being rendered. But in console I get this error:
WebSocket connection to 'ws://localhost:1337/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
I am not sure what's wrong?
I have 3 files: index.html, server.js and client.js
server.js
#!/usr/bin/env node
var WebSocketServer = require('websocket').server;
var http = require('http');
var server = http.createServer(function(request, response) {
console.log('Received request from ' + request.url);
response.writeHead(404);
response.end();
});
server.listen(1337, function() {
console.log('Server is listening on port 1337.');
});
wsServer = new WebSocketServer({
httpServer: server,
autoAcceptConnections: false // because security matters
});
function isAllowedOrigin(origin) {
console.log('Connection requested from origin ' + origin);
valid_origins = [
'http://localhost:8080',
'127.0.0.1',
'null'
];
if (valid_origins.indexOf(origin) != -1) {
console.log('Connection accepted from origin ' + origin);
return true;
}
console.log('Origin ' + origin + ' is not allowed.')
return false;
}
wsServer.on('connection', function(webSocketConnection) {
console.log('Connection started.');
});
wsServer.on('request', function(request) {
var connection = isAllowedOrigin(request.origin) ?
request.accept('echo-protocol', request.origin)
: request.reject();
connection.on('message', function(message) {
var response = '';
console.log('Received Message: ' + message.utf8Data);
if (message.type === 'utf8') {
switch (message.utf8Data) {
case 'hi':
response = 'Hey there';
break;
case 'hello':
response = 'Heya!';
break;
case 'xyzzy':
response = 'Nothing happens.';
break;
case 'desu':
response = 'Keep typing, man. Keep typing.';
break;
default:
response = "Hello. Uh... what am I supposed to do with '" +
message.utf8Data + "'?";
}
connection.sendUTF(response);
}
});
connection.on('close', function(reasonCode, description) {
console.log(connection.remoteAddress + ' has been disconnected.');
});
});
client.js
(function () {
var ws = new WebSocket('ws://localhost:1337', 'echo-protocol');
ws.onopen = function (event) {
console.log('Connection opened.');
}
ws.onmessage = function (event) {
console.log('Response from server: ' + event.data);
}
ws.onclose = function (event) {
console.log('Connection closed.');
}
ws.onerror = function (event) {
console.log('An error occurred. Sorry for that.');
}
WebSocket.prototype.sendMessage = function (message) {
this.send(message);
console.log('Message sent: ' + message);
}
document.getElementById('send').addEventListener('click', function (event) {
event.preventDefault();
var message = document.getElementById('message').value;
ws.sendMessage(message);
});
})();
index.html - consist of forms
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>WebSocket Client Demo</title>
</head>
<body>
<h1>WebSocket Client</h1>
<form>
<label for="message">Send a message</label>
<input id="message" name="message" type="text">
<button id="send" name="send">Send</button>
</form>
<script src="client.js"></script>
</body>
</html>
Your web server doesn't serve your index.html file.
You can see this post to get an idea how to serve static files, or you can just boot up another HTTP server to serve your index file, like with python, the way they suggested in the README file of the tutorial that you are following: https://github.com/simonewebdesign/websocket-demo

How to post data from my html page to a listener?

I'm currently designing a UI for an Automated Parking System. I currently need to test if my page sends out data from a form by sending it to a listener. I currently have this code but I'm not sure why it isn't working. Any help would be greatly appreciated.
This is my code that sends the data to a local listener.
<script>
var INPARK = {cardID: $("#ticket_num").val(), lift: 1, floor: 1};
$.ajax({
type:"POST",
url: '192.168.150.148:5007',
contentType:"application/json",
data: JSON.stringify(INPARK)
});
</script>
This is the listener code.
var HOST = '192.168.150.148'; // This should be your IP of 192.168.150.XXX
var PORT = 5007;
var http = require('http');
http.createServer(function (req, res) {
// Only listen for POST requests
if (req.method === 'POST') {
var buffer = '';
req.on('data', function (chunk) {
buffer += chunk;
});
req.on('end', function () {
var path = req.url.substring(0, req.url.indexOf('/', 1)).toUpperCase();
var json;
try {
json = JSON.parse(buffer);
} catch (err) {
//
}
if (path === '/INPARK') {
// Handle INPARK request
console.log(json);
res.write('inpark results');
} else if (path === '/OUTPARK') {
// Handle OUTPARK request
console.log(json);
res.write('outpark results');
} else {
// Do nothing - Bad request
res.write('BAD REQUEST');
}
// Close the connection
res.end();
});
}
}).listen(PORT, HOST, function () {
console.log('Listening at %s:%s', HOST, PORT);
});
Your ajax request is most likely going from port 80 or 443 to 5007, which is a cross domain request, hence it will fail,
If you want to resolve this issue, read up on CORS:
https://en.wikipedia.org/wiki/Cross-origin_resource_sharing,
and JSONP:
https://en.wikipedia.org/wiki/JSONP

io.connect: io is not defined but socket.io is loaded

I have built a node.js server that provides a client.html page with a list of messages from a mysql db. I can't make it work using an ajax call.
The client.html page is this:
<time></time>
<div id="container">Loading ...</div>
<script src="http://oclock.dyndns.org:8000/socket.io/socket.io.js"></script>
<!--<script src="socket.io/socket.io.js"></script>-->
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
// create a new websocket
var socket = io.connect('http://oclock.dyndns.org:8000');
// on message received we print all the data inside the #container div
socket.on('notification', function (data) {
var msgs = '<div>';
$.each(data.flashmsgs,function(index,flashmsg){
msgs += "<b>Messaggio inviato da " + flashmsg.created_by + "</b><br>";
msgs += flashmsg.testo;
});
msgs += '</div>';
$('#container').html(msgs);
$('time').html('Last Update:' + data.time);
});
</script>
and the code for the ajax call is the following:
(function nodeLoader(){
$.ajax({
url: "client.html",
method: "get",
data: {hk: hk },
success: function(data){
$('#messaggi').html(data);
}
});
})();
The socket.io code is loaded but I get an error on io.connect: io is not defined. Same issue if i change the url from client.html to http://oclock.dyndns.org:8000 (the url of the node.js server that is listening for requests).
Any help is appreciated!
EDIT:
server.js
var hwkey;
var app = require('http').createServer(handler),
io = require('socket.io').listen(app),
url = require('url'),
fs = require('fs'),
mysql = require('mysql'),
connectionsArray = [],
connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'flipper',
database: 'oclock',
port: 3306
}),
POLLING_INTERVAL = 3000,
pollingTimer;
// If there is an error connecting to the database
connection.connect(function(err) {
// connected! (unless `err` is set)
if (err) {
console.log(err);
}
});
// creating the server ( localhost:8000 )
app.listen(8000);
function handler(req, res) {
var origin = (req.headers.origin || "*");
if (req.method.toUpperCase() === "OPTIONS"){
res.writeHead(
"204",
"No Content",
{
"access-control-allow-origin": origin,
"access-control-allow-methods": "GET, POST, PUT, DELETE, OPTIONS",
"access-control-allow-headers": "content-type, accept",
"access-control-max-age": 10, // Seconds.
"content-length": 0
}
);
return( res.end() );
}
console.log("INCOMING REQUEST: "+req.method+" "+req.url);
req.parsed_url = url.parse(req.url, true);
var getp = req.parsed_url.query;
hwkey = getp.hk;
fs.readFile(__dirname + '/client.html', function(err, data) {
if (err) {
console.log(err);
res.writeHead(500);
return res.end('Error loading client.html');
}
res.writeHead(
200,
{
"access-control-allow-origin": origin,
"content-length": data.length
}
);
res.end(data);
});
}
function pollingLoop(){
// Doing the database query
var query = connection.query('SELECT id, testo, created_by FROM flashmsgs WHERE hwk="'+hwkey+'" AND letto="0"'),
//var query = connection.query('SELECT max(id), testo, created_by FROM flashmsgs'),
flashmsgs = []; // this array will contain the result of our db query
// setting the query listeners
query
.on('error', function(err) {
// Handle error, and 'end' event will be emitted after this as well
console.log(err);
updateSockets(err);
})
.on('result', function(flashmsg) {
// it fills our array looping on each user row inside the db
flashmsgs.push(flashmsg);
})
.on('end', function() {
// loop on itself only if there are sockets still connected
if (connectionsArray.length) {
pollingTimer = setTimeout(pollingLoop, POLLING_INTERVAL);
updateSockets({
flashmsgs: flashmsgs
});
} else {
console.log('The server timer was stopped because there are no more socket connections on the app')
}
});
};
// creating a new websocket to keep the content updated without any AJAX request
io.sockets.on('connection', function(socket) {
console.log('Number of connections:' + connectionsArray.length);
// starting the loop only if at least there is one user connected
if (!connectionsArray.length) {
pollingLoop();
}
socket.on('disconnect', function() {
var socketIndex = connectionsArray.indexOf(socket);
console.log('socketID = %s got disconnected', socketIndex);
if (~socketIndex) {
connectionsArray.splice(socketIndex, 1);
}
});
console.log('A new socket is connected!');
connectionsArray.push(socket);
});
var updateSockets = function(data) {
// adding the time of the last update
data.time = new Date();
console.log('Pushing new data to the clients connected ( connections amount = %s ) - %s', connectionsArray.length , data.time);
console.log(hwkey);
// sending new data to all the sockets connected
connectionsArray.forEach(function(tmpSocket) {
tmpSocket.volatile.emit('notification', data);
});
};
console.log('Please use your browser to navigate to http://localhost:8000');
Okay, I misunderstood at first. I just investigated your live app and it appears your ajax call is pulling down an entire html document.
If you're loading markup via ajax and then inserting into the existing page, you don't want a full HTML document. Just send down the body content.
Also, the socket.io script reference should ideally be on the parent page, not the page loaded via ajax.

Connections are duplicationg in Socket.io

I'm developing a chat app, and the connections are duplicating.
In my route, I have:
exports.index = function (io) {
return function (req, res) {
var userId;
res.render('index', {
title: 'RandomChat.me',
test: 'test2'
});
io.sockets.on('connection', function (socket) {
userId = socket.id;
console.log("+++++++++++++++++++" + userId);
socket.emit('addUser', { userId: userId });
socket.room = 'General';
socket.join(socket.room);
socket.on('sendMessage', function (data) {
console.log(data.room);
// socket.broadcast.emit('receiveMessage', { data: data });
socket.broadcast.to(data.room).emit('receiveMessage', { message: data.message });
});
});
}
};
Client-side something like:
var socket = io.connect('http://domain.com:3000');
var userId;
socket.on('addUser', function(data) {
userId = data.userId;
console.log(userId);
});
socket.on('receiveMessage', function (data) {
console.log(data);
});
var room: "General";
var message: "Test";
socket.emit('sendMessage', { room : room, message: message });
console.log(userId + " " + message)
If I go to the app and check the console log, I see the userId, and when I reload the page, I see the same ID's twice, if I reload again, I see it 3 times and so on.
The same thing is happening in the node.js console.
So basically when connections/users are duplicated, the other users receive duplicate messages, as the sendMessage/receiveMessages functions are run more than once.
Help appreciated.
The problem is this line
io.sockets.on('connection', function (socket) {
You should not put these inside a request handler because its just wrong to add a connection handler for socket for each request. Try doing these outside the request handler and use the io object to emit/broadcast events to sockets from the request handler.
Using io.sockets.once('connection', function (data){}) instead of io.sockets.on('connection', function (data){}) fixed it. It doesn't try to recover a lost connection.

How to push changes in a database to the client using socket.io?

I am working on an app which, among other things, pushes data to the client when an updation occurs on the database. The trouble is that the websocket on node.js listens to the databse on a different port then the node. The guy before me wrote a piece of code and then dumped it on me. The node looks somewhat like this:
var handler=http.createServer(function(req, res){
session(req, res, function(req, res, body) {
if (!req.session || !req.session.data || !req.session.data.uid || req.session.data.uid == '' || !req.session.data.role || req.session.data.role =='') {
var uri = url.parse(req.url).pathname;
if(req.method == 'GET' && uri =="/attendance-node/getMonthFromReport") {
var uri = url.parse(req.url).pathname;
var url_parts = url.parse(req.url,true);
processgetMonthFromReport(req, res, uri, url_parts.query);
return;
}
res.writeHead(401, {"Content-Type": "text/plain"});
res.write("401 Unauthorized");
res.end();
return;
}
if(req.method == 'POST') {
var uri = url.parse(req.url).pathname;
var qs = require('querystring');
var POSTVAR = qs.parse(body, '&', '=', {"maxKeys" : 0});
//var POSTVAR=JSON.parse(body);
handleRequest(req, res, uri, POSTVAR);
}
if (req.method=='GET') {
var uri = url.parse(req.url).pathname;
var url_parts = url.parse(req.url,true);
handleRequest(req, res, uri, url_parts.query);
}
});
}).listen(3014,"127.0.0.1");
var io = require('socket.io').listen(8077,"127.0.0.1");
sys.puts("websocket Server running on port 8077");
io.configure(function () {
io.set('transports', ['websocket', 'flashsocket', 'xhr-polling','jsonp-polling']);
io.set('log level', 0);
});
io.sockets.on('connection', function (socket) {
io.sockets.emit('init',"i am working via websocket");
});
As you can see the node is listening on 3014 and the socket on 8077. Now how am I suppossed to provide an handler for the message received on the socket and forward it to the node's client?
Note: I am fairly new to web development. So basically I was thrown in the water and now I am learning to swim.
P.S. Also, what would the client side of the socket look like?
P.P.S. The database sending update notification to the socket is already taken care of. It comes as a POST request.
Thanx in advance!!
It sounds like you want to have socket.io also on the client side (browser?) as well.
I'd say the best solution would be to have socket.io run on the same port as your web server. However, if it this not possible and you must keep the web socket that the database uses separate from the web server you could run two instances of socket.io.
One would be attached to the web server, and the other would be for the database.
var app = require('http').createServer(handler)
, IO = require('socket.io')
, web_io = IO.listen(app)
, data_io = IO.listen(8080)
, fs = require('fs')
app.listen(80);
function handler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
web_io.sockets.on('connection', function (socket) {
socket.on('some_event', function (data) {
console.log(data);
});
});
data_io.sockets.on('connection', function (socket) {
socket.on('database_update', function (data) {
// Will be sent to everyone socket listening on port 80 (browser sockets mostlikely)
web_io.sockets.emit('database_update', data);
});
socket.on('disconnect', function () {
io.sockets.emit('user disconnected');
});
});

Categories