How to send socket.io messages from several routes using NodeJS


How to send socket.io messages from several routes using NodeJS



I'm using socket.io to send and receive messages between the clients and a NodeJS HTTP server. So far, it works fine as all the code is in the app.js main file, like this:


app.js


let express = require('express')
let app = express();

let http = require('http');
let server = http.Server(app);

let socketIO = require('socket.io');
let io = socketIO(server);

io.on('connection', (socket) => {
console.log('New user connected');

socket.on('new-message', (message) => {
console.log(message);

io.emit('new-message', message);
});
});



But now I have this case:


/compile


/save



routes/compile.js


var express = require('express');

var router = express.Router();

router.get('/compile', (req, res, next) => {
// DO THE OPERATIONS

// For each operation, send a socket.io message to the client with the result
});



The socket for each client is obtained in the main file, when they connect to the server (io.on('connection', (socket) => {), so how could I use it inside the routes?


socket


io.on('connection', (socket) => {



Hope I explained it well, the nodeJS/socket.io combination is blowing my mind... Thanks!




2 Answers
2



A simple way is to join the user to a specific channel, and then emit to that specific channel.


io.on('connection', (socket) => {
console.log('New user connected');

const userId = getUserIdSomehow(); // logged user, ip, cookie, or whatever you like
socket.join(userId);

socket.on('new-message', (message) => {
console.log(message);

io.emit('new-message', message);
});
});



express route


router.get('/compile', (req, res, next) => {
// DO THE OPERATIONS
const userId = getUserIdSomehow(); // ip, cookie, or whatever you like
io.to(userId).emit('some-event', 'some-data');
// For each operation, send a socket.io message to the client with the result
});



You will need to pass io instance to your express route module. There are multiple ways of doing this, check this question:


io



What is the best way to pass common variables into separate modules in Node.js?



An alternative is to send the socketId in your HTTP requests, either with a cookie or a custom header.



client-side


socket.on('connect', function() {
// Save this session Id, and use it on every request
const sessionid = socket.socket.sessionid;
setCookie('socketId', sessionId); // implement setCookie
});



express route


router.get('/compile', (req, res, next) => {
// DO THE OPERATIONS
const userId = req.cookies.socketId;
io.to(userId).emit('some-event', 'some-data');
// For each operation, send a socket.io message to the client with the result
});



Each Socket in Socket.IO is identified by a random, unguessable,
unique identifier Socket#id. For your convenience, each socket
automatically joins a room identified by this id.



The downside of this way, is that if the socket connection drops, or if the user leaves, the socketId will change, and you won't be able to emit. The first way is recommended if you can identify and persist the identification of the user.





Thanks for your fast reply, I'll try to implement the first solution. And, in the express routes, how would you initialize the io object?
– Fel
Jun 28 at 15:01


io





You're welcome. You don't have to initialize it, you need to pass the same io object, that you have on app.js. You need to use that instance of io. You can use one of the many ways to pass variables to other modules. Check this other question: stackoverflow.com/questions/10306185/…
– Marcos Casagrande
Jun 28 at 15:03


io


app.js


io



Following Marcos suggestion, this is what I've done to solve the problem:



app.js


let socketIO = require('socket.io');
let io = socketIO(server);

// ROUTES
let compileRoute = require('./routes/compile')(io); // Inject the Socket IO object into the routes module

app.use('/compile', compileRoute);



routes/compile.js


module.exports = function(io) {
router.post('/', (req, res, next) => {
var body = req.body;

var sid = body.socketId; // Socket ID from the client

// OPERATION LOOP

// Use the injected Socket IO object and the socket ID received from the client
// to send the result messages
io.to(sid).emit('new-message', 'Operation result');
});

return router;
};



ANGULAR COMPONENT


public doCompile() {
const body = {
// Obtain the socket ID from the service (basically, it returns this.socket.id)
socketId: this.socketService.getSocketId()
};

// Send the HTTP request with the socket id in the body
this.httpClient.post('http://localhost:2999/compile', body).subscribe(
}



Now, I have to manage the possible socket disconnections to reassign a new socket id in the socket service, but that's another subject :)



Cheers,






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Comments

Popular posts from this blog

paramiko-expect timeout is happening after executing the command

how to run turtle graphics in Colaboratory

Export result set on Dbeaver to CSV