Raising a socket.io event from a Restify handler - node.js

I have a resitfy server and socketio server configured as per the example here.
My requirement is to raise a socket.io event from within a handler. So, my code looks like this:
var restify = require('restify');
var socketio = require('socket.io');
var server = restify.createServer();
server.get('/', function (req, res, next) {
res.json(204, null);
io.emit("sample", {"sample":"event"});
next();
});
server.listen(8080, function () {
console.log('socket.io server listening at %s', server.url);
});
My client code is pretty simple and looks like this:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Socket.IO Chat Example</title>
</head>
<body>
<script src="socket.io.js"></script>
<script type="text/javascript">
var socket = io.connect('http://localhost:8080');
socket.on('sample', function (data) {
console.dir(data);
});
</script>
</body>
</html>
When I start the server, the server exists after the first time a client connects and this is found in the logs:
socket.io:server initializing namespace / +0ms
socket.io:server creating engine.io instance with opts {"path":"/socket.io"} +3ms
socket.io:server attaching client serving req handler +1ms
socket.io server listening at http://0.0.0.0:8080
socket.io:server incoming connection with id U9hLZRlbsGfvI8QPAAAA +2s
socket.io:client connecting to namespace / +4ms
socket.io:namespace adding socket to nsp / +0ms
http.js:690
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (http.js:690:11)
at ServerResponse.format (/home/vagrant/socket.io-server-example/node_modules/restify/lib/response.js:109:10)
at ServerResponse.send (/home/vagrant/socket.io-server-example/node_modules/restify/lib/response.js:231:24)
at emitRouteError (/home/vagrant/socket.io-server-example/node_modules/restify/lib/server.js:152:13)
at onRoute (/home/vagrant/socket.io-server-example/node_modules/restify/lib/server.js:610:21)
at Router.find (/home/vagrant/socket.io-server-example/node_modules/restify/lib/router.js:512:5)
at Server._route (/home/vagrant/socket.io-server-example/node_modules/restify/lib/server.js:604:21)
at routeAndRun (/home/vagrant/socket.io-server-example/node_modules/restify/lib/server.js:572:14)
at Server._handle (/home/vagrant/socket.io-server-example/node_modules/restify/lib/server.js:592:9)
at Server.onRequest (/home/vagrant/socket.io-server-example/node_modules/restify/lib/server.js:255:14)
What I am not able to understand is, how can I serve REST API and socket.io events from the same port using restify?
Why does restify complain about not being able to set headers once they are sent?
Am I missing something fundamental here?

Try using using this example
Pass the result from listen method to socketio and then use the io instance to send those events on your handlers.
var restify = require('restify');
var server = restify.createServer();
var app = server.listen(8080, function() {
console.log('%s listening at %s', server.name, server.url);
});
var io = require("socket.io")(app);
function respond(req, res, next) {
res.send('hello ' + req.params.name);
io.emit('sample',{"data":"hello from server."});
next();
}
server.get('/hello/:name', respond);
server.head('/hello/:name', respond);
io.on('connection', function(socket){
console.log('new connection');
});

Related

Node SocketIo - Client not emitting?

I'm having issues with Node SocketIo client not emitting data. So when the client connects in the index.html does log the "Connected This Is A Test", however it does not socket.emit('cool'), no errors nor does it seem to log on server.js. I'm not sure why its not emitting or the server isnt listening.
Server.js
const path = require('path');
const http = require('http');
const express = require('express');
const socketio = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = socketio(server);
const PORT = 3002;
app.use(express.static(path.join(__dirname, 'public')));
// run when client connects
io.on('connection', () => {
console.log('New WS connection...');
io.emit('connection', 'This Is A Test');
});
io.on('cool', (msg) => {
console.log(msg);
});
server.listen(PORT, () => console.log(`server running on port ${PORT}`));
index.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title></title>
</head>
<body>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://' + document.domain + ':' + location.port);
socket.on('connection', function(data){
console.log("connected", data);
socket.emit('cool', 'MSG');
});
</script>
</body>
</html>
On your server, you need to be listening for the cool message on a specific connected socket, not on the io object. The io object does not have specific socket messages other than announcing a newly connected socket. To listen for messages from a specific socket, you need a listener on the connected socket itself. The usual place to add that listener is in the connection event where you are presented with the newly connected socket object.
So change this:
// run when client connects
io.on('connection', () => {
console.log('New WS connection...');
io.emit('connection', 'This Is A Test');
});
io.on('cool', (msg) => {
console.log(msg);
});
to this:
// run when client connects
io.on('connection', (socket) => {
console.log('New WS connection...');
// send a test event back to the socket that just connected
socket.emit('test', 'This Is A Test');
// listen for the cool message on this new socket
socket.on('cool', (msg) => {
console.log(msg);
});
});
Also, you really should not be emitting event names used by the system like connection. That's why I changed the event name to test so it won't conflict with names that socket.io itself is using.

Chat application using socket.io not connecting when deploying on production server

I am trying to implement chat application using nodejs and socket.io. The application works on localhost. But when I deploy same on my production server then socket.io can't make any connection.
Code for server.js
var express = require('express');
var app = express();
var socket = require('socket.io');
var chat_controller = require('./controllers/ChatController.js');
var user_controller = require('./controllers/UserController.js');
var Group_controller = require('./controllers/GroupChatController.js');
app.get('/search', function (req, res) {
user_controller.get(req, res);
});
app.get('/groupSearch', function (req, res) {
user_controller.get(req, res);
});
var server = app.listen(3600, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
});
var io = socket(server);
io.on('connection', (socket) => {
console.log('made socket connection', socket.id);
socket.broadcast.emit('userconnected');
chat_controller.respond(io, socket);
Group_controller.respond(io, socket);
user_controller.respond(io, socket);
});
io.on('disconnect', function () {
console.log('made socket disconnect', socket.id);
});
Code for client.js
var socket = io.connect('https://www.mywebsite.com', {
path: '/apichat'
});
/* Other events related to socket. */
As my server uses SSL I can't used IP:PORT directly so I am using ProxyPass as
ProxyPass /apichat http://127.0.0.1:3600
After all this still socket connection is not established between server and client.
Error shown in browser console is:
POST https://www.mywebsite.com/apichat/?EIO=3&transport=polling&t=MUc-TJK 404 (Not Found)
And in browser Network tab it shows:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot POST /</pre>
</body>
</html>
I have checked many other questions posted here and other sites but no question address this issue.
Please Help.
The issue you are encountering is probably due to ssl enabled on your website.
You need to pass ssl related files in your app.js file. Sample code for this is as follow:
var fs = require('fs');
var options = {
key: fs.readFileSync('PATH_TO_SSL_KEYS.key'),
cert: fs.readFileSync('PATH_TO_SSL_CERTS.crt'),
ca: fs.readFileSync('PATH_TO_SSL.pem')
};
var app = require('https').createServer(options, handler), io = require('socket.io').listen(app);
io.set('transports', [
'websocket',
'flashsocket',
'htmlfile',
'xhr-polling',
'jsonp-polling',
'polling'
]);
function handler(req, res) {
res.writeHead(200);
res.end("welcome sir!");
}
var chat_controller = require('./controllers/ChatController.js');
var user_controller = require('./controllers/UserController.js');
io.sockets.on('connection', function (socket) {
socket.broadcast.emit('userconnected');
chat_controller.respond(io, socket);
user_controller.respond(io, socket);
socket.on('message', function (data) {
socket.broadcast.emit('message', data);
});
});
io.on('disconnect', function (socket) {
console.log('made socket disconnect', socket.id);
});
app.listen(3300);
Try editing your application file as per above mentioned sample code and then try to use it. If you can't get path to ssl related file, then you need to contact either your system administrator or the hosting provider.
I hope it helped.

node-http-proxy load balance websocket error

I have just started evaluating the node-http-proxy because I need to have a scalable web socket server.
I have tested the ’simple-balancer-with-websockets’ example provided in the repository but it does not work when acting as a proxy to multiple addresses. It only works as a proxy for one address!
When proxying to multiple addresses a WebSocket hangup error as follows:
Error: socket hang up
at createHangUpError (http.js:1472:15)
at Socket.socketOnEnd [as onend] (http.js:1568:23)
at Socket.g (events.js:180:16)
at Socket.EventEmitter.emit (events.js:117:20)
at _stream_readable.js:920:16
at process._tickCallback (node.js:415:13)
I am using:
node 0.10.26
socket io 1.0.6
node-http-proxy 1.1.5
platform OSX
The following is the load-balancer. Its only difference to the provided sample is the addresses used and the listen port.
var http = require('http'),
httpProxy = require('http-proxy');
//
// A simple round-robin load balancing strategy.
//
// First, list the servers you want to use in your rotation.
//
var addresses = [
{
host: 'localhost',
port: 8000
},
{
host: 'localhost',
port: 8001
},
{
host: 'localhost',
port: 8002
}
];
//
// Create a HttpProxy object for each target
//
var proxies = addresses.map(function (target) {
return new httpProxy.createProxyServer({
target: target
});
});
//
// Get the proxy at the front of the array, put it at the end and return it
// If you want a fancier balancer, put your code here
//
function nextProxy() {
var proxy = proxies.shift();
proxies.push(proxy);
return proxy;
}
//
// Get the 'next' proxy and send the http request
//
var server = http.createServer(function (req, res) {
nextProxy().web(req, res);
});
//
// Get the 'next' proxy and send the upgrade request
//
server.on('upgrade', function (req, socket, head) {
nextProxy().ws(req, socket, head);
});
server.listen(9000);
The basic http server acting as a target for the above load-balancer is:
var http = require('http'),
fs = require('fs'),
io = require('socket.io');
var args = process.argv.splice(2);
var port = args[0] || 8000;
server = http.createServer(function(req, res) {
var filePath = (__dirname + '/public/connect.html');
fs.readFile(filePath,function (err, data){
res.writeHead(200, {'Content-Type': 'text/html','Content-Length':data.length});
res.write(data);
res.end();
});
});
server.listen(port, function() {
console.log('ws listening on: ' + port);
});
io = io(server);
io.on('connect', function(socket){
console.log('socket connected');
socket.emit('message', 'ws message from ' + port);
});
The client html is:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
socket.on('message', function (data) {
console.log(data);
});
</script>
</head>
<body>
node-http-proxy basic load balance test with websockets
</body>
</html>
I regard this as a basic test and yet it does not work! Can anyone explain what I am doing wrong and suggest a solution please?
Many thanks for any thoughts.
Socket.io 1.0 needs sticky sessions. See socket.io/docs/using-multiple-nodes
First engine.io makes an xhr request then it makes an websocket request. Both requests need to reach the same socket.io server. Even more so if engine.io needs to fallback to long polling etc . . .
To fix it, you just need to make your proxy server session aware. It can still round robin fresh connections, but as soon as it serves a socket.io request it needs to route subsequent requests from that session to the same backend.

Can’t connect to node.js server on client side

I’m having a problem getting started with Node.js.
I’ve created a basic server that I know works, because if I navigate to http://localhost:5000 in my browser I get the expected message. However, I’m having trouble then connecting to this server on the client side with a basic HTML page.
My Node.js app looks like this:
var http = require('http');
var socket = require('socket.io');
var port = process.env.PORT || 5000;
var players;
var app = http.createServer(function(request, response) {
response.write('Server listening to port: ' + port);
response.end();
}).listen(port);
var io = socket.listen(app);
function init() {
io.configure(function() {
io.set('transports', [ 'xhr-polling' ]);
io.set('polling duration', 10);
});
io.sockets.on('connection', onSocketConnection);
};
function onSocketConnection(client) {
console.log('New connection');
console.log(client);
};
init();
My HTML page looks like this (based on https://github.com/mongolab/tractorpush-server/blob/master/index.html):
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('/');
socket.on('all', function(data) {
console.log(data);
});
socket.on('complex', function(data) {
console.log(data);
});
</script>
</body>
</html>
I understand that the sockets.io.js file is automatically generated by socket.io, but I just get the following error when I view my index.html file:
Uncaught ReferenceError: io is not defined
How do I actually connect to my server?

Connect to node.js socket.io server: clients don't connect - server reports" destroying non-socket.io upgrade"

I thought that socket.io would allow me to implement a websocket server. I have this very simple code:
// Require HTTP module (to start server) and Socket.IO
var http = require('http'), io = require('socket.io');
// start at port 8888
var server = http.createServer(function(req, res) {
res.writeHead(200,{'Content-Type': 'text\html'});
res.end('<h1>Welcome to the Notification Server</h1>');
});
server.listen(8888);
// Create Socket.io obj/pass to server
var socket = io.listen(server);
socket.on('connection', function(client) {
console.log('Successful Websocket connection!');
client.on('message', function(event) {
console.log("Received message from client", event);
});
client.on('disconnect', function() {
console.log('Client has disconnected');
});
});
I've tried a few different test clients all of which generate this message on the server: debug - destroying non-socket.io upgrade
One such client attempt has some code like this:
<html>
<script type="text/javascript">
<!---
window.WebSocket = window.WebSocket || window.MozWebSocket;
var ws = new WebSocket("ws://dev.ourserver.com:8888");
ws.onopen = function() {
alert("Connected");
}
ws.onerror = function(error) {
alert("Error:"+error);
}
// -->
</script>
<body>
</body>
</html>
As soon as we load the page I get the debug message on the server.
I thought the point of this library was to support the websocket protocol and any client supporting websockets would be able to connect.
If I interpret the message literally it seems to indicate that server.io has detected that it is connecting to a "non socket.io" client. Does this mean that there is no way for me to connect to this server without using socket.io in the client?

Resources