2

In my express app, generated with express-generator, I want to use the io of socket.io in some other controller files to emit data to client sockets. My approach is below, but I get the following error with that. It would be a great favor if someone can help me in this case.

(node:11376) UnhandledPromiseRejectionWarning: TypeError: io.emit is not a function at F:\backend\controllers\LessonController.js:169:9

In the express apps, generated by express-generator, the process of creating the server happens in the /bin/www.js. I tried importing the io instance from there and use it in some other file, but it didn't work.

bin/www.js

#!/usr/bin/env node

var app = require('../app');
var debug = require('debug')('backend:server');
var http = require('http');

var port = normalizePort(process.env.PORT || '8080');
app.set('port', port);

var server = http.createServer(app);
const io = require('socket.io')(server);

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

// several other functions are omitted for brevity

module.exports = io;

LessonController.js

const Lesson = require('../models/Lesson');
const Course = require('../models/Course');
const User = require('../models/User');
const io = require('../bin/www')
var _ = require('lodash');

module.exports = {
    addComment: async (lessonId, userId, content, callback) => {
        const newData = {
            comments: {
                user: userId,
                content: content,
            },
        };

        Lesson.findOneAndUpdate({ _id: lessonId }, { $push: newData }, {new: true})
        .exec()
        .then(
            function (data) {
                if (data) {
                    io.emit("comment_"+lessonId,data)
                    callback(null, data);
                } else if (err) {
                    callback(err, null);
                }
            }
        )
    }
};
1
  • You could export a function in your LessonsController which takes a parameter like module.exports = function(io) {...} and then you could inject the instance from your www.js like require('./routes/lessonCtontroller')(io);. In case this fits the rest of your code. Commented May 8, 2020 at 18:26

3 Answers 3

6
+50

You can try to export the socket.io instance to the global level and access that as needed.

My project was also created with express-generator, therefore, follows the same template.

In my project, I would like to count the current number of active users in home page.

Here is an example:

bin/www

#!/usr/bin/env node
const app = require('../app');
const http = require('http').Server(app);
const io = require('socket.io')(http)
http.listen(process.env.PORT);
io.on('connection', (socket) => {    
    const qtd = socket.client.conn.server.clientsCount;
    io.emit('novaconexao', qtd);
    socket.on('disconnect', () => {
        io.emit('disconnecteduser', qtd - 1);
    });
});
app.set('socketio', io);//here you export my socket.io to a global       

console.log('Microsservice login listening at http://localhost:%s', process.env.PORT);

server/index.js

const router = require('express').Router();
router.get('/', (req, res) => {
    const io = req.app.get('socketio'); //Here you use the exported socketio module
    console.log(io.client.conn.server.clientsCount)
    io.emit('new-user', {qtd: io.client.conn.server.clientsCount})
    res.status(200).json({ msg: 'server up and running' });
})
module.exports = router;

Following this strategy, you can use socketio in any route in your application.

Sign up to request clarification or add additional context in comments.

Comments

6

Here is a solution

Create a module io.js

const sio = require('socket.io');

let io = null;
module.exports = {
    //Initialize the socket server
    initialize: function(httpServer) {
        io = sio(httpServer);
        io.on('connection', function(socket) {
            console.log('New client connected with id = ', socket.id);
            socket.on('disconnect', function(reason) {
                console.log('A client disconnected with id = ', socket.id, " reason ==> ", reason);
            });
        });

    },
    //return the io instance
    getInstance: function() {
        return io;
    }
}

In bin/www.js

var server = http.createServer(app);
require('path_to_io_js/io').initialize(server);

In your controllers / LessonController.js

//require the io module
const socket = require('path_to_io_js/io');
module.exports = {
    addComment: async (lessonId, userId, content, callback) => {
        const newData = { comments: { user: userId, content: content, }, };
        Lesson.findOneAndUpdate({ _id: lessonId }, { $push: newData }, { new: true })
            .exec().then(function (data) {
                if (data) {
                    //get the io instance
                    const io = socket.getInstance();
                    io.emit("comment_" + lessonId, data)
                }
                callback(null, data);
            }).catch(err => {
                callback(err);
            })
    }
};

Comments

0

Create socketInstance.js

let io = null;

// set this when you initialize the io
const setSocketInstance = (ioInstance) => {
  io = ioInstance;
};
//  you can call this anywhere
const getSocketInstance = () => {
  return io;
};

inside socket.js where you initialize io

const setSocketInstance = require("./socketInstance");
const initializeIO = (server) => {
  const io = require("socket.io")(server, {
    cors: {
      origin: "*",
      methods: ["GET", "POST"],
    },
  });
  // as soon as we initialize the io, we set the instance
  setSocketInstance(io);
 // ....
};

Now you can call getSocketInstance anywhere in your app.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.