Cleaned up 'src/app/channel'

This commit is contained in:
rainbownapkin 2024-11-20 06:54:44 -05:00
parent 985f8a250f
commit 5b5f495853
4 changed files with 160 additions and 123 deletions

View file

@ -15,8 +15,69 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.*/ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
module.exports = class{ module.exports = class{
constructor(name){ constructor(server, name){
this.server = server;
this.name = name; this.name = name;
this.userList = new Map(); this.userList = new Map();
} }
handleConnection(userDB, socket){
//get current user object from the userlist
var userObj = this.userList.get(userDB.user);
//If user is already connected
if(userObj){
//Add this socket on to the userobject
userObj.sockets.push(socket.id);
}else{
//if this is the first connection, initialize the userObject w/ the current socked id
userObj = {
id: userDB.id,
rank: userDB.rank,
flair: userDB.flair,
sockets: [socket.id]
}
}
//Set user entry in userlist
this.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);
}
handleDisconnect(socket, reason){
//If we have more than one active connection
if(this.userList.get(socket.user.user).sockets.length > 1){
//temporarily store userObj
var userObj = this.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
this.userList.set(socket.user.user, userObj);
}else{
//If this is the last connection for this user, remove them from the userlist
this.userList.delete(socket.user.user);
}
//and send out the filtered list
this.broadcastUserList(socket.chan);
}
broadcastUserList(){
var userList = [];
this.userList.forEach((userObj, user) => {
userList.push(user);
});
this.server.io.in(this.name).emit("user-list", userList);
}
} }

View file

@ -18,6 +18,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
const channelModel = require('../../schemas/channelSchema'); const channelModel = require('../../schemas/channelSchema');
const flairModel = require('../../schemas/flairSchema'); const flairModel = require('../../schemas/flairSchema');
const userModel = require('../../schemas/userSchema'); const userModel = require('../../schemas/userSchema');
const loggerUtils = require('../../utils/loggerUtils');
const activeChannel = require('./activeChannel'); const activeChannel = require('./activeChannel');
const chatHandler = require('./chatHandler'); const chatHandler = require('./chatHandler');
@ -40,111 +41,78 @@ module.exports = class{
//Prevent logged out connections and authenticate socket //Prevent logged out connections and authenticate socket
if(socket.request.session.user != null){ if(socket.request.session.user != null){
try{ try{
//Find the user in the Database since the session won't store enough data to fulfill our needs :P //Authenticate socket
const userDB = await userModel.findOne({user: socket.request.session.user.user}); const userDB = await this.authSocket(socket);
//Set socket user and channel values //Get the active channel based on the socket
socket.user = { var activeChan = await this.getActiveChan(socket);
id: userDB.id,
user: userDB.user,
};
socket.chanName = socket.handshake.headers.referer.split('/c/')[1]; //Define listeners
this.defineListeners(socket);
//Check if channel exists this.chatHandler.defineListeners(socket);
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);
//Connect the socket to it's given channel
activeChan.handleConnection(userDB, socket);
}catch(err){ }catch(err){
socket.disconnect("Server Error During Channel Connection Initialization"); //Flip a table if something fucks up
console.log(err); return loggerUtils.socketCriticalExceptionHandler(socket, err);
return;
} }
}else{ }else{
//Toss out anon's
socket.disconnect("Unauthenticated"); socket.disconnect("Unauthenticated");
return; return;
} }
}
async authSocket(socket){
//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});
if(userDB == null){
throw new Error("User not found!");
}
//Set socket user and channel values
socket.user = {
id: userDB.id,
user: userDB.user,
};
return userDB;
}
async getActiveChan(socket){
socket.chan = socket.handshake.headers.referer.split('/c/')[1];
//Check if channel exists
if(await channelModel.findOne({name: socket.chan}) == null){
throw new Error("Channel not found!")
}
//Check if current channel is active
var activeChan = this.activeChannels.get(socket.chan);
if(!activeChan){
//If not, make it so
activeChan = new activeChannel(this, socket.chan);
this.activeChannels.set(socket.chan, activeChan);
}
//Return whatever the active channel is (new or old)
return activeChan;
}
defineListeners(socket){
//Socket Listeners //Socket Listeners
socket.conn.on("close", (reason) => { socket.conn.on("close", (reason) => {this.handleDisconnect(socket, 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);
} }
broadcastUserList(chan){ handleDisconnect(socket, reason){
var activeChan = this.activeChannels.get(chan); var activeChan = this.activeChannels.get(socket.chan);
var userList = []; activeChan.handleDisconnect(socket, reason);
activeChan.userList.forEach((socketlist, user) => {
userList.push(user);
});
this.io.in(chan).emit("user-list", userList);
} }
socketToUser(socket){ getSocketInfo(socket){
const channel = this.activeChannels.get(socket.chan); const channel = this.activeChannels.get(socket.chan);
return channel.userList.get(socket.user.user); return channel.userList.get(socket.user.user);
} }

View file

@ -28,39 +28,42 @@ module.exports = class{
} }
defineListeners(socket){ defineListeners(socket){
socket.on("chatMessage", (data) => { socket.on("chatMessage", (data) => {this.relayChat(socket, data)});
//Trim and Sanatize for XSS socket.on("setFlair", async (data) => {this.setFlair(socket, data)});
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); relayChat(socket, 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 its empty or huge const user = this.server.getSocketInfo(socket);
if(!validator.isLength(msg, {min: 1, max: 255})){
return; //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});
}
async setFlair(socket, 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 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

@ -25,3 +25,8 @@ module.exports.socketExceptionHandler = function(socket, err){
//if not yell at the browser for fucking up, and tell it what it did wrong. //if not yell at the browser for fucking up, and tell it what it did wrong.
return socket.emit("error", {errors: [{type: "Caught Exception", msg: err.message, date: new Date()}]}); return socket.emit("error", {errors: [{type: "Caught Exception", msg: err.message, date: new Date()}]});
} }
module.exports.socketCriticalExceptionHandler = function(socket, err){
//if not yell at the browser for fucking up, and tell it what it did wrong.
return socket.disconnect("error", {errors: [{type: "Caught Exception", msg: err.message, date: new Date()}]});
}