diff --git a/src/app/channel/commandPreprocessor.js b/src/app/channel/commandPreprocessor.js
index 8b75261..c08c653 100644
--- a/src/app/channel/commandPreprocessor.js
+++ b/src/app/channel/commandPreprocessor.js
@@ -18,6 +18,7 @@ along with this program. If not, see .*/
const validator = require('validator');//No express here, so regular validator it is!
//Local Imports
+const chatPreprocessor = require('../chatPreprocessor');
const tokebot = require('./tokebot');
const linkUtils = require('../../utils/linkUtils');
const permissionModel = require('../../schemas/permissionSchema');
@@ -26,148 +27,20 @@ const channelModel = require('../../schemas/channel/channelSchema');
/**
* Class containing global server-side chat/command pre-processing logic
*/
-class commandPreprocessor{
+class commandPreprocessor extends chatPreprocessor{
/**
* Instantiates a commandPreprocessor object
* @param {channelManager} server - Parent Server Object
* @param {chatHandler} chatHandler - Parent Chat Handler Object
*/
constructor(server, chatHandler){
- /**
- * Parent Server Object
- */
- this.server = server;
-
- /**
- * Parent Chat Handler Object
- */
- this.chatHandler = chatHandler;
-
- /**
- * Child Command Processor Object
- */
- this.commandProcessor = new commandProcessor(server, chatHandler);
-
- /**
- * Child Tokebot Object
- */
- 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){
- //Set command object
- const commandObj = {
- socket,
- sendFlag: true,
- rawData: data,
- chatType: 'chat'
- }
-
- //If we don't pass sanatization/validation turn this car around
- if(!this.sanatizeCommand(commandObj)){
- return;
- }
-
- //split the command
- this.splitCommand(commandObj);
-
- //Process the command
- await this.processServerCommand(commandObj);
-
- //If we're going to relay this command as a message, continue on to chat processing
- if(commandObj.sendFlag){
- //Prep the message
- await this.prepMessage(commandObj);
-
- //Send the chat
- this.sendChat(commandObj);
- }
- }
-
- /**
- * 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){
- //Trim and Sanatize for XSS
- commandObj.command = validator.trim(validator.escape(commandObj.rawData.msg));
-
- //Return whether or not the shit was long enough
- 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){
- //Split string by words
- 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
- }
-
- /**
- * 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){
- //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 it isn't just an exclimation point, and we have a real command
- 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){
- //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);
- }else{
- //Process as toke command if we didnt get a match from the standard server-side command processor
- commandObj.sendFlag = await this.tokebot.tokeProcessor(commandObj);
- }
- }
- }
- }
-
- /**
- * 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){
- //Setup the links array
- commandObj.links = [];
-
- //For each link sent from the client
- //this.rawData.links.forEach((link) => {
- for (const link of commandObj.rawData.links){
- //Add a marked link object to our links array
- commandObj.links.push(await linkUtils.markLink(link));
- }
- }
-
- /**
- * Re-creates message string from processed Command Array
- * @param {Object} commandObj - Object representing a single given command/chat request
- */
- async prepMessage(commandObj){
- //Create message from commandArray
- commandObj.message = commandObj.commandArray.join('').trimStart();
- //Validate links and mark them by embed type
- 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){
- //FUCKIN' SEND IT!
- this.chatHandler.relayUserChat(commandObj.socket, commandObj.message, commandObj.chatType, commandObj.links);
+ //Call derived constructor
+ super(
+ server,
+ chatHandler,
+ new commandProcessor(server, chatHandler),
+ new tokebot(server, chatHandler)
+ );
}
}
diff --git a/src/app/chatPreprocessor.js b/src/app/chatPreprocessor.js
new file mode 100644
index 0000000..43e77fc
--- /dev/null
+++ b/src/app/chatPreprocessor.js
@@ -0,0 +1,171 @@
+/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .*/
+
+//NPM Imports
+const validator = require('validator');//No express here, so regular validator it is!
+
+//Local Imports
+const linkUtils = require('../utils/linkUtils');
+
+/**
+ * Class containing global server-side chat/command pre-processing logic
+ */
+class chatPreprocessor{
+ /**
+ * Instantiates a commandPreprocessor object
+ * @param {channelManager} server - Parent Server Object
+ * @param {chatHandler} chatHandler - Parent Chat Handler Object
+ */
+ constructor(server, chatHandler, commandProcessor, tokebot){
+ /**
+ * Parent Server Object
+ */
+ this.server = server;
+
+ /**
+ * Parent Chat Handler Object
+ */
+ this.chatHandler = chatHandler;
+
+ /**
+ * Child Command Processor Object. Contains functions named after commands.
+ */
+ this.commandProcessor = commandProcessor;
+
+ /**
+ * Child Tokebot Object
+ */
+ this.tokebot = tokebot;
+ }
+
+ /**
+ * 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){
+ //Set command object
+ const commandObj = {
+ socket,
+ sendFlag: true,
+ rawData: data,
+ chatType: 'chat'
+ }
+
+ //If we don't pass sanatization/validation turn this car around
+ if(!this.sanatizeCommand(commandObj)){
+ return;
+ }
+
+ //split the command
+ this.splitCommand(commandObj);
+
+ //Process the command
+ await this.processServerCommand(commandObj);
+
+ //If we're going to relay this command as a message, continue on to chat processing
+ if(commandObj.sendFlag){
+ //Prep the message
+ await this.prepMessage(commandObj);
+
+ //Send the chat
+ this.sendChat(commandObj);
+ }
+ }
+
+ /**
+ * 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){
+ //Trim and Sanatize for XSS
+ commandObj.command = validator.trim(validator.escape(commandObj.rawData.msg));
+
+ //Return whether or not the shit was long enough
+ 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){
+ //Split string by words
+ 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
+ }
+
+ /**
+ * 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){
+ //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 it isn't just an exclimation point, and we have a real command
+ 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){
+ //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);
+ }else{
+ //Process as toke command if we didnt get a match from the standard server-side command processor
+ commandObj.sendFlag = await this.tokebot.tokeProcessor(commandObj);
+ }
+ }
+ }
+ }
+
+ /**
+ * 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){
+ //Setup the links array
+ commandObj.links = [];
+
+ //For each link sent from the client
+ //this.rawData.links.forEach((link) => {
+ for (const link of commandObj.rawData.links){
+ //Add a marked link object to our links array
+ commandObj.links.push(await linkUtils.markLink(link));
+ }
+ }
+
+ /**
+ * Re-creates message string from processed Command Array
+ * @param {Object} commandObj - Object representing a single given command/chat request
+ */
+ async prepMessage(commandObj){
+ //Create message from commandArray
+ commandObj.message = commandObj.commandArray.join('').trimStart();
+ //Validate links and mark them by embed type
+ 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){
+ //FUCKIN' SEND IT!
+ this.chatHandler.relayUserChat(commandObj.socket, commandObj.message, commandObj.chatType, commandObj.links);
+ }
+}
+
+module.exports = chatPreprocessor;
\ No newline at end of file
diff --git a/src/schemas/channel/chatSchema.js b/src/schemas/channel/chatSchema.js
index 537afd0..c0d81b0 100644
--- a/src/schemas/channel/chatSchema.js
+++ b/src/schemas/channel/chatSchema.js
@@ -32,10 +32,11 @@ const chatSchema = new mongoose.Schema({
},
flair: {
type: mongoose.SchemaTypes.String,
- required: true,
+ //Leave this as unreq'd for internal type chats that have no flair
},
highLevel: {
type: mongoose.SchemaTypes.Number,
+ default: 0,
required: true,
},
msg: {