Improved channelManager and chatHandler

This commit is contained in:
rainbownapkin 2024-11-20 05:27:05 -05:00
parent 4b4cb2ed3d
commit 985f8a250f
3 changed files with 154 additions and 117 deletions

View file

@ -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);
}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 = [];
//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);
}
activeChan.userList.forEach((socketlist, user) => {
userList.push(user);
});
//and send out the filtered list
module.exports.broadcastUserList(io, socket.chan);
});
//define chat listeners
chatHandler.defineListeners(io, socket);
this.io.in(chan).emit("user-list", userList);
}
}
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);
}
}

View file

@ -16,42 +16,51 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
//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);
//nuke the message if the high number is wrong
if(high < 0 || high > 10){
return;
}
const user = this.server.socketToUser(socket);
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);
}
}
});
}
}

View file

@ -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, () => {