Matt Bryson
Matt Bryson

Reputation: 2934

Socket io emit message to client from express controller method

I know that usually you would have app.js create the socket server, and pass that instance down to your router, which in turn can pass it to controller methods. As shown here (Socket.io emit from Express controllers)

However, I have a controller method that needs to emit progress to any client who happens to be listening, but this method can be executed from many different routes, and other controllers, and I don't really want to have to pass a reference to socket around all these other parts of the app.

Is there a better way to do it?

I was thinking something like a socketio helper module. The app.js module passes it a reference to io, which can be retrieved later....

app.js

var io = require('socket.io').listen(server);    
require('./helpers/socketio').set(io);

helpers/socketio.js

var io=null;

exports.set = function(socketio) {
   io=socketio;
}

exports.get = function() {
  return io;
}

Then whenever you need it in the app..

var io = require('./helpers/socketio').get();
io.emit('message', {a:1, b:2});

Is there a cleaner way to do this? Clearly it could return null, which you would have to check for. It just doesn't feel right....

Upvotes: 4

Views: 2608

Answers (3)

Fernando Campos
Fernando Campos

Reputation: 131

This works for me:

Create a js file and add something like this

const service = {}

    const server = require('http').Server()
    const io = require('socket.io')(server, {
    cors: {
        origins: ['http://localhost:4200']
    }
});

service.inicializar = () => {
    io.on('connection', (socket) => {
        const idHandShake = socket.id;
        const { email } = socket.handshake.query;

        socket.join(email);

        console.log(`Conexion establecida --> ${idHandShake}`);

        //Este metodo escucha lo que envia el front y tiene la capacidad de emitir hacia otros miembros de la sala.
        socket.on('event', (res) => {
            const data = res
            console.log(data)

            //Envia un mensaje a todos los participantes del room
            socket.to(email).emit('event', data);
        })
    })
    return io;
}

service.emitEvent = async (email, mensaje) => {
    const sockets = await io.in(email).fetchSockets();
    sockets[0].emit('event', mensaje);
}
service.emitSesionIniciada = async (email, mensaje) => {
    console.log('email de session iniciada: ', email);
    const sockets = await io.in(email).fetchSockets();
    sockets[0].emit('sessionIniciada', mensaje);
}

module.exports = service;

you can see that Im exporting some methods on service object. You can use it later from other files just refering this one

In your server.js or app.js o whatever you run the server

const socket = require('./src/services/socket')---< this is refering the file you created
const io = socket.inicializar() ---> this call it just one. Initialize the server.

Hope this helps. Regards.

Upvotes: 0

brian burnett
brian burnett

Reputation: 83

A solution that worked for me was assigning io to app as:

 app.io = io in app.js

then anywhere you have access to the app object you have a link to the socket.

example :

file: index.js my main routing file for authenticated users

const express = require('express');

const router = express.Router();

const { ensureAuthenticated } = require('../config/auth');

... rest of the file

// Dashboard

router.get('/dashboard', ensureAuthenticated, (req, res) =>{

  res.render('dashboard')  //sends the dashboard page to the user

  req.app.io.emit('hello',req.user.name + ' Has Joined' ) 
 // lets every one else know that a new user has joined

})

Upvotes: 2

greenlikeorange
greenlikeorange

Reputation: 505

Modules are cached after the first time they are loaded.

Actually, you can verify socket.io at helper/socketio.js. Although you call require() that socketio.js from other files, node.js will execute code on that file only one time.

You can look Node Documentation

Upvotes: 1

Related Questions