Express JS Controllers with Socket IO Issue

Viewed 166

I am trying to setup Socket IO to work well in different controllers in my Express application.

Here is how I have Socket IO initialized in my server.js

//Run When Connection Received
io.on('connection', (socket) => {
    socket.emit('message', 'This is a test message from the server.')
})

Here is what one of my controllers looks like:

const getComments = asyncHandler(async (request, response) => {
    const { liveID, token: accessToken } = request.body
    var source = new EventSource(
        `https://streaming-graph.facebook.com/${liveID}/live_comments?access_token=${accessToken}&comment_rate=one_per_two_seconds&fields=from{name,id},message`
    )
    source.onmessage = function (event) {
        // Do something with event.message for example
        console.log(event)

        // THIS IS WHERE I NEED TO EMIT A SOCKET IO EVENT.
        // THE DATA IN 'event' NEEDS TO BE SENT BACK TO THE CLIENT VIA THE SOCKET

    }
    source.onerror = function (error) {
        console.log('Error!')
        console.log(error)
    }

    source.onopen = function (event) {
        console.log(event)
    }
})

I have been trying to follow this documentation from Socket IO but for the life in me I can not seem to figure out how to make this work with my above example I have tried so many different things and I just seem to be missing something.

https://socket.io/docs/v4/server-application-structure/

Any help here would be greatly appreciated!

1 Answers

What you can do to have access to io in controller is to attach it to request object like so:

app.use((req, res, next) => {
    req.io = io;
    next();
});

When a socket connects add an user id to the socket

io.on('connection', (socket) => {
    // assuming you send user id in a header for example
    socket.userId = socket.client.request.headers.userId;
})

Then in a controller:

const getComments = asyncHandler(async (request, response) => {
    var io = request.io;

    // https://socket.io/docs/v4/server-api/#serverfetchsockets
    // return all Socket instances
    const sockets = await io.fetchSockets();

    // assuming there's a loggedin user object attached to request
    const socket = sockets.find(s => s.userId === request.user.id);

    const { liveID, token: accessToken } = request.body
    var source = new EventSource(
        `https://streaming-graph.facebook.com/${liveID}/live_comments?access_token=${accessToken}&comment_rate=one_per_two_seconds&fields=from{name,id},message`
    )
    source.onmessage = function (event) {
        // Do something with event.message for example
        console.log(event)

        socket.emit(....);

    }
    source.onerror = function (error) {
        console.log('Error!')
        console.log(error)
    }

    source.onopen = function (event) {
        console.log(event)
    }

})
Related