Express routes with Socket IO Node JS - javascript

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.

Related

Socket io Client in ReactJS is getting multiple emits from the server

I am building a chat room with some extra features, and I have a socket io server, as well as a socket io client in ReactJS.
I have it so if someone pins a message or changes the settings of the chat room, it emits the changes to the server, the server saves those changes, and then emits them back out to everyone so everyone is synced.
The settings and pinned messages successfully transfer and are communicated, I have console.logs at almost every step of the transfer, the client logs out a single request, the server logs that it emits a single time, but the client logs that it recieved an emit multiple times, sometimes a couple of times like 2-6 requests, sometime it gives out 60 requests. I'm trying to really control the efficiency, but I have no idea what is causing this
I'm not sure it matters but another thing of note is that the client also connects to a native WebSocket server to get messages from another source
what the client generally looks like is:
effect(()=>{
socket.emit('changeSetting', setting)
},[setting])
socket.on('recieveSetting', (arg)=>{
if(arg != setting){
setSetting(arg);
}
})
the server then looks like this:
socket.on('changeSetting', (arg)=>{
storedSetting = arg
socket.emit('recieveSetting', storedSetting)
})
That's the general structure, so I don't think its an issue of the code, more like if reactJS or connecting to the other websocket causes it to get multiple emits

Creating a redux middleware that uses websocket api for syncing server data state with client

I have a server API, that is based on websockets. If the client connects, he must first send a message, and if a success message from server is emitted, client can start working with the server data.
Now i have a angular4 based app, that if the user opens several view components, each component registers to specific events from the API (Using a Websockets service). If the a new state comes from server, the views can update itself. Views can also send update events to server, that recalculates data and sends updates via websockets. The server itself holds a state of the data.
But now, no real client state exists. Without overcomplicating this post (i exclude routing etc), the main target for me now is to integrate redux for managing the state in UI, so that the user can reload the page and see last opened views with a synced with server data.
The current approach of me, is to create create a
Backend service, that holds an WebSocketSubject (RxJS) and manages the sending or recieving from server. I pass an connection observable, that dispatches an event if connection exist. I also have a Subscription inside the service, that dispatches all the websockets push messages as redux events and acts like a middleware
/** this code is a binding to redux word, and acts as middleware push
* #type {Subscription}
*/
this.subscription = this.socket$.subscribe(
(msg) => this.ngRedux.dispatch({type: msg.method, value: msg.parameters}),
(err) => this.ngRedux.dispatch({type: AppActions.CONNECTION_FAILED}),
() => this.ngRedux.dispatch({type: AppActions.CONNECTION_CLOSED})
);
The idea is that i will have reducers, that will react on data state changes from server e.g. if an error is send and a specific view listens to it, it should have a error state.
case BackendStreams.some__error:
return Object.assign({}, lastState, {
error: 'Could not do some calcucations'
});
The server code itself is deterministic and works works the messages from one stack, so i can expect that if i send same 4 messages in same sequence, i will receive same responses.
The problem what i have now, is that if i reload the window (or use the DevTools), the state is recreated, but none of the events are resent to backend. How can i accomplish this? Should i somehow (what tools) tell Redux that some of impurity exists, or have something like a state machine? Im just guessing...

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.

Where to add Socket.io logic in Sailjs project

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.

Sending message between two users via node.js and socket.io

I'm new with node.js and socket.io
I have two clients, and they have their ID 1 & 2.
I need to send data via socket.io that contain:
user_from, user_to, action
And the data is send from both sides.
How do i send this data from client 1 with socket.emit(), so I can set variable:data ?
How to read that data on server with socket.get ?
And send it again from server to client 2 ?
(i found this code: io.sockets.volatile.emit( 'broadcast_msg' , msg ); but i want to send it only from specific user to specific user, not all users connected.)
Thank you for your help, I see a lot of examples, but not what I need.
UPDATE:
I don't understand this code:
// on server started we can load our client.html page
function handler(req, res) {
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);
res.end(data);
});
}
Why do I need to do this? I have ex: index.php?menu=30 or index.php?menu=30&action=12
You are looking for routing functionality. What socket.io provides is point-to-point communication. e.g. from 1 client to the server.
So logically, you need the server to route messages, which means that messages should have addressing information (e.g. ID of the target recipient). This can then be used to route messages by, for example, creating (custom) user-specific events to be triggered based on the target user of the incoming message.
If you are building anything that needs to scale, perhaps you should look at a messaging framework like RabbitMQ. It is exactly meant to route messages between distributed entities (like the users).
Cheers!

Categories

Resources