Split commandPreprocessor in preperation for formatted private messaging.
This commit is contained in:
parent
e81a4c0973
commit
d465863ee6
|
|
@ -18,6 +18,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||||
const validator = require('validator');//No express here, so regular validator it is!
|
const validator = require('validator');//No express here, so regular validator it is!
|
||||||
|
|
||||||
//Local Imports
|
//Local Imports
|
||||||
|
const chatPreprocessor = require('../chatPreprocessor');
|
||||||
const tokebot = require('./tokebot');
|
const tokebot = require('./tokebot');
|
||||||
const linkUtils = require('../../utils/linkUtils');
|
const linkUtils = require('../../utils/linkUtils');
|
||||||
const permissionModel = require('../../schemas/permissionSchema');
|
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 containing global server-side chat/command pre-processing logic
|
||||||
*/
|
*/
|
||||||
class commandPreprocessor{
|
class commandPreprocessor extends chatPreprocessor{
|
||||||
/**
|
/**
|
||||||
* Instantiates a commandPreprocessor object
|
* Instantiates a commandPreprocessor object
|
||||||
* @param {channelManager} server - Parent Server Object
|
* @param {channelManager} server - Parent Server Object
|
||||||
* @param {chatHandler} chatHandler - Parent Chat Handler Object
|
* @param {chatHandler} chatHandler - Parent Chat Handler Object
|
||||||
*/
|
*/
|
||||||
constructor(server, chatHandler){
|
constructor(server, chatHandler){
|
||||||
/**
|
//Call derived constructor
|
||||||
* Parent Server Object
|
super(
|
||||||
*/
|
server,
|
||||||
this.server = server;
|
chatHandler,
|
||||||
|
new commandProcessor(server, chatHandler),
|
||||||
/**
|
new tokebot(server, chatHandler)
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
171
src/app/chatPreprocessor.js
Normal file
171
src/app/chatPreprocessor.js
Normal file
|
|
@ -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 <https://www.gnu.org/licenses/>.*/
|
||||||
|
|
||||||
|
//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;
|
||||||
|
|
@ -32,10 +32,11 @@ const chatSchema = new mongoose.Schema({
|
||||||
},
|
},
|
||||||
flair: {
|
flair: {
|
||||||
type: mongoose.SchemaTypes.String,
|
type: mongoose.SchemaTypes.String,
|
||||||
required: true,
|
//Leave this as unreq'd for internal type chats that have no flair
|
||||||
},
|
},
|
||||||
highLevel: {
|
highLevel: {
|
||||||
type: mongoose.SchemaTypes.Number,
|
type: mongoose.SchemaTypes.Number,
|
||||||
|
default: 0,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
msg: {
|
msg: {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue