Retrieve web feeds from routes

I am trying to configure my server using websockets so that when I update something using my routes, I can also issue a websocket message when something on this route is updated.

The idea is to save something on my mongo-db when someone gets on the /add-team-member route, for example, then gives a message to everyone who is connected via websocket, and is part of any room on the Internet, which corresponds to this command.

I followed the documentation for socket.io to configure my application as follows:

App.js

 // there a lot of code in here which sets what to use on my app but here the important lines const app = express(); const routes = require('./routes/index'); const sessionObj = { secret: process.env.SECRET, key: process.env.KEY, resave: false, saveUninitialized: false, store: new MongoStore({ mongooseConnection: mongoose.connection }), secret : 'test', cookie:{_expires : Number(process.env.COOKIETIME)}, // time im ms } app.use(session(sessionObj)); app.use(passport.initialize()); app.use(passport.session()); module.exports = {app,sessionObj}; 

start.js

 const mongoose = require('mongoose'); const passportSocketIo = require("passport.socketio"); const cookieParser = require('cookie-parser'); // import environmental variables from our variables.env file require('dotenv').config({ path: 'variables.env' }); // Connect to our Database and handle an bad connections mongoose.connect(process.env.DATABASE); // import mongo db models require('./models/user'); require('./models/team'); // Start our app! const app = require('./app'); app.app.set('port', process.env.PORT || 7777); const server = app.app.listen(app.app.get('port'), () => { console.log(`Express running β†’ PORT ${server.address().port}`); }); const io = require('socket.io')(server); io.set('authorization', passportSocketIo.authorize({ cookieParser: cookieParser, key: app.sessionObj.key, // the name of the cookie where express/connect stores its session_id secret: app.sessionObj.secret, // the session_secret to parse the cookie store: app.sessionObj.store, // we NEED to use a sessionstore. no memorystore please success: onAuthorizeSuccess, // *optional* callback on success - read more below fail: onAuthorizeFail, // *optional* callback on fail/error - read more below })); function onAuthorizeSuccess(data, accept){} function onAuthorizeFail(data, message, error, accept){} io.on('connection', function(client) { client.on('join', function(data) { client.emit('messages',"server socket response!!"); }); client.on('getmessage', function(data) { client.emit('messages',data); }); }); 

My problem is that I have many changes to the mongo save file that happen in my ./routes/index file, and I would like to be able to send messages from my routes and not from the end of start.js where the socket is .io.

Is it possible to somehow transfer the websocket message from my ./routes/index file, even if IO is configured further down the line in start.js?

