Where to add Socket.io logic in Sailjs project - javascript

I am new to sailjs and socket.io. I have gone through the samples in socket.io home page. Now I am confused where(in which file) to write the logic of socket connected, emitting messages and chat room management in a sailjs project. Is there any clean documentation on using socket.io with sailjs.
I have seen this tutorial but he is not demonstrated it using sailsjs, even though the subject says Building a Sails Application: Ep18 - Understanding Web Sockets and Socket IO Including Room Creation and Management.
Thanks for all the help.

You'll find all the documentation here: http://sailsjs.org/#!documentation/sockets
Out of the box, Sails handles Socket.io requests the same way it handles HTTP requests-- through the Express interface. It does this by creating a fake Express request and automatically routing the socket requests to the proper controller and action. For instance, here is a simple controller:
// api/controllers/EchoController.js
module.exports = {
index: function (req,res) {
// Get the value of a parameter
var param = req.param('message');
// Send a JSON response
res.json({
success: true,
message: param
});
}
};
Note the file EchoController.js which in this example is where the sockets are handled.

Related

Express routes with Socket IO Node JS

I'm creating a microservice with NodeJS which will send & receive messages with socketIO. I'm following a boilerplate and setup the GET & POST routes with ExpressRouter
socket.on('sendmessage', (newMessage) => {
socket.in(userId).emit('newmessage', newMessage);
});
app.post('/sendMessage', expressAsyncHandler(async function (req, res) {
// saving the message to database and returning a response....
}))
I'm just confused about why do I need routes if I can handle all data saving, validation and authorization functionality too in socketIO code block? What is the best case for an application like that which ensures message delivery and no data loss?
Whether to use routes or not depends on the design and architecture of your application. If you need to implement additional functionality outside of sending and receiving messages, such as authentication or data validation, using routes with Express is a good option. If your application is solely focused on sending and receiving messages, then you can handle the functionality within the socket.on() event.
For ensuring message delivery and avoiding data loss, you can implement message acknowledgment or implement a message queue like RabbitMQ or Apache Kafka to buffer messages before they are processed by the server. This helps ensure that messages are not lost even if the server goes down or there is a connection issue.

Understanding how to use Redis with Node.js and Server Sent Events

My Project is built with Nodejs as proxy server to communicate with an external API.
The API send product updates via Redis (pub/sub); The Proxy server handle the message and send it to the client via SSE (Server Sent Events).
It is the first time for me using Redis and SSE and looking online for tutorials seems to be easy to implement and I did it.
On the Client side I just created an EventSource and as soon as I receive an update I do something with it:
// Client Side
var source = new EventSource('/redis'); // /redis is path to proxy server
source.addEventListener('items', handleItemsCallback, false);
source.addEventListener('users', handleUsersCallback, false);
source.addEventListener('customers', handleCustomersCallback, false);
// Function sample...
function handleItemsCallback (msg) {
// Do something with msg...
}
In the Proxy server I created a controller with routing to /redis to handle Redis messages:
exports.redisUpdates = function (req, res) {
// Redis Authentication
var redisURL = url.parse(process.env.REDISCLOUD_URL);
var client = redis.createClient(redisURL.port, redisURL.hostname, {ignore_subscribe_messages: false});
client.auth(redisURL.auth.split(":")[1]);
// let request last as long as possible
req.socket.setTimeout(0);
// Subscribe to channels
client.subscribe('items', 'users', 'customers');
// Handle messages
client.on('message', function (channel, message) {
res.write('retry: 5000\n');
res.write('event: ' + channel + '\n');
res.write('data: ' + message + '\n\n');
res.flush(); // If I do not add this it doesn't push updates to the client (?)
});
//send headers for event-stream connection
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
res.write('\n');
};
Using it locally in a development environment it works fine but using it in Production generate several different errors, the App is hosted on Heroku and the Heroku Metrics show several H18, H12, H27 Errors;
Sometimes the /redis call return status 503;
What I wish to understand is if I'm using those services correctly, why all tutorials do not mention res.flush() and I discovered it by myself to let it work the first time...
In all fairness, this question is not really answerable for a few reasons. I don't know which tutorials you are talking about since you didn't reference any in the question. I cannot speak on behalf of those who wrote the unreferenced tutorials. They could just be wrong, or maybe the architecture of what you are trying to accomplish differs in some small way. I also don't know what framework or optional middleware you are using in your project.
Now, with all of that said there are a few things I can share that may help you out.
Most tutorials you find out there are probably not going to open a connection and read from the stream indefinitely. When the process ends, the http response is closed with .end() or something similar. Since an HTTP response is a write stream, it follows the same rules as any other stream. You can find a lot of good info about streams here:
https://github.com/substack/stream-handbook
Something important to understand is that a stream can have a buffer and most http frameworks enable compression which causes buffers to be used. The code sample in the next link is a good example of what a framework would do for you behind the scenes (a minimal implementation of course)
https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/#what-we-ve-got-so-far
Since you want the output to continue being updated, you either have to wait until the output buffer size is reached or you have to call .flush().
If you ARE using express, check out this next Stack Overflow post related to compression middleware. I believe you'll have to have it disabled for your /redis route.
Node Express Content-Length
I hope that helped a little. Like I said, its kind of hard to answer this question. ;)

Running a node.js file from website

I have recently started using the Twilio platform to send SMS to my users. I am perfectly able to run the node.js file from the node terminal with the command:
node twilio.js
Now, my goal is to be able to send those SMS, but from my website. For instance, when the user provides his phone number and presses the "Send sms" button. How can I achieve this? I have been looking this up for a while and I came across Express platform, ajax post requests, http server, etc. But, I can't figure out how to use them. I currently make many ajax requests (POST and GET) on my site, but I'm not able to make a request to a node file.
Thanks in advance,
Here is the twilio.js file:
// Twilio Credentials
var accountSid = 'ACCOUNT SID';
var authToken = 'ACCOUNT TOKEN';
//require the Twilio module and create a REST client
var client = require('twilio')(accountSid, authToken);
client.messages.create({
to: 'TO',
from: 'FROM',
body: 'Message sent from Twilio!',
}, function (err, message) {
console.log(message.sid);
});
Being able to run any arbitrary script on your server from a webpage would be a huge security risk - don't do that. I'm not sure where you're hosting your site, or what technology stack you're running your site on, but since you mentioned Express and Node -- if you're using Express I'd recommend that you setup a route that handles an ajax request. When someone presses 'Send SMS' you send an ajax request to that route, and in the handler that gets invoked you place the Twilio logic.
Here is a very simple way to setup an Express request that calls you node module:
twilio.js:
// Twilio Credentials
var accountSid = 'ACCOUNT SID';
var authToken = 'ACCOUNT TOKEN';
//require the Twilio module and create a REST client
var client = require('twilio')(accountSid, authToken);
function sendSms(callback) {
client.messages.create({
to: 'TO',
from: 'FROM',
body: 'Message sent from Twilio!',
}, callback);
}
// Export this function as a node module so that you can require it elsewhere
module.exports = sendSms;
Here is a good start for Express.
server.js:
var express = require('express');
var app = express();
// Requiring that function that you exported
var twilio = require('/path/to/twilio.js');
// Creating a controller for the get request: localhost:8081/send/sms
app.get('/send/sms', function (req, res) {
twilio(function(err, message) {
if (err) res.send(err);
res.send('Message sent: ' + message);
});
});
// Creating an HTTP server that listens on port 8081 (localhost:8081)
var server = app.listen(8081, function () {
var host = server.address().address;
var port = server.address().port;
console.log("Example app listening at http://%s:%s", host, port);
});
Then you can run node server.js, go to your browser and go to the url: localhost:8081/send/sms and your message will be sent :)
I'd make it so the client sends a HTTP POST request to the server, and then the server will send the message on behalf of the client.
Easiest way is to use express. I'm a bit unsure of how you're serving your website from a Node.js app without using express. Do you have a custom solution or only a non-connected from end, or something like heroku or something? In any case, you can create a route that processes posts with the following:
app.post("send_twilio_message_route", function(req,res){
// this receives the post request -- process here
});
^ Note that doesn't actually create the express app. See my link below and they give examples of some of the nitty gritty and syntax.
So the above would be on the server, in your Node.js app. From the front-end client code that runs in the browser, you need to create a post. The easiest way and most likely way to do it is through $.post in Jquery. if you are using Angular there's a slightly different syntax but it's the same idea. You call post, point it to a url, and put in the body data.
Make the body of the post request contain data such the message, phone numbers,
authentication token maybe.
See this to be able to get the body from a post request and some more implementation details of how to set it up:
How to retrieve POST query parameters?
Depending on the nature of what you're doing you might consider having the sms processing stuff run separate from the actual web service. I would create the sms unique stuff as its own module and have a function retrieve the router so that you can mount is onto the app and move it about later. This might be overkill if you're doing something small, but I'm basically encouraging you to at the start put thought into isolating your services of your website, else you will create a mess. That being said, if it's just a small thing and just for you it might not matter. Depends on your needs.
Important: I highly encourage you to think about the malicious user aka me. If you don't add any authentication in the post body (or you could include it in the url but I wouldn't do that although it's equivalent), a malicious client could totally be a jerk and expend all of your twilio resources. So once you get it basic up in running, before deploying it to anything that people will see it, I recommend you add authentication and rate limiting.

Would love some help determining where to start with the Node.JS app file provided with BlueMix

I've been reading tutorials for JS and I've got a good idea of the syntax and methodology, now I'm looking to figure out how to use Node.JS to build an app with BlueMix. I'm pretty fluent with Java, but I'm absolutely new to web programming so I'm pretty lost as to how to start. Forgive my current state of being an absolute beginner, but I'm just really stuck. Here's the file they give you to build off of.
/*eslint-env node*/
//--------------------------------------------------------------------------
// node.js starter application for Bluemix
//--------------------------------------------------------------------------
// This application uses express as its web server
// for more info, see: http://expressjs.com
var express = require('express');
// cfenv provides access to your Cloud Foundry environment
// for more info, see: https://www.npmjs.com/package/cfenv
var cfenv = require('cfenv');
// create a new express server
var app = express();
// serve the files out of ./public as our main files
app.use(express.static(__dirname + '/public'));
// get the app environment from Cloud Foundry
var appEnv = cfenv.getAppEnv();
// start server on the specified port and binding host
app.listen(appEnv.port, '0.0.0.0', function() {
// print a message when the server starts listening
console.log("server starting on " + appEnv.url);
});
To clarify, I get the general purpose of the code - it's commented pretty well, but I just don't know how to start // test on the BlueMix platform. I tried doing things like adding print statements, but nothing really changes.
To give a little insight on what I'm trying to do: Just create a webpage where a user can input a string and I can post a string in response. I'm just trying to learn BlueMix, so I need to do it on this platform, and in Node JS.
I suggest you to take a look at this tutorial: IBM Bluemix DevOps Services - Develop and deploy a Node.js app. It is useful to get started with DevOps Services (reading your comments it seems that you are using it to deploy from the Web IDE to Bluemix) to get a "Hello World" Node.js Web application on Bluemix. It also shows how to apply some changes and re-push them directly on Bluemix.
Just to answer to your questions, assuming that you have already deployed the starter application (as in your example):
Consider that the starter application uses Express.js, that is an application server framework that helps you to manage the incoming requests. Now let's say that you want to send the string "Hello, World!" in HTTP response when the server receives an HTTP GET request (let's say /printhello). Using express you'll have something like:
app.get('/printhello', function (req, res) {
res.send('Hello, World!');
});
Now you just need to do the HTTP GET /printhello from a web page (for example the index page under the public folder of the starter application). You could for example use an onclick event to send the request to the server. You will see that the server receives it and sends the response to the browser, that will show the string "Hello, World!".
The reason why you can't see the "starting server" log is that console.log prints in the Node.js console, not into the HTTP response, so you can't see that from the client. To see that output you can use cf logs (please refer to this blog post).
Finally, I invite you to take a look at the Bluemix - Node.js SDK documentation, it is really simple and clear.
I hope this can give you some starting points.
Check out https://github.com/IBM-Bluemix/bluemix-hello-node. It provides a pretty good starting place for node. There are somethings you need to code around for Node to work for Bluemix. The biggest is binding to the correct port, the port is given through process.env.PORT. I have pasted a super simple Node.app below (the rest of the code is at the GitHub link above).
var express = require("express"),
app = express();
var port = process.env.PORT || 8080;
app.use(express.static(__dirname + '/public'));
app.get("/hello", function (request, response) {
response.writeHead(200, {"Content-Type": "text/plain"})
response.end("Hello World!\n");
});
app.listen(port);

Socket.IO and AngularJS creates multiple connections, how to stop?

I'm developing a realtime socket.io app using AngularJS, Nodejs, and Socket.io both the server and client side libraries. I'm using the module called angular-socket-io however when I tell Angular to connect, the more I refresh the page it seems like multiple connections keep being maintained with Socket.IO and I'm the only user on the page right now.
In my server logs I keep seeing many socket IDs print out and when I refresh the application page, it takes a while for it to reconnect. Watching the console I see it communicating with the server a lot (probably has to do with the multiple socket connection handshakes) but after a good minute or two, it finally stabilizes and starts receiving data again.
I think I'm doing this wrong, or is this normal? Does anyone have any good advice for using Socket.IO in angular so that when the page refreshes it reconnects once and gets rid of all previous connections so that only one is maintained at all times?
Here's some code samples. Just to clarify, the btford.socket-io prefixes all forwarded socket events with "socket:". So in my example it would be "socket:start".
myApp.js
angular.module('myApp', [ 'btford.socket-io', 'myControllers' ])
.config([ 'socketProvider', function(socketProvider) {
var appSocket = io.connect('http://live.myapp.com');
socketProvider.ioSocket(appSocket);
}])
.run(['socket', function(socket) {
socket.forward('error');
socket.forward('start'); // this is the event i'm trying to listen for
});
myController
angular.module('myControllers').controller('startController', [
'$scope',
function($scope) {
$scope.$on('socket:start', function(ev, data) {
$scope.activeDrivers.push({
name: data.user.firstName + " " + data.user.lastName
});
$scope.driversActiveTab.count = $scope.activeDrivers.length;
});
}
]);
So that's it, and I can't figure out why it keeps making so many connections to the server! Thanks for the help in advance!
you should generate a id(ex:random string) in your angular page.when you connect server first.record this id in your server, id is bind your socket. when client disconnect,will call server 'disconnect' event,listen this event and clean the socket.
Answering my own question. Per this page, if you have nodejs instances running across servers or on multiple cores you must use the RedisStore to queue and properly handle socket requests. The strange behavior I described in my question was the browser attempting to connect to one of my 4 cores and missing responses from other cores. I followed the instructions to enable Redis as the data store for SocketIO and all of the problems went away.

Categories

Resources