diff --git a/src/app/channel/channelManager.js b/src/app/channel/channelManager.js index 9cf2273..74cb43a 100644 --- a/src/app/channel/channelManager.js +++ b/src/app/channel/channelManager.js @@ -21,103 +21,131 @@ const userModel = require('../../schemas/userSchema'); const activeChannel = require('./activeChannel'); const chatHandler = require('./chatHandler'); -//local variables -var activeChannels = new Map; +module.exports = class{ + constructor(io){ + //Set the socket.io server + this.io = io; -module.exports.handleConnection = async function(io, socket){ - //Prevent logged out connections and authenticate socket - if(socket.request.session.user != null){ - try{ - //Find the user in the Database since the session won't store enough data to fulfill our needs :P - const userDB = await userModel.findOne({user: socket.request.session.user.user}); + //Load + this.activeChannels = new Map; - //Set socket user and channel values - socket.user = { - id: userDB.id, - user: userDB.user, - rank: userDB.rank, - flair: userDB.flair - }; + //Load server components + this.chatHandler = new chatHandler(this); - socket.chanName = socket.handshake.headers.referer.split('/c/')[1]; + //Handle connections from socket.io + io.on("connection", this.handleConnection.bind(this) ); + } - //Check if channel exists - if(await channelModel.findOne({name: socket.chanName}) == null){ - socket.disconnect("Channel does not exist!"); + async handleConnection(socket){ + //Prevent logged out connections and authenticate socket + if(socket.request.session.user != null){ + try{ + //Find the user in the Database since the session won't store enough data to fulfill our needs :P + const userDB = await userModel.findOne({user: socket.request.session.user.user}); + + //Set socket user and channel values + socket.user = { + id: userDB.id, + user: userDB.user, + }; + + socket.chanName = socket.handshake.headers.referer.split('/c/')[1]; + + //Check if channel exists + if(await channelModel.findOne({name: socket.chanName}) == null){ + socket.disconnect("Channel does not exist!"); + return; + } + + //Check if current channel is active + var activeChan = this.activeChannels.get(socket.chan); + if(!activeChan){ + //If not, make it so + activeChan = new activeChannel(socket.chan); + this.activeChannels.set(socket.chan, activeChan); + } + + //Check if this user is already connected + if(activeChan.userList.get(socket.user.user)){ + //get current list of socket connnections of selected user + var userObj = activeChan.userList.get(userDB.user); + //Add this one on + userObj.sockets.push(socket.id); + //Set the user back socket list back + activeChan.userList.set(userDB.user, userObj); + }else{ + //if this is the first connection, initialize the socket array for this user + var userObj = { + id: userDB.id, + rank: userDB.rank, + flair: userDB.flair, + sockets: [socket.id] + } + + activeChan.userList.set(userDB.user, userObj); + } + + //if everything looks good, admit the connection to the channel + socket.join(socket.chan); + + //Send out the userlist + this.broadcastUserList(socket.chan); + + }catch(err){ + socket.disconnect("Server Error During Channel Connection Initialization"); + console.log(err); return; } - //Check if current channel is active - var activeChan = activeChannels.get(socket.chan); - if(!activeChan){ - //If not, make it so - activeChan = new activeChannel(socket.chan); - activeChannels.set(socket.chan, activeChan); - } - - //Check if this user is already connected - if(activeChan.userList.get(socket.user.user)){ - //get current list of socket connnections of selected user - var socketList = activeChan.userList.get(socket.user.user); - //Add this one on - socketList.push(socket.id); - //Set the user back socket list back - activeChan.userList.set(socket.user.user, socketList); - }else{ - //if this is the first connection, initialize the socket array for this user - activeChan.userList.set(socket.user.user, [socket.id]); - } - - //if everything looks good, admit the connection to the channel - socket.join(socket.chan); - - //Send out the userlist - module.exports.broadcastUserList(io, socket.chan); - - }catch(err){ - socket.disconnect("Server Error During Channel Connection Initialization"); - console.log(err); - return; + }else{ + socket.disconnect("Unauthenticated"); + return; } - }else{ - socket.disconnect("Unauthenticated"); - return; + //Socket Listeners + socket.conn.on("close", (reason) => { + //Get active channel + var activeChan = this.activeChannels.get(socket.chan); + + //If we have more than one active connection + if(activeChan.userList.get(socket.user.user).sockets.length > 1){ + //temporarily store userObj + var userObj = activeChan.userList.get(socket.user.user); + + //Filter out disconnecting socket from socket list, and set as current socket list for user + userObj.sockets = userObj.sockets.filter((id) => { + return id != socket.id; + }); + + //Update the userlist + activeChan.userList.set(socket.user.user, userObj); + }else{ + //If this is the last connection for this user, remove them from the userlist + activeChan.userList.delete(socket.user.user); + } + + //and send out the filtered list + this.broadcastUserList(socket.chan); + }); + + //define chat listeners + this.chatHandler.defineListeners(socket); + } - //Socket Listeners - socket.conn.on("close", (reason) => { - //Get active channel - var activeChan = activeChannels.get(socket.chan); + broadcastUserList(chan){ + var activeChan = this.activeChannels.get(chan); + var userList = []; + + activeChan.userList.forEach((socketlist, user) => { + userList.push(user); + }); - //If we have more than one active connection - if(activeChan.userList.get(socket.user.user).length > 1){ - //temporarily store list of active user sockets - var socketList = activeChan.userList.get(socket.user.user); - //Filter out disconnecting socket from socket list, and set as current socket list for user - activeChan.userList.set(socket.user.user,socketList.filter((id) => { - return id != socket.id; - })) - }else{ - activeChan.userList.delete(socket.user.user); - } + this.io.in(chan).emit("user-list", userList); + } - //and send out the filtered list - module.exports.broadcastUserList(io, socket.chan); - }); - - //define chat listeners - chatHandler.defineListeners(io, socket); - -} - -module.exports.broadcastUserList = function(io, chan){ - var activeChan = activeChannels.get(chan); - var userList = []; - - activeChan.userList.forEach((socketlist, user) => { - userList.push(user); - }); - - io.in(chan).emit("user-list", userList); + socketToUser(socket){ + const channel = this.activeChannels.get(socket.chan); + return channel.userList.get(socket.user.user); + } } \ No newline at end of file diff --git a/src/app/channel/chatHandler.js b/src/app/channel/chatHandler.js index fe23bec..327071e 100644 --- a/src/app/channel/chatHandler.js +++ b/src/app/channel/chatHandler.js @@ -16,42 +16,51 @@ along with this program. If not, see .*/ //NPM Imports const validator = require('validator');//No express here, so regular validator it is! + +//local imports const loggerUtils = require('../../utils/loggerUtils'); const userModel = require('../../schemas/userSchema'); +const channelManager = require('./channelManager'); -module.exports.defineListeners = function(io, socket){ - socket.on("chatMessage", (data) => { - //Trim and Sanatize for XSS - const msg = validator.trim(validator.escape(data.msg)); - //make sure high is an int - const high = validator.toInt(data.high); +module.exports = class{ + constructor(server){ + this.server = server; + } - //nuke the message if its empty or huge - if(!validator.isLength(msg, {min: 1, max: 255})){ - return; - } + defineListeners(socket){ + socket.on("chatMessage", (data) => { + //Trim and Sanatize for XSS + const msg = validator.trim(validator.escape(data.msg)); + //make sure high is an int + const high = validator.toInt(data.high); + + const user = this.server.socketToUser(socket); - //nuke the message if the high number is wrong - if(high < 0 || high > 10){ - return; - } - - io.in(socket.chan).emit("chatMessage", {user: socket.user.user, flair: socket.user.flair, high, msg}); - }); - - socket.on("setFlair", async (data) => { - const userDB = await userModel.findOne({user: socket.user.user}); - - if(userDB){ - try{ - //We can take this data raw since our schema checks it against existing flairs, and mongoose sanatizes queries - userDB.flair = data.flair; - await userDB.save(); - }catch(err){ - return loggerUtils.socketExceptionHandler(socket, err); + //nuke the message if its empty or huge + if(!validator.isLength(msg, {min: 1, max: 255})){ + return; } - } + //nuke the message if the high number is wrong + if(high < 0 || high > 10){ + return; + } - }); + this.server.io.in(socket.chan).emit("chatMessage", {user: socket.user.user, flair: user.flair, high, msg}); + }); + + socket.on("setFlair", async (data) => { + const userDB = await userModel.findOne({user: socket.user.user}); + + if(userDB){ + try{ + //We can take this data raw since our schema checks it against existing flairs, and mongoose sanatizes queries + userDB.flair = data.flair; + await userDB.save(); + }catch(err){ + return loggerUtils.socketExceptionHandler(socket, err); + } + } + }); + } } \ No newline at end of file diff --git a/src/server.js b/src/server.js index d9515c7..1bc641e 100644 --- a/src/server.js +++ b/src/server.js @@ -110,7 +110,7 @@ statModel.incrementLaunchCount(); flairModel.loadDefaults(); //Hand over general-namespace socket.io connections to the channel manager -io.on("connection", (socket) => {channelManager.handleConnection(io, socket)} ); +module.exports.channelManager = new channelManager(io) //Listen Function httpServer.listen(port, () => {