MonkeyOnARock MonkeyOnARock - 4 months ago 8
Node.js Question

socket.io only working in main server file, not in route files

Version 2 of post

Okay, first the file structure:

app
|___app.js
|___models/
|_user.js
|___routes/
|___admin.js
|___public/
|___js/
|___script.js


app.js:

var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);

http.listen(3000, function (err){
if (err) throw err;
console.log("Server is running");
});


script.js:

var socket = io();

//Next, this tells the browser that is has connected to the socket.io server
socket.on('connect', function() {
console.log('Connected to socket.io server!');
});

socket.on('message', function(message){
console.log('New message: ');
console.log(message.text);
});

var $newUsername = $('#Username');

$newUsername.on('blur', function(event){
socket.emit('message', {
text: $newUsername.val()
});
});


So on a registration page, if a user enters a 'username' already in the database, it will console.log 'This user already exists'. At least, that's the idea.

There is still sockets.io code I need to add on the server side. I am trying to put it here:

admin.js:

var router = require('express').Router();
var User = require('../models/user');

io.on('connection', function(socket) {
console.log('User connected via socket.io!');

socket.on('message', function(message) {

Username.findOne({username: message.text}, function (err, existingUsername) {
if (existingUsername) {
console.log('This user already exists: ' + message.text);
}
});
});
});


So, as this stands, the sockets.io code in admin.js won't work because it can't access the io function. I would like to know how I can fix this.

To add to this: The sockets.io code I have in the admin.js file will work fine if I placed it in my app.js file.

Answer

The key here is to pass the io instance to any module that needs it when that module is first loaded. This is called the "push" method of sharing as you share by pushing data from one module to another by passing it in the constructor function of the other module.

There is also a "pull" module where one module asks some other module for some shared data by calling a method in that module.

Here's how you could implement the "push" model:

In your admin.js file, you define a constructor function that you call and pass the io instance to when you load it:

var router = require('express').Router();
var User = require('../models/user');
var io;

// define constructor function that receives the io instance so the rest
// of the module can use it
module.exports = function(ioInstance) {
    io = ioInstance;
    io.on('connection', function(socket) {
        console.log('User connected via socket.io!');

        socket.on('message', function(message) {

            Username.findOne({
                username: message.text
            }, function(err, existingUsername) {
                if (existingUsername) {
                    console.log('This user already exists: ' + message.text);
                }
            });
        });
    });
}

Then, in your app.js file:

var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);

http.listen(3000, function (err){
    if (err) throw err;
    console.log("Server is running");
});

// when you load the admin.js file, you pass it the io instance
require('./routes/admin.js')(io);