Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Socket.io emit from Express controllers

I'm quite new to Node.js / Express, and I'm using it as a backend for an AngularJS app. I've looked all over StackOverflow for some help on my problem, but I can't seem to figure out how to port the suggestions to my code.

My application works as follows:

  • A long running Scala process periodically sends my Node.js application log messages. It does this by posting to an HTTP API
  • When the post is received, my application writes the log message to MongoDB
  • The log messages are then sent in real time to the Angular client.

I am having a problem with Node's modules, as I can't figure out how to refer to the socket instance in the Express controller.

As you can see, in server.js, socket.io is instantiated there. However, I would like the controller itself, logs.js, to be able to emit using the socket.io instance.

How can I refer to io in the controller? I'm not sure how to pass the io instance to the controller so I can emit messages?

Here is some of the Node code:

server.js

var app = express(),
  server = require('http').createServer(app),
  io = require('socket.io').listen(server);

require('./lib/config/express')(app);
require('./lib/routes')(app);

server.listen(config.port, config.ip, function() {
  console.log('Express server listening on %s:%d, in %s mode', config.ip, config.port, app.get('env'));
});

io.set('log level', 1); // reduce logging

io.sockets.on('connection', function(socket) {
  console.log('socket connected');
  socket.emit('message', {
    message: 'You are connected to the backend through the socket!'
  });
});

exports = module.exports = app;

routes.js

var logs = require('./controllers/logs'),
  middleware = require('./middleware');

module.exports = function(app) {
  app.route('/logs')
    .post(logs.create);
}

logs.js

exports.create = function(req, res) {
 // write body of api request to mongodb (this is fine)
 // emit log message to angular with socket.io (how do i refer to the io instance in server.js)
};
like image 390
mousetree Avatar asked May 19 '14 11:05

mousetree


1 Answers

You can use a pattern based on standard JS closures. The main export in logs.js will not be the controller function itself, but a factory function that will accept all needed dependencies, and create the controller:

exports.create = function(socket) {
  return function(req, res) {
    // write body of api request to mongodb
    socket.emit();
  }
}

Then, when you want to use it:

app.route('/logs').post(logs.create(socket));

Since you set up your routes in a separate package, you have to use the same pattern in routes.js - routes should receive the socket to use as a parameter.

This pattern works well if you want to handle those things with DI later, or test your controllers with mock "sockets".

like image 59
Jakub Wasilewski Avatar answered Sep 20 '22 01:09

Jakub Wasilewski