for example, something like this:

 router.get('/add-team-member', (req, res) => { // some io.emit action here }); 

Perhaps I need to move to where I initialize the socket.io file, but could not find any documentation about this, or maybe I can access socket.io from the routes already somehow?

Thanks and appreciate the help, let me know if something is unclear!

+5
source share
5 answers

You can use the emiter adapter to transfer data to the client in another process / server. It uses redis DB as a server to send messages.

+1
source

As mentioned above, io is in your global area. If you do

 router.get('/add-team-member', (req, res) => { io.sockets.emit('AddTeamMember'); }); 

Then, each client connected, if it is listening to this AddTeamMember event, will run the associated .on function on its respective clients. This is probably the easiest solution, and if you do not expect a huge wave of users without any load balancing plans, this should be appropriate at the moment.

Another alternative you can go for: socket.io lib has number functionality in which you can join and emit using the io object itself https://socket.io/docs/rooms-and-namespaces/ , if you have a skill for this, it looks something like this:

 io.sockets.in('yourroom').broadcast('AddTeamMember'); 

This will essentially do the same as the top, but instead of broadcasting to each client, it will be broadcast only to those who are exclusive to this room. You would basically need to figure out a way to get this socket for users in the room // before they // made a request to receive, or, in other words, made them exclusive. This way, you can reduce the amount of load that your server must push out whenever a route request is made.

Finally, if none of the above options work for you, and you just need to send this singular client when it initiates it, then it will be confused because you must have some kind of identifier for that person, and since you don’t have links, you will need to store all your sockets when connected, and then perform a comparison. I don’t quite recommend something like that, because it’s good that I have never tested it, and I don’t know what consequences can happen, but here is the essence of the idea that I had:

 app.set('trust proxy', true) var SOCKETS = [] io.on('connection', function(client) { SOCKETS.push(client); client.on('join', function(data) { client.emit('messages',"server socket response!!"); }); client.on('getmessage', function(data) { client.emit('messages',data); }); }); router.get('/add-team-member', (req, res) => { for (let i=0; i< SOCKETS.length; i++){ if(SOCKETS[i].request.connection.remoteAddress == req.ip) SOCKETS[i].emit('AddTeamMember'); } }); 

Keep in mind that if you go along this route, you will need to maintain this array when users disconnect, and if you are managing sessions, it will be very attractive.

Good luck let us know your results.

+1
source

Yes, maybe you just need to attach an instance of socket.io until you receive the request on your server. Looking at the start.js file, you just need to replace your functions as follows:

 // Start our app! const app = require('./app'); app.app.set('port', process.env.PORT || 7777); const io = require('socket.io')(app.app); const server = app.app.listen(app.app.get('port'), () => { server.on('request', function(request, response){ request.io = io; } console.log(`Express running β†’ PORT ${server.address().port}`); }); 

Now that you receive a message stating that you want to send a message to clients, you can use your io instance from the request object.

 router.get('/add-team-member', (req, res) => { req.io.sockets.emit('addteammember', {member: 6}); //as you are doing a broadcast you just need broadcast msg .... res.status(200) res.end() }); 

By doing this, I was also able to integrate with a test framework such as mocha, and verify that events were emitted too ...

I did some similar integrations, and in my experience, the last thing to do is pass the msg message to the instances on the socket.

As a good practice, at the very beginning of the middleware functions, I performed data validation, data processing and data cleansing. Here is my working example:

 var app = require('../app'); var server = require('http').Server(app); var io = require('socket.io')(server); io.on('connection', function(client) { client.emit('connected'); client.on('disconnect', function() { console.log('disconnected', client.id); }); }); server.on('request', function(request, response) { request.io = io; }); pg.initialize(app.config.DATABASEURL, function(err){ if(err){ throw err; } app.set('port', process.env.PORT || 3000); var server1 = server.listen(app.get('port'), function(){ var host = 'localhost'; var port = server1.address().port; console.log('Example app listening at http://%s:%s', host, port); }); }); 
+1
source

In the past, I have done something similar using namespaces .

Suppose your client connects to your server using "Frontend" as the namespace. My solution was to create an instance of socket.io as a class in a separate file:

Websockets / index.js

 const socket = require('socket.io'); class websockets { constructor(server) { this.io = socket(server); this.frontend = new Frontend(this.io); this.io.use((socket, next) => { // put here the logic to authorize your users.. // even better in a separate file :-) next(); }); } } class Frontend { constructor(io) { this.nsp = io.of('/Frontend'); [ ... ] } } module.exports = websockets; 

Then in App.js

 const app = require('express')(); const server = require('http').createServer(app); const websockets = require('./websockets/index'); const WS = new websockets(server); app.use('/', (req, res, next) => { req.websocket = WS; next(); }, require('./routes/index')); [ ... ] 

Finally, your routes can:

routes /index.js

 router.get('/add-team-member', (req, res) => { req.websocket.frontend.nsp.emit('whatever', { ... }); [ ... ] }); 
+1
source

Your io is actually a socket object, you can send events from this object to any specific user using

 io.to(userSocketId).emit('eventName', data); 

Or you can broadcast by -

 io.emit('eventName', data); 

Just create require socket.io before using it :)

+1
source

Source: https://habr.com/ru/post/1274693/


All Articles