ace196 ace196 - 5 months ago 36
Node.js Question

Modularizing an Express/Socket.io application

I want to be able to load these 4 functions:

returnAvailable
,
processMessage
,
removeUser
and
joinRoom
from an external file, but i get reference errors where it says that socket and nicknames are undefined. How do I modularize my app with respect to dependencies I use?

Here's my code:

server.js

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

// mongoDB init
var mongoose = require('mongoose');
mongoose.connect("mongodb://localhost:27017/chat");
var Message = require('./server/datasets/message');

//include these 4 functions
var util = require('./server/util/util');

//object which contains all users and chatrooms
var nicknames = {
'Music': [],
'Videogames': [],
'Sports': [],
'TV': [],
'Politics': []
};

// middleware
// serves static files
app.use('/client', express.static(__dirname + '/client'));
app.use('/node_modules', express.static(__dirname + '/node_modules'));


// routes
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html')
});

app.get('/api/rooms/get', function(req, res){
res.json(nicknames);
});


server.listen(2000);


// socket functionality
io.sockets.on('connection', function(socket){

socket.on('new user', util.returnAvailable);

// do when 'send message' data is received from client
socket.on('send message', function(data){
util.processMessage(data);
});

// do when 'disconnect' data is received from the client
socket.on('disconnect', function(data){
util.removeUser();
});

socket.on('leave room', function(){
util.removeUser();
});

});


util.js

module.exports.returnAvailable = function (data, callback){
console.log(data);

if(nicknames[data.room].indexOf(data.username) != -1){
callback({ bool: false });
}else {
socket.nickname = data.username;
joinRoom(socket, data.room);

nicknames[data.room].push(socket.nickname);
console.log(nicknames[data.room]);

io.sockets.to(data.room).emit('usernames', nicknames[data.room]);
callback({ bool: true, nickname: socket.nickname});
}
}

module.exports.removeUser = function(){
//console.log(socket.nickname + " disconnected. Bool value: " + socket.nickname==true);
if(socket.nickname==false) return;
// socket.room has to be defined, otherwise crashes if user reloads while not in a roomn
if(socket.room)
{
nicknames[socket.room].splice(nicknames[socket.room].indexOf(socket.nickname), 1);
socket.leave(socket.room);
}

io.sockets.to(socket.room).emit('usernames', nicknames[socket.room]);
}

module.exports.joinRoom = function (data){
socket.join(data);
socket.room = data;
console.log(socket.room);

var query = Message.find({room: socket.room});
query.sort({created:-1}).limit(5).exec(function(err, results){
if(err) { console.log(err); }

else if(results){
io.sockets.to(socket.room).emit('old messages', results);
}
});
}


module.exports.processMessage = function(data){
io.sockets.to(socket.room).emit('new message', {msg : data, nick : socket.nickname});
var message = new Message({
created: new Date,
user: socket.nickname,
message: data,
room: socket.room
});

message.save(function(err){
if(err){
console.log(err);
}else{
console.log('Successfully saved.');
}
});
}


I'm using Express 4.13.4

Answer

The socket variable is only available within io.sockets.on('connection', callback function so you can't use it in other files this easily. But you can pass the socket variable to the function where you are trying to use it like this

util.removeUser(socket);

and change the definition of removeUser to accept the socket as an argument

module.exports.removeUser = function(socket){

    // your code here

}

The same goes for nicknames variable, use it like this

socket.on('new user', function(data) {

    util.returnAvailable(io, socket, nicknames, data);

});

and change the function to accept those arguments

module.exports.returnAvailable = function (io, socket, nicknames, data){

    // your code here

}
Comments