marcvander
marcvander

Reputation: 629

io.sockets.on not working inside a route in Node.js

I'm trying to use io.sockets.on inside a route in a Node.js and Express app. I have been following what is said here: https://stackoverflow.com/a/31277123/8271839

I can successfully send io.sockets.emit events, but I cannot receive events with io.sockets.on.

Here is my code:

index.js:

const cors = require('cors');
const express = require('express');
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const taskRequest = require('./routes/taskRequest');

app.use(cors())
app.use(express.json());
app.use('/api/taskRequest', taskRequest);

app.set('socketio', io);

server.listen(4002);

io.sockets.on("connection",function(socket){
    console.log("connected");
    socket.on("connected", function (data) {
        console.log("hello");
    })
});

routes/taskRequest.js:

const express = require('express');
const router = express.Router();

router.post('/', async (req, res) => {

    var io = req.app.get('socketio');

    //pickedUser is one of the connected client
    var pickedUser = "JZLpeA4pBECwbc5IAAAA";

    //we only send the emit event to the pickedUser
    io.to(pickedUser).emit('taskRequest', req.body);

    io.on('connection', function (socket) {
        console.log('connected 2');
        socket.on('taskResponse', function () {
            console.log('hello 2');
        });
    });

});

module.exports = router; 

When a client is connected, I get the "connected" message in console, but not the "connected 2" message.

Also, when client emits "connected" message, I get "hello" in console, but when clients emits "taskResponse" message, I don't get "hello 2" in console.

Though when io.to(pickedUser).emit('taskRequest', req.body); is called, it works, client receives the "taskRequest" message.

Why is .emit() working inside my route but not .on() ?

Upvotes: 2

Views: 2721

Answers (2)

marcvander
marcvander

Reputation: 629

I mark TRomesh answer as the right answer, since indeed you can only have one io.on('connection', function (socket) {}) in your code.

Now here is what I have done to make it work for me: the issue was that if you place io.on('connection', function (socket) {}) within your router.post('/', async (req, res) => {}), it will only be triggered when you call your endpoint. In my case, I had some sockets events that I wanted to be called at anytime, not only when the endpoint is called. So I had to place the io.on('connection', function (socket) {}) outside of my router.post('/', async (req, res) => {}). Thus I couldn't use var io = req.app.get('socketio'); inside the router. Here is what I have done instead:

index.js:

const cors = require('cors');
const express = require('express');
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const taskRequest = require('./routes/taskRequest')(io);

app.use(cors())
app.use(express.json());
app.use('/api/taskRequest', taskRequest);

server.listen(4002);

routes/taskRequest.js

const express = require('express');
const router = express.Router();

module.exports = function(io) {

    //we define the variables
    var sendResponse = function () {};

    io.sockets.on("connection",function(socket){
        // Everytime a client logs in, display a connected message
        console.log("Server-Client Connected!");

        socket.on('connected', function(data) {
            //listen to event at anytime (not only when endpoint is called)
            //execute some code here
        });

        socket.on('taskResponse', data => {
            //calling a function which is inside the router so we can send a res back
            sendResponse(data);
        })     
    });

    router.post('/', async (req, res) => {

        //pickedUser is one of the connected client
        var pickedUser = "JZLpeA4pBECwbc5IAAAA";
        io.to(pickedUser).emit('taskRequest', req.body);

        sendResponse = function (data) {
            return res.status(200).json({"text": "Success", "response": data.data});
        }

    });

    return router;

};

Upvotes: 1

TRomesh
TRomesh

Reputation: 4471

According to you code, io is a Socket.IO server instance attached to an instance of http.Server listening for incoming events. Then inside the route you are again attaching a instance to listen to to incoming events which does not work. the io.to(pickedUser).emit works because the server instance with socketio is correctly listening to the connection thus giving the console.log("connected");.

index.js:

const cors = require('cors');
const express = require('express');
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const taskRequest = require('./routes/taskRequest');

app.use(cors())
app.use(express.json());
app.use('/api/taskRequest', taskRequest);

app.set('socketio', io);

server.listen(4002);

routes/taskRequest.js:

const express = require('express');
const router = express.Router();

router.post('/', async (req, res) => {

    var io = req.app.get('socketio');

    //pickedUser is one of the connected client
    var pickedUser = "JZLpeA4pBECwbc5IAAAA";

    io.on('connection', function (socket) {
        console.log('connected 2');
        io.to(pickedUser).emit('taskRequest', req.body);
        socket.on('taskResponse', function () {
            console.log('hello 2');
        });
    });

});

module.exports = router; 

Upvotes: 4

Related Questions