Javadoc for src/app complete

This commit is contained in:
rainbow napkin 2025-08-29 01:59:44 -04:00
parent ad057916d8
commit 2303c89bcf
4 changed files with 313 additions and 11 deletions

View file

@ -25,7 +25,14 @@ const emoteValidator = require('../../validators/emoteValidator');
const chat = require('./chat'); const chat = require('./chat');
const {userModel} = require('../../schemas/user/userSchema'); const {userModel} = require('../../schemas/user/userSchema');
/**
* Class containing global server-side chat relay logic
*/
module.exports = class{ module.exports = class{
/**
* Instantiates a chatHandler object
* @param {channelManager} server - Parent Server Object
*/
constructor(server){ constructor(server){
//Set server //Set server
this.server = server; this.server = server;
@ -35,6 +42,10 @@ module.exports = class{
this.chatBufferSize = 50; this.chatBufferSize = 50;
} }
/**
* Defines global server-side chat relay event listeners
* @param {Socket} socket - Requesting Socket
*/
defineListeners(socket){ defineListeners(socket){
socket.on("chatMessage", (data) => {this.handleChat(socket, data)}); socket.on("chatMessage", (data) => {this.handleChat(socket, data)});
socket.on("setFlair", (data) => {this.setFlair(socket, data)}); socket.on("setFlair", (data) => {this.setFlair(socket, data)});
@ -43,10 +54,20 @@ module.exports = class{
socket.on("deletePersonalEmote", (data) => {this.deletePersonalEmote(socket, data)}); socket.on("deletePersonalEmote", (data) => {this.deletePersonalEmote(socket, data)});
} }
/**
* Handles incoming chat messages from client connections
* @param {Socket} socket - Socket we're receiving the request from
* @param {Object} data - Event payload
*/
handleChat(socket, data){ handleChat(socket, data){
this.commandPreprocessor.preprocess(socket, data); this.commandPreprocessor.preprocess(socket, data);
} }
/**
* Handles incoming client request to change flair
* @param {Socket} socket - Socket we're receiving the request from
* @param {Object} data - Event payload
*/
async setFlair(socket, data){ async setFlair(socket, data){
var userDB = await userModel.findOne({user: socket.user.user}); var userDB = await userModel.findOne({user: socket.user.user});
@ -66,6 +87,11 @@ module.exports = class{
} }
} }
/**
* Handles incoming client request to change high level
* @param {Socket} socket - Socket we're receiving the request from
* @param {Object} data - Event payload
*/
async setHighLevel(socket, data){ async setHighLevel(socket, data){
var userDB = await userModel.findOne({user: socket.user.user}); var userDB = await userModel.findOne({user: socket.user.user});
@ -89,6 +115,11 @@ module.exports = class{
} }
} }
/**
* Handles incoming client request to add a personal emote
* @param {Socket} socket - Socket we're receiving the request from
* @param {Object} data - Event payload
*/
async addPersonalEmote(socket, data){ async addPersonalEmote(socket, data){
//Sanatize and Validate input //Sanatize and Validate input
const name = emoteValidator.manualName(data.name); const name = emoteValidator.manualName(data.name);
@ -119,6 +150,11 @@ module.exports = class{
} }
} }
/**
* Handles incoming client request to delete a personal emote
* @param {Socket} socket - Socket we're receiving the request from
* @param {Object} data - Event payload
*/
async deletePersonalEmote(socket, data){ async deletePersonalEmote(socket, data){
//Get user doc from DB based on socket //Get user doc from DB based on socket
const userDB = await userModel.findOne({user: socket.user.user}); const userDB = await userModel.findOne({user: socket.user.user});
@ -130,10 +166,25 @@ module.exports = class{
} }
//Base chat functions //Base chat functions
/**
* Creates a new chatObject and relays the resulting message to the given channel
* @param {String} user - Originating user
* @param {String} flair - Flair ID to mark chat with
* @param {Number} highLevel - High Level to mark chat with
* @param {String} msg - Message Text Content
* @param {String} type - Message Type, used for client-side chat post-processing.
* @param {String} chan - Channel to broadcast message within
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
*/
relayChat(user, flair, highLevel, msg, type = 'chat', chan, links){ relayChat(user, flair, highLevel, msg, type = 'chat', chan, links){
this.relayChatObject(chan, new chat(user, flair, highLevel, msg, type, links)); this.relayChatObject(chan, new chat(user, flair, highLevel, msg, type, links));
} }
/**
* Relays an existing chat object to a channel
* @param {String} chan - Channel to broadcast message within
* @param {chat} chat - Chat Object representing the message to broadcast to the given channel
*/
relayChatObject(chan, chat){ relayChatObject(chan, chat){
//Send out chat //Send out chat
this.server.io.in(chan).emit("chatMessage", chat); this.server.io.in(chan).emit("chatMessage", chat);
@ -150,46 +201,107 @@ module.exports = class{
channel.chatBuffer.push(chat); channel.chatBuffer.push(chat);
} }
/**
* Creates a new chatObject and relays the resulting message to the given socket
* @param {Socket} socket - Socket we're sending a message to (sounds menacing, huh?)
* @param {String} user - Originating user
* @param {String} flair - Flair ID to mark chat with
* @param {Number} highLevel - High Level to mark chat with
* @param {String} msg - Message Text Content
* @param {String} type - Message Type, used for client-side chat post-processing.
* @param {String} chan - Channel to broadcast message within
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
*/
relayPrivateChat(socket, user, flair, highLevel, msg, type, links){ relayPrivateChat(socket, user, flair, highLevel, msg, type, links){
this.relayPrivateChatObject(socket , new chat(user, flair, highLevel, msg, type, links)); this.relayPrivateChatObject(socket , new chat(user, flair, highLevel, msg, type, links));
} }
/**
* Handles incoming client request to delete a personal emote
* @param {Socket} socket - Socket we're receiving the request from
* @param {Object} data - Event payload
*/
relayPrivateChatObject(socket, chat){ relayPrivateChatObject(socket, chat){
socket.emit("chatMessage", chat); socket.emit("chatMessage", chat);
} }
/**
* Creates a new chatObject and relays the resulting message to the entire server
* @param {String} user - Originating user
* @param {String} flair - Flair ID to mark chat with
* @param {Number} highLevel - High Level to mark chat with
* @param {String} msg - Message Text Content
* @param {String} type - Message Type, used for client-side chat post-processing.
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
*/
relayGlobalChat(user, flair, highLevel, msg, type = 'chat', links){ relayGlobalChat(user, flair, highLevel, msg, type = 'chat', links){
this.relayGlobalChatObject(new chat(user, flair, highLevel, msg, type, links)); this.relayGlobalChatObject(new chat(user, flair, highLevel, msg, type, links));
} }
/**
* Relays an existing chat object to the entire server
* @param {chat} chat - Chat Object representing the message to broadcast throughout the server
*/
relayGlobalChatObject(chat){ relayGlobalChatObject(chat){
this.server.io.emit("chatMessage", chat); this.server.io.emit("chatMessage", chat);
} }
//User Chat Functions //User Chat Functions
/**
* Relays a chat message from a user to the rest of the channel based on socket
* @param {Socket} socket - Socket we're receiving the request from
* @param {String} msg - Message Text Content
* @param {String} type - Message Type, used for client-side chat post-processing.
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
*/
relayUserChat(socket, msg, type, links){ relayUserChat(socket, msg, type, links){
const user = this.server.getSocketInfo(socket); const user = this.server.getSocketInfo(socket);
this.relayChat(user.user, user.flair, user.highLevel, msg, type, socket.chan, links); this.relayChat(user.user, user.flair, user.highLevel, msg, type, socket.chan, links);
} }
//Toke Chat Functions //Toke Chat Functions
/**
* Broadcasts toke callout to the server
* @param {String} msg - Message Text Content
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
*/
relayTokeCallout(msg, links){ relayTokeCallout(msg, links){
this.relayGlobalChat("Tokebot", "", '∞', msg, "toke", links); this.relayGlobalChat("Tokebot", "", '∞', msg, "toke", links);
} }
/**
* Broadcasts toke callout to the server
* @param {Socket} socket - Socket we're sending the whisper to
* @param {String} msg - Message Text Content
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
*/
relayTokeWhisper(socket, msg, links){ relayTokeWhisper(socket, msg, links){
this.relayPrivateChat(socket, "Tokebot", "", '∞', msg, "tokewhisper", links); this.relayPrivateChat(socket, "Tokebot", "", '∞', msg, "tokewhisper", links);
} }
/**
* Broadcasts toke whisper to the server
* @param {String} msg - Message Text Content
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
*/
relayGlobalTokeWhisper(msg, links){ relayGlobalTokeWhisper(msg, links){
this.relayGlobalChat("Tokebot", "", '∞', msg, "tokewhisper", links); this.relayGlobalChat("Tokebot", "", '∞', msg, "tokewhisper", links);
} }
//Announcement Functions //Announcement Functions
/**
* Broadcasts announcement to the server
* @param {String} msg - Message Text Content
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
*/
relayServerAnnouncement(msg, links){ relayServerAnnouncement(msg, links){
this.relayGlobalChat("Server", "", '∞', msg, "announcement", links); this.relayGlobalChat("Server", "", '∞', msg, "announcement", links);
} }
/**
* Broadcasts announcement to a given channel
* @param {String} msg - Message Text Content
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
*/
relayChannelAnnouncement(chan, msg, links){ relayChannelAnnouncement(chan, msg, links){
const activeChan = this.server.activeChannels.get(chan); const activeChan = this.server.activeChannels.get(chan);
@ -200,6 +312,11 @@ module.exports = class{
} }
//Misc Functions //Misc Functions
/**
* Clears chat for a given channel, targets specified user or entire channel if none found/specified.
* @param {String} user - User chats to clear
* @param {String} chan - Channel to broadcast message within
*/
clearChat(chan, user){ clearChat(chan, user){
const activeChan = this.server.activeChannels.get(chan); const activeChan = this.server.activeChannels.get(chan);

View file

@ -23,7 +23,15 @@ const linkUtils = require('../../utils/linkUtils');
const permissionModel = require('../../schemas/permissionSchema'); const permissionModel = require('../../schemas/permissionSchema');
const channelModel = require('../../schemas/channel/channelSchema'); const channelModel = require('../../schemas/channel/channelSchema');
/**
* Class containing global server-side chat/command pre-processing logic
*/
module.exports = class commandPreprocessor{ module.exports = class commandPreprocessor{
/**
* Instantiates a commandPreprocessor object
* @param {channelManager} server - Parent Server Object
* @param {chatHandler} chatHandler - Parent Chat Handler Object
*/
constructor(server, chatHandler){ constructor(server, chatHandler){
this.server = server; this.server = server;
this.chatHandler = chatHandler; this.chatHandler = chatHandler;
@ -31,6 +39,11 @@ module.exports = class commandPreprocessor{
this.tokebot = new tokebot(server, chatHandler); this.tokebot = new tokebot(server, chatHandler);
} }
/**
* Ingests a command/chat request from Chat Handler and pre-processes and processes it accordingly
* @param {Socket} socket - Socket we're receiving the request from
* @param {Object} data - Event payload
*/
async preprocess(socket, data){ async preprocess(socket, data){
//Set command object //Set command object
const commandObj = { const commandObj = {
@ -61,6 +74,11 @@ module.exports = class commandPreprocessor{
} }
} }
/**
* Sanatizes and Validates a single user chat message/command
* @param {Object} commandObj - Object representing a single given command/chat request
* @returns {Boolean} false if Command/Message is too long to send
*/
sanatizeCommand(commandObj){ sanatizeCommand(commandObj){
//Trim and Sanatize for XSS //Trim and Sanatize for XSS
commandObj.command = validator.trim(validator.escape(commandObj.rawData.msg)); commandObj.command = validator.trim(validator.escape(commandObj.rawData.msg));
@ -69,17 +87,27 @@ module.exports = class commandPreprocessor{
return (validator.isLength(commandObj.rawData.msg, {min: 1, max: 255})); return (validator.isLength(commandObj.rawData.msg, {min: 1, max: 255}));
} }
/**
* Splits raw chat/command data into seperate arrays, one by word-borders and words surrounded by word-borders
* These arrays are used to handle further command/chat processing
* @param {Object} commandObj - Object representing a single given command/chat request
*/
splitCommand(commandObj){ splitCommand(commandObj){
//Split string by words //Split string by words
commandObj.commandArray = commandObj.command.split(/\b/g);//Split by word-borders commandObj.commandArray = commandObj.command.split(/\b/g);//Split by word-borders
commandObj.argumentArray = commandObj.command.match(/\b\w+\b/g);//Match by words surrounded by borders commandObj.argumentArray = commandObj.command.match(/\b\w+\b/g);//Match by words surrounded by borders
} }
/**
* Uses the server's Command Processor object to process the chat/command request.
* @param {Object} commandObj - Object representing a single given command/chat request
*/
async processServerCommand(commandObj){ async processServerCommand(commandObj){
//If the raw message starts with '!' (skip commands that start with whitespace so people can send example commands in chat) //If the raw message starts with '!' (skip commands that start with whitespace so people can send example commands in chat)
if(commandObj.rawData.msg[0] == '!'){ if(commandObj.rawData.msg[0] == '!'){
//if it isn't just an exclimation point, and we have a real command //if it isn't just an exclimation point, and we have a real command
if(commandObj.argumentArray != null){ if(commandObj.argumentArray != null){
//If the command processor knows what to do with whatever the fuck the user sent us
if(this.commandProcessor[commandObj.argumentArray[0].toLowerCase()] != null){ if(this.commandProcessor[commandObj.argumentArray[0].toLowerCase()] != null){
//Process the command and use the return value to set the sendflag (true if command valid) //Process the command and use the return value to set the sendflag (true if command valid)
commandObj.sendFlag = await this.commandProcessor[commandObj.argumentArray[0].toLowerCase()](commandObj, this); commandObj.sendFlag = await this.commandProcessor[commandObj.argumentArray[0].toLowerCase()](commandObj, this);
@ -91,6 +119,10 @@ module.exports = class commandPreprocessor{
} }
} }
/**
* Iterates through links in message and marks them by link type for later use by client-side post-processing
* @param {Object} commandObj - Object representing a single given command/chat request
*/
async markLinks(commandObj){ async markLinks(commandObj){
//Setup the links array //Setup the links array
commandObj.links = []; commandObj.links = [];
@ -103,6 +135,10 @@ module.exports = class commandPreprocessor{
} }
} }
/**
* Re-creates message string from processed Command Array
* @param {Object} commandObj - Object representing a single given command/chat request
*/
async prepMessage(commandObj){ async prepMessage(commandObj){
//Create message from commandArray //Create message from commandArray
commandObj.message = commandObj.commandArray.join('').trimStart(); commandObj.message = commandObj.commandArray.join('').trimStart();
@ -110,19 +146,36 @@ module.exports = class commandPreprocessor{
await this.markLinks(commandObj); await this.markLinks(commandObj);
} }
/**
* Relays chat to channel via parent Chat Handler object
* @param {Object} commandObj - Object representing a single given command/chat request
*/
sendChat(commandObj){ sendChat(commandObj){
//FUCKIN' SEND IT! //FUCKIN' SEND IT!
this.chatHandler.relayUserChat(commandObj.socket, commandObj.message, commandObj.chatType, commandObj.links); this.chatHandler.relayUserChat(commandObj.socket, commandObj.message, commandObj.chatType, commandObj.links);
} }
} }
/**
* Class representing global server-side chat/command processing logic
*/
class commandProcessor{ class commandProcessor{
/**
* Instantiates a commandProcessor object
* @param {channelManager} server - Parent Server Object
* @param {chatHandler} chatHandler - Parent Chat Handler Object
*/
constructor(server, chatHandler){ constructor(server, chatHandler){
this.server = server; this.server = server;
this.chatHandler = chatHandler; this.chatHandler = chatHandler;
} }
//Command keywords get run through .toLowerCase(), so we should use lowercase method names for command methods //Command keywords get run through .toLowerCase(), so we should use lowercase method names for command methods
/**
* Command Processor method to handle the '!whisper' command
* @param {Object} commandObj - Object representing a single given command/chat request
* @returns {Boolean} True to enable send flag
*/
whisper(commandObj){ whisper(commandObj){
//splice out our command //splice out our command
commandObj.commandArray.splice(0,2); commandObj.commandArray.splice(0,2);
@ -134,6 +187,11 @@ class commandProcessor{
return true return true
} }
/**
* Command Processor method to handle the '!spoiler' command
* @param {Object} commandObj - Object representing a single given command/chat request
* @returns {Boolean} True to enable send flag
*/
spoiler(commandObj){ spoiler(commandObj){
//splice out our command //splice out our command
commandObj.commandArray.splice(0,2); commandObj.commandArray.splice(0,2);
@ -145,6 +203,11 @@ class commandProcessor{
return true return true
} }
/**
* Command Processor method to handle the '!strikethrough' command
* @param {Object} commandObj - Object representing a single given command/chat request
* @returns {Boolean} True to enable send flag
*/
strikethrough(commandObj){ strikethrough(commandObj){
//splice out our command //splice out our command
commandObj.commandArray.splice(0,2); commandObj.commandArray.splice(0,2);
@ -156,6 +219,11 @@ class commandProcessor{
return true return true
} }
/**
* Command Processor method to handle the '!bold' command
* @param {Object} commandObj - Object representing a single given command/chat request
* @returns {Boolean} True to enable send flag
*/
bold(commandObj){ bold(commandObj){
//splice out our command //splice out our command
commandObj.commandArray.splice(0,2); commandObj.commandArray.splice(0,2);
@ -167,6 +235,11 @@ class commandProcessor{
return true return true
} }
/**
* Command Processor method to handle the '!italics' command
* @param {Object} commandObj - Object representing a single given command/chat request
* @returns {Boolean} True to enable send flag
*/
italics(commandObj){ italics(commandObj){
//splice out our command //splice out our command
commandObj.commandArray.splice(0,2); commandObj.commandArray.splice(0,2);
@ -178,6 +251,11 @@ class commandProcessor{
return true return true
} }
/**
* Command Processor method to handle the '!announce' command
* @param {Object} commandObj - Object representing a single given command/chat request
* @returns {Boolean} True to enable send flag on un-authorized call to shame the user
*/
async announce(commandObj, preprocessor){ async announce(commandObj, preprocessor){
//Get the current channel from the database //Get the current channel from the database
const chanDB = await channelModel.findOne({name: commandObj.socket.chan}); const chanDB = await channelModel.findOne({name: commandObj.socket.chan});
@ -201,6 +279,11 @@ class commandProcessor{
return true; return true;
} }
/**
* Command Processor method to handle the '!serverannounce' command
* @param {Object} commandObj - Object representing a single given command/chat request
* @returns {Boolean} True to enable send flag on un-authorized call to shame the user
*/
async serverannounce(commandObj, preprocessor){ async serverannounce(commandObj, preprocessor){
//Check if the user has permission, and publicly shame them if they don't (lmao) //Check if the user has permission, and publicly shame them if they don't (lmao)
if(await permissionModel.permCheck(commandObj.socket.user, 'announce')){ if(await permissionModel.permCheck(commandObj.socket.user, 'announce')){
@ -221,6 +304,11 @@ class commandProcessor{
return true; return true;
} }
/**
* Command Processor method to handle the '!resettoke' command
* @param {Object} commandObj - Object representing a single given command/chat request
* @returns {Boolean} True to enable send flag on un-authorized call to shame the user
*/
async resettoke(commandObj, preprocessor){ async resettoke(commandObj, preprocessor){
//Check if the user has permission, and publicly shame them if they don't (lmao) //Check if the user has permission, and publicly shame them if they don't (lmao)
if(await permissionModel.permCheck(commandObj.socket.user, 'resetToke')){ if(await permissionModel.permCheck(commandObj.socket.user, 'resetToke')){
@ -238,6 +326,11 @@ class commandProcessor{
return true; return true;
} }
/**
* Command Processor method to handle the '!clear' command
* @param {Object} commandObj - Object representing a single given command/chat request
* @returns {Boolean} True to enable send flag on un-authorized call to shame the user
*/
async clear(commandObj){ async clear(commandObj){
//Get the current channel from the database //Get the current channel from the database
const chanDB = await channelModel.findOne({name: commandObj.socket.chan}); const chanDB = await channelModel.findOne({name: commandObj.socket.chan});
@ -254,6 +347,11 @@ class commandProcessor{
return true; return true;
} }
/**
* Command Processor method to handle the '!kick' command
* @param {Object} commandObj - Object representing a single given command/chat request
* @returns {Boolean} True to enable send flag on un-authorized call to shame the user
*/
async kick(commandObj){ async kick(commandObj){
//Get the current channel from the database //Get the current channel from the database
const chanDB = await channelModel.findOne({name: commandObj.socket.chan}); const chanDB = await channelModel.findOne({name: commandObj.socket.chan});

View file

@ -22,7 +22,17 @@ const flairModel = require('../../schemas/flairSchema');
const emoteModel = require('../../schemas/emoteSchema'); const emoteModel = require('../../schemas/emoteSchema');
const { userModel } = require('../../schemas/user/userSchema'); const { userModel } = require('../../schemas/user/userSchema');
/**
* Class representing a single user connected to a channel
*/
module.exports = class{ module.exports = class{
/**
* Instantiates a connectedUser object
* @param {Mongoose.Document} userDB - User document to re-hydrate user from
* @param {PemissionModel.chanRank} chanRank - Enum representing user channel rank
* @param {String} - Channel the user is connecting to
* @param {Socket} socket - Socket associated with the users connection
*/
constructor(userDB, chanRank, channel, socket){ constructor(userDB, chanRank, channel, socket){
this.id = userDB.id; this.id = userDB.id;
this.user = userDB.user; this.user = userDB.user;
@ -44,6 +54,12 @@ module.exports = class{
this.sockets = [socket.id]; this.sockets = [socket.id];
} }
/**
* Handles server-side initialization for new connections from a specific user
* @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
* @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
* @param {Socket} socket - Requesting Socket
*/
async handleConnection(userDB, chanDB, socket){ async handleConnection(userDB, chanDB, socket){
//send metadata to client //send metadata to client
this.sendClientMetadata(); this.sendClientMetadata();
@ -69,6 +85,10 @@ module.exports = class{
} }
} }
/**
* Iterates through all known connections for a given user, running them through a supplied callback function
* @param {Function} cb - Callback to call against found sockets for a given user
*/
socketCrawl(cb){ socketCrawl(cb){
//Crawl through user's sockets (lol) //Crawl through user's sockets (lol)
this.sockets.forEach((sockid) => { this.sockets.forEach((sockid) => {
@ -79,22 +99,33 @@ module.exports = class{
}); });
} }
//My brain keeps going back to using dynamic per-user namespaces for this
//but everytime i look into it I come to the conclusion that it's a bad idea, then I toy with making chans namespaces /**
//and using per-user channels for this, but what of gold or mod-only features? or games? * Emits an event to all known sockets for a given user
//No matter what it'd probably end up hacky, as namespaces where meant for splitting app logic not user comms (like rooms). *
//at the end of the day there has to be some penance for decent multi-session handling on-top of a library that doesn't do it. * My brain keeps going back to using dynamic per-user namespaces for this
//Having to crawl through these sockets is that. Because the other ways seem more gross somehow. * but everytime i look into it I come to the conclusion that it's a bad idea, then I toy with making chans namespaces
emit(eventName, args){ * and using per-user channels for this, but what of gold or mod-only features? or games?
* No matter what it'd probably end up hacky, as namespaces where meant for splitting app logic not user comms (like rooms).
* at the end of the day there has to be some penance for decent multi-session handling on-top of a library that doesn't do it.
* Having to crawl through these sockets is that. Because the other ways seem more gross somehow.
* @param {String} eventName - Event name to emit to client sockets
* @param {Object} data - Data to emit to client sockets
*/
emit(eventName, data){
this.socketCrawl((socket)=>{ this.socketCrawl((socket)=>{
//Ensure our socket is initialized //Ensure our socket is initialized
if(socket != null){ if(socket != null){
socket.emit(eventName, args); socket.emit(eventName, data);
} }
}); });
} }
//generic disconnect function, defaults to kick /**
* Disconnects all sockets for a given user
* @param {String} reason - Reason for being disconnected
* @param {String} type - Disconnection Type
*/
disconnect(reason, type = "Disconnected"){ disconnect(reason, type = "Disconnected"){
this.emit("kick",{type, reason}); this.emit("kick",{type, reason});
this.socketCrawl((socket)=>{socket.disconnect()}); this.socketCrawl((socket)=>{socket.disconnect()});
@ -102,6 +133,11 @@ module.exports = class{
//This is the big first push upon connection //This is the big first push upon connection
//It should only fire once, so things that only need to be sent once can be slapped into here //It should only fire once, so things that only need to be sent once can be slapped into here
/**
* Sends glut of required initial metadata to the client upon a new connection
* @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
* @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
*/
async sendClientMetadata(userDB, chanDB){ async sendClientMetadata(userDB, chanDB){
//Get flairList from DB and setup flairList array //Get flairList from DB and setup flairList array
const flairListDB = await flairModel.find({}); const flairListDB = await flairModel.find({});
@ -166,6 +202,9 @@ module.exports = class{
this.emit("clientMetadata", {user: userObj, flairList, queue, queueLock, chatBuffer}); this.emit("clientMetadata", {user: userObj, flairList, queue, queueLock, chatBuffer});
} }
/**
* Send copy of site emotes to the user
*/
async sendSiteEmotes(){ async sendSiteEmotes(){
//Get emote list from DB //Get emote list from DB
const emoteList = await emoteModel.getEmotes(); const emoteList = await emoteModel.getEmotes();
@ -174,6 +213,10 @@ module.exports = class{
this.emit('siteEmotes', emoteList); this.emit('siteEmotes', emoteList);
} }
/**
* Send copy of channel emotes to the user
* @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
*/
async sendChanEmotes(chanDB){ async sendChanEmotes(chanDB){
//if we wherent handed a channel document //if we wherent handed a channel document
if(chanDB == null){ if(chanDB == null){
@ -188,6 +231,10 @@ module.exports = class{
this.emit('chanEmotes', emoteList); this.emit('chanEmotes', emoteList);
} }
/**
* Send copy of channel emotes to the user
* @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
*/
async sendPersonalEmotes(userDB){ async sendPersonalEmotes(userDB){
//if we wherent handed a user document //if we wherent handed a user document
if(userDB == null){ if(userDB == null){
@ -202,6 +249,10 @@ module.exports = class{
this.emit('personalEmotes', emoteList); this.emit('personalEmotes', emoteList);
} }
/**
* Send copy of channel emotes to the user
* @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
*/
async sendUsedTokes(userDB){ async sendUsedTokes(userDB){
//if we wherent handed a user document //if we wherent handed a user document
if(userDB == null){ if(userDB == null){
@ -215,6 +266,10 @@ module.exports = class{
}); });
} }
/**
* Set flair for a given user and broadcast update to clients
* @param {String} flair - Flair string to update user's flair to
*/
updateFlair(flair){ updateFlair(flair){
this.flair = flair; this.flair = flair;
@ -222,6 +277,10 @@ module.exports = class{
this.sendClientMetadata(); this.sendClientMetadata();
} }
/**
* Set high level for a given user and broadcast update to clients
* @param {Number} highLevel - Number to update user's high-level to
*/
updateHighLevel(highLevel){ updateHighLevel(highLevel){
this.highLevel = highLevel; this.highLevel = highLevel;

View file

@ -17,11 +17,18 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
//Local Imports //Local Imports
const tokeCommandModel = require('../../schemas/tokebot/tokeCommandSchema'); const tokeCommandModel = require('../../schemas/tokebot/tokeCommandSchema');
const {userModel} = require('../../schemas/user/userSchema'); const {userModel} = require('../../schemas/user/userSchema');
const statModel = require('../../schemas/statSchema');
const statSchema = require('../../schemas/statSchema'); const statSchema = require('../../schemas/statSchema');
/**
* Class containing global server-side tokebot logic
*/
module.exports = class tokebot{ module.exports = class tokebot{
/**
* Instantiates a tokebot object
* @param {channelManager} server - Parent Server Object
* @param {chatHandler} chatHandler - Parent Chat Handler Object
*/
constructor(server, chatHandler){ constructor(server, chatHandler){
//Set parents //Set parents
this.server = server; this.server = server;
@ -46,11 +53,19 @@ module.exports = class tokebot{
this.refreshCommands(); this.refreshCommands();
} }
/**
* Reloads toke commands from DB into RAM-based toke command store
*/
async refreshCommands(){ async refreshCommands(){
//Pull Command Strings from DB //Pull Command Strings from DB
this.tokeCommands = await tokeCommandModel.getCommandStrings(); this.tokeCommands = await tokeCommandModel.getCommandStrings();
} }
/**
* Processes toke commands from Command Pre-Processor
* @param {Object} commandObj - Object representing a single given command/chat request, passed down from the Command Pre-Processor
* @returns {Boolean} True if the toke is an invalid toke command (tells Command Pre-Processor to send command as chat)
*/
tokeProcessor(commandObj){ tokeProcessor(commandObj){
//Check for site-wide toke commands //Check for site-wide toke commands
if(this.tokeCommands.indexOf(commandObj.argumentArray[0].toLowerCase()) != -1){ if(this.tokeCommands.indexOf(commandObj.argumentArray[0].toLowerCase()) != -1){
@ -127,6 +142,9 @@ module.exports = class tokebot{
} }
} }
/**
* Called each second during the toke. Handles decrementing the timer variable, and countdown end logic.
*/
countdown(){ countdown(){
//If we're in the last three seconds //If we're in the last three seconds
if(this.tokeCounter <= 3 && this.tokeCounter > 0){ if(this.tokeCounter <= 3 && this.tokeCounter > 0){
@ -169,6 +187,10 @@ module.exports = class tokebot{
this.tokeTimer = setTimeout(this.countdown.bind(this), 1000) this.tokeTimer = setTimeout(this.countdown.bind(this), 1000)
} }
/**
* This method seems to be a vestage from a bygone era. We should remove it after documenting shit.
* I would now, but I don't want to break shit in a comment-only commit.
*/
async asyncFinisher(){ async asyncFinisher(){
//Grab a copy of the tokers map before it gets cleared out //Grab a copy of the tokers map before it gets cleared out
const tokers = this.tokers; const tokers = this.tokers;
@ -177,6 +199,9 @@ module.exports = class tokebot{
await userModel.tattooToke(tokers); await userModel.tattooToke(tokers);
} }
/**
* Runs every second for 60 seconds after a toke
*/
cooldown(){ cooldown(){
//If the cooldown timer isn't over //If the cooldown timer isn't over
if(this.cooldownCounter > 0){ if(this.cooldownCounter > 0){
@ -191,6 +216,9 @@ module.exports = class tokebot{
} }
} }
/**
* Resets toke cooldowns early upon authorized request
*/
resetToke(){ resetToke(){
//Set cooldown to 0 //Set cooldown to 0
this.cooldownCounter = 0; this.cooldownCounter = 0;