Azure Mobile Service - Socket.IO integration - azure

I have problem with creating Azure Mobile Services Custom Script, I want to use Socket.IO Node.js module, but I don't know how to edit Azure Mobile Services route to be able to access /socket.io/1
After execution this code socket.io is started but client is not able to access URL endpoint from browser, please help me, thank you in advance, my email is: stepanic.matija#gmail.com
My code is:
in /api/notify
exports.register = function (api) {
api.get('socket.io',getSocketIO);
};
function getSocketIO(req,res)
{
var app = require('express')()
, server = require('http').createServer(app)
, io = require('socket.io').listen(server);
server.listen(80);
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
res.send(statusCodes.OK, { message : '23 Hello World!', bla: 'bla2' });
}

Support for Socket.IO has been added using startup script extension
var path = require('path');
exports.startup = function (context, done) {
var io = require('socket.io')(context.app.server);
io.on('connection', function(socket){
socket.on('chat message', function(msg){
io.emit('chat message', msg);
});
});
context.app.get('/public/chat.html', function(req, res) {
res.sendfile(path.resolve(__dirname, '../public/chat.html'));
});
done();
}
For details see: http://azure.microsoft.com/blog/2014/08/26/how-to-use-socket-io-with-azure-mobile-service-node-backend/

Socket.io is not currently supported.
In may be possible to get it working, but you would need to do this code inside of your mobile services startup script, http://blogs.msdn.com/b/azuremobile/archive/2014/01/14/new-startup-scripts-preview-feature-in-azure-mobile-services.aspx, using the App object provided there.
You'd also need to update the routes on it so your routes are picked up before the mobile service ones.

#stepanic, you might try bundling the Socket.io client as a static file. Here's how we do it in Sails for reference:
From the docs:
<!-- .... -->
</body>
<script type="text/javascript" src="./path/to/bower_components/sails.io.js"></script>
<script type="text/javascript">
// `io` is available as a global.
// `io.socket` will connect automatically, but it is not ready yet (think of $(document).ready() from jQuery).
// Fortunately, this library provides an abstraction to avoid this issue.
// Requests you make before `io` is ready will be queued and replayed automatically when the socket connects.
// To disable this behavior or configure other things, you can set properties on `io`.
// You have one cycle of the event loop to change `io` settings before the auto-connection behavior starts.
io.socket.get('/hello', function serverResponded (body, sailsResponseObject) {
// body === sailsResponseObject.body
console.log('Sails responded with: ', body);
console.log('with headers: ', sailsResponseObject.headers);
console.log('and with status code: ', sailsResponseObject.statusCode);
});
</script>
</html>

Related

Socket.IO rooms not working on Azure, but working locally

I made a simple app with socket.io and node.js, it is a push notification service.
When a user connects to the websocket, sends his username (and the name of dashboard) and immediately joins to a room named as the user. The application listens for POST request, saves them and then emits a message to the user's room.
io.on('connection', function(socket) {
socket.on('userid', function(data) {
socket.join(data.userid+'-'+data.dashboard);
notification.find({userid: data.userid, to: data.dashboard, received_by_user: false}, function(err, notifs) {
socket.emit('get_notifications', notifs);
}
}
});
app.post('/notify', function(req, res, next) {
var notif_recv = new notification(req.body);
notif_recv.save(function (err, notif_recv) {
io.sockets.in(notif_recv.userid+'-'+notif_recv.dashboard).emit('new_notification', notif_recv);
});
res.send(200);
});
When I test it with node locally, it works fine, I send a POST to /notify and I can see the notification arriving at the dashboard. The problem is, when I test on an AppService on Azure, the client connects to the websocket and receives the first notifications (get_notifications event), but when I POST to /notify, the client doesn't receives anything! (no new_notification event, io.sockets.in(...).emit(...) doesnt seems to work on Azure).
For debugging purposes, I used console.log(...) to log at the server the returned value of functions socket.join(...) and io.sockets.in(...).emit(...), resulting that io.socket.in(...).emit(...) seems to return a io server without any channels and connections!
IIS could be messing with it? I tend to think that IIS have different processes for app.post('/notify'... and io.on('connection'... so, the socket I am referencing on app.post is DIFFERENT from I am joining the user in io.on('connection'.. (socket.join(...)).
Any tip when using socket.io rooms in Azure/IIS?
Thanks!
Did you try adding a 'disconnect' handler for debugging?
io.on('connection', function (socket) {
socket.on('disconnect', function(){ //add this part
console.log('Client disconnected');
});
socket.emit('get_notifications', "get_notifications_:"+new Date());
});
Also log at every emit and receive, so that you know when the client gets disconnected exactly. If its getting disconnected after the get_notifications event, make sure you are not sending a callback to the client or that the client is not expecting a callback from the server.
I notice some missing closing braces for the notification.find(..) and socket.on('userid'..). I hope that is only in the code that you pasted here.
To test the socket.io and POST issue on Azure App Services, I simplify the project and test on Azure.
The test server.js:
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var bodyParser = require('body-parser')
app.use( bodyParser.json() ); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
server.listen(process.env.PORT ||3000, function(){
console.log('listening on *:3000');
});
app.get('/', function (req, res) {
res.sendfile(__dirname + '/client.html');
});
app.post('/notify', function(req, res, next) {
io.sockets.emit('new_notification', req.body);
res.send(200);
});
io.on('connection', function (socket) {
socket.emit('get_notifications', "get_notifications_:"+new Date());
});
The client content:
<body>
<script src="/socket.io/socket.io.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script>
var socket = io();
$.post("/notify",{
msg:"notification from client"
});
socket.on('get_notifications',function(msg){
console.log(msg);
});
socket.on('new_notification',function(msg){
console.log(msg);
});
</script>
</body>
And this simple project works fine on Azure App Services.
So it could be some other part of your application which raise your issue.
You can check the Diagnostics Logs or leverage Visual Studio Team Services to troubleshooting the issue. Refer to the answer of How to run django manage.py command on Azure App Service for how the enable the Team Services extension on Azure App Services.
Any further concern, please feel free to let me know.

How do I connect two Socket.io servers/apps?

I'm trying to build an application that has two components. There's a public-facing component and an administrative component. Each component will be hosted on a different server, but the two will access the same database. I need to set up the administrative component to be able to send a message to the public-facing component to query the database and send the information to all the public clients.
What I can't figure out is how to set up a connection between the two components. I'm using the standard HTTP server setup provided by Socket.io.
In each server:
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, 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);
});
}
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
And on each client:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost');
socket.on('news', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});
</script>
I've looked at this question but couldn't really follow the answers provided, and I think the situation is somewhat different. I just need one of the servers to be able to send a message to the other server, and still send/receive messages to/from its own set of clients.
I'm brand new to Node (and thus, Socket), so some explanation would be incredibly helpful.
The easiest thing I could find to do is simply create a client connection between the servers using socket.io-client. In my situation, the admin server connects to the client server:
var client = require("socket.io-client");
var socket = client.connect("other_server_hostname");
Actions on the admin side can then send messages to the admin server, and the admin server can use this client connection to forward information to the client server.
On the client server, I created an on 'adminMessage' function and check for some other information to verify where the message came from like so:
io.sockets.on('connection', function (socket) {
socket.on('adminMessage', function (data) {
if(data.someIdentifyingData == "data") {
// DO STUFF
}
});
});
I had the same problem, but instead to use socket.io-client I decided to use a more simple approach (at least for me) using redis pub/sub, the result is pretty simple. My main problem with socket.io-client is that you'll need to know server hosts around you and connect to each one to send messages.
You can take a look at my solution here: https://github.com/alissonperez/scalable-socket-io-server
With this solution you can have how much process/servers you want (using auto-scaling solution), you just use redis as a way to forward your messages between your servers.

Access is forbidden for Node.js

I am trying to create a simple chat application using Node js. I am using a Windows operating system. As local server I am using Xampp. I have installed Node. I have also installed socket.io using package.json. The code in package.json is given below.
{
"name":"chat",
"version":"0.0.1",
"private":"true",
"dependencies":{
"socket.io":"0.9.16",
"express":"3.4.0"
}
}
Then I have written the code for the server. The Node server is running in port 1337. The code for the server is given below.
var io = require('socket.io').listen(1337);
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
Then when I run it, it is running. Then I have written the code for the client in a index.php file. The code for the client is given below.
<!DOCTYPE html>
<html>
<head>
<title>Chat app.</title>
</head>
<body>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="/node:1337/socket.io/socket.io.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var socket = io.connect('http: // localhost / node : 1337');
socket.on('news', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});
});
</script>
</body>
</html>
But when I try to the run it with a browser, all I get see in the console is that access is forbidden. All my files including node_modules is saved in C:\xampp\htdocs\node.
The code you're using is copied from the socket.io Home page and it's only used as an example, but it's not actually working code because the socket.io script isn't being bound to any server instance.
Socket.io isn't a server. It's just a library for nicely handling Websockets. In order to use socket.io you have to require HTTP or Express and create a server instance. Then you'll have to bind the server instance with socket.io.
For a working implementation on how to get socket.io up and running with your server, you'll have to look at the How To Use page. There they have these nice code example, depending on the implementation you're running (if it's HTTP, or something else).
So scratch the whole Xampp server idea. Node has it's own built in server capabilities and that's what you're meant to be using.
Here's a working example (from the socket.io website) of how Socket.io is meant to be used with HTTP. In this code snippet, the server is also created (and it's listening on port 80), so you won't have to worry about that:
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, 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);
});
}
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
Once your server's up and running, you can access it by typing localhost:80 into the browser.

Can't find socket.io for client when server is created without handler

Browser can't find socket.io.js for client:
<script src="/socket.io/socket.io.js"></script>
When server is created without handler:
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, fs = require('fs');
app.listen(80);
//without this part:
/*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);
});
}*/
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
I don't need and don't want handler function because everything I generate in PHP. And sometimes use client application functions for another file than index.html/php
So how to make browser can find socket.io.js?
I've wrote a demo app that you could have a look at if you don't want to loose to much time getting started with socket.io and Express 3.
To have websockets working your client js needs to be delivered from a webserver. This is one of those many browser limitation.
The easiest setup is to have a node server that provide both the client side Js and the WebSockets. Using easier the http module of Express (a bit overkill but super practical if you want to build something more than just a test app).
Other wise you need to have your client side js pointing to the right place. For example if you run your socket.io server of port 8080 and you deliver your static client side on port 8000 (using python -m SimpleHTTPServer for example or port 80 using a regular apache).
<script src="http://localhost:8080/socket.io/socket.io.js"></script>
If you don't need access to http module functionality use this way:
var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
Include this on your client side !
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
var io = io.connect();

Browser can't get socket.io.js file using express

I have problem with socket.io examples. My browser can't get socket.io.js file (404 error in console).
Code that work:
server.js
var app = require('express').createServer()
, io = require('socket.io').listen(81);
app.listen(80);
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
index.html
<script src="http://192.168.1.104:81/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://192.168.1.104:81');
socket.on('news', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});
</script>
But this one not:
server.js
var app = require('express').createServer()
, io = require('socket.io').listen(app);
app.listen(80);
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
index.html
<script src="http://192.168.1.104:80/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://192.168.1.104:80');
socket.on('news', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});
</script>
In this case my browser can't get socket.io.js file.
EDIT : all the below text is wrong until the next "EDIT". Leaving it there as a trace...
there is one thing you should know, two things you should do + all needed Express doc is here :
Express filter/handle every access to your node server. It means that when you're trying to access your socket.io script file, Express tries to find it in the routes you declared and fails as you didn't (and you were right not to).
Most important : declare a static, non "computed" folder in
express where you will put all your static files (css, client scripts, images) :
app.use('/static', express.static(__dirname + '/static'));
This line must be put in you app.configure call, before app.use(app.router) (I actually put it first)
I like to have this /static/scripts ; /static/css ; /static/img folder organisation but you're free to adapt to your needs.
Change the link to the socket.io script file to a relative path
(optional but strongly advised) : src='/static/scripts/socket.io/socket.io.js'
EDIT : I am wrong, very very wrong and I am sorry for that. Socket.io generates the different path / files needed and you don't have to declare them nor to copy any client script files.
Please try switching the <script src="http://192.168.1.104:81/socket.io/socket.io.js"></script> client line to the normal relative one <script src="/socket.io/socket.io.js"></script> because that's the only difference between your code and the express guide code.
What Express version are you using?
The API has changed from Express 2.x to 3.x, so the answer is in the Socket.IO compatibility section at the Migrating from 2.x to 3.x wiki:
Socket.IO's .listen() method takes an http.Server instance as an argument.
As of 3.x, the return value of express() is not an http.Server instance. To get Socket.IO working with Express 3.x, make sure you manually create and pass your http.Server instance to Socket.IO's .listen() method:
var app = express()
, http = require('http')
, server = http.createServer(app)
, io = require('socket.io').listen(server);
server.listen(3000);

Resources