Archived
0
0
Fork 0

feat(commands): added basic command handler

This commit is contained in:
Daryl Ronningen 2021-06-20 02:39:44 -07:00
parent 6b22ebdb9c
commit 7ad0d4bae4
Signed by: Daryl Ronningen
GPG key ID: FD23F0C934A5EC6B
9 changed files with 174 additions and 22 deletions

View file

@ -1,4 +1,5 @@
{
"token": "",
"logLevel": "info"
"logLevel": "",
"prefix": ""
}

View file

@ -156,6 +156,16 @@
"license-header.txt"
],
"no-case-declarations": "off",
"keyword-spacing": ["error", {"overrides": {
"if": {
"before": false,
"after": false
},
"catch": {
"before": true,
"after": false
}
}}],
"@typescript-eslint/no-non-null-assertion": "off"
},
"reportUnusedDisableDirectives": true
@ -186,6 +196,7 @@
"@": "dist",
"@src": "dist/src",
"@lib": "dist/src/lib",
"@utils": "dist/src/lib/utils/"
"@utils": "dist/src/lib/utils/",
"@structures": "dist/src/lib/structures"
}
}

View file

@ -23,10 +23,16 @@ import config from 'config';
import chalk from 'chalk';
import { Validator } from 'jsonschema';
import { DateTime } from 'luxon';
import { Client } from 'discord.js';
import { debug, error, info, verbose } from '@utils/logger';
import { Client, Collection } from 'discord.js';
import { debug, error, fatal, info, verbose } from '@utils/logger';
import { ELoggingScope } from '@utils/types';
import { Defaults } from '@utils/defaults';
import { walkDir } from '@utils/utils';
import type Command from '@structures/command';
let isBotReady = false;
const commands: Collection<string, Command> = new Collection();
info('Starting bot... Please wait!', ELoggingScope.Startup);
debug('Checking config JSON schema', ELoggingScope.Startup);
@ -36,7 +42,7 @@ const mergedConfig = config.util.extendDeep(Defaults.config, config.util.loadFil
const schemaValidator = new Validator();
const validate = schemaValidator.validate(mergedConfig, Defaults.configSchema);
if (validate.valid) {
if(validate.valid) {
debug('Config matches JSON schema', ELoggingScope.Startup);
} else {
// Manually send fatal message in case someone messes up the logLevel config
@ -53,7 +59,7 @@ if (validate.valid) {
}
figlet('Argon Bot', (err, data) => {
if (err) error(`Figlet encountered an error!\n${err.message}`);
if(err) error(`Figlet encountered an error!\n${err.message}`);
info(gradient.rainbow.multiline(`\n${data}`), ELoggingScope.Startup);
});
@ -62,11 +68,50 @@ const client = new Client({
intents: ['GUILDS', 'GUILD_MESSAGES'],
});
client.on('ready', () => {
client.on('message', (msg) => {
if(!isBotReady) return;
if(msg.author.bot) return;
if(!msg.content.startsWith(config.get('prefix'))) return;
const args = msg.content.slice((config.get('prefix') as string).length).trim().split(/ +/);
const command = args.shift()!.toLowerCase();
const findCommand = commands.find((com) => com.options.name === command);
if(!findCommand) return;
else findCommand.run(msg, ...args);
});
client.on('ready', async () => {
info('Loading commands...', ELoggingScope.Startup);
try {
const files = await walkDir(`${__dirname}/commands`);
files?.forEach(async (file) => {
if(file.endsWith('js')) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fileCommand = require(file).default;
const command = new fileCommand();
commands.set(command.options.name, command);
debug(`Loaded ${command.options.name}`, ELoggingScope.Startup);
}
});
info(`Finished loading commands! Found ${commands.size} commands.`, ELoggingScope.Startup);
} catch(err) {
fatal(`An error has occurred while attempting to load command files! Please see error below\n${err.message}`, ELoggingScope.Startup);
}
info('Bot is ready!', ELoggingScope.Startup);
debug(`Total number of Servers: ${client.guilds.cache.size}`, ELoggingScope.Startup);
debug(`Total number of Users: ${client.users.cache.size}`, ELoggingScope.Startup);
info('Bot is ready!', ELoggingScope.Startup);
isBotReady = true;
});
client.on('raw', (payload) => {

View file

@ -0,0 +1,30 @@
/*
* This file is part of ArgonBot
*
* ArgonBot is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ArgonBot 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ArgonBot. If not, see <https: //www.gnu.org/licenses/>.
*/
import type { Client, Message } from 'discord.js';
import type { ICommandOptions } from '@utils/types';
export default abstract class Command {
public readonly client: Client;
public readonly options: ICommandOptions
public constructor(client: Client, options: ICommandOptions) {
this.client = client;
this.options = options;
}
public abstract run(message: Message, ...args:string[]): void;
}

View file

@ -19,9 +19,7 @@ export const Defaults = {
logLevel: 'info',
},
configSchema: {
$id: 'http://example.com/example.json',
$schema: 'http://json-schema.org/draft-07/schema',
required: ['token', 'logLevel'],
required: ['token', 'logLevel', 'prefix'],
type: 'object',
properties: {
token: {
@ -40,6 +38,10 @@ export const Defaults = {
'fatal',
],
},
prefix: {
$id: '#/properties/prefix',
type: 'string',
},
},
additionalProperties: false,
},

View file

@ -70,8 +70,8 @@ export function verbose(message: string, scope?: ELoggingScope): void {
const splitMultiline = message.split('\n');
splitMultiline.forEach((val) => {
if (verboseLevel)
if (scope)
if(verboseLevel)
if(scope)
console.log(chalk`{grey (${date})} {magenta.bold ${scope}} {white.bold [VERBOSE]}: {white ${val}}`);
else
console.log(chalk`{grey (${date})} {white.bold [VERBOSE]}: {white ${val}}`);
@ -83,8 +83,8 @@ export function debug(message: string, scope?: ELoggingScope): void {
const splitMultiline = message.split('\n');
splitMultiline.forEach((val) => {
if (debugLevel)
if (scope)
if(debugLevel)
if(scope)
console.log(chalk`{grey (${date})} {magenta.bold ${scope}} {blue.bold [DEBUG]}: {blue ${val}}`);
else
console.log(chalk`{grey (${date})} {blue.bold [DEBUG]}: {blue ${val}}`);
@ -96,7 +96,7 @@ export function info(message: string, scope?: ELoggingScope): void {
const splitMultiline = message.split('\n');
splitMultiline.forEach((val) => {
if (infoLevel)
if(infoLevel)
if(scope)
console.log(chalk`{grey (${date})} {magenta.bold ${scope}} {green.bold [INFO]}: {green ${val}}`);
else
@ -109,8 +109,8 @@ export function warn(message: string, scope?: ELoggingScope): void {
const splitMultiline = message.split('\n');
splitMultiline.forEach((val) => {
if (warnLevel)
if (scope)
if(warnLevel)
if(scope)
console.log(chalk`{grey (${date})} {magenta.bold ${scope}} {yellow.bold [WARN]}: {yellow ${val}}`);
else
console.log(chalk`{grey (${date})} {yellow.bold [WARN]}: {yellow ${val}}`);
@ -122,8 +122,8 @@ export function error(message: string, scope?: ELoggingScope): void {
const splitMultiline = message.split('\n');
splitMultiline.forEach((val) => {
if (errorLevel)
if (scope)
if(errorLevel)
if(scope)
console.log(chalk`{grey (${date})} {magenta.bold ${scope}} {bold.underline.rgb(255, 165, 0) [ERROR]}: {underline.rgb(255, 165, 0) ${val}}`);
else
console.log(chalk`{grey (${date})} {bold.underline.rgb(255, 165, 0) [ERROR]}: {underline.rgb(255, 165, 0) ${val}}`);
@ -135,8 +135,8 @@ export function fatal(message: string, scope?: ELoggingScope): void {
const splitMultiline = message.split('\n');
splitMultiline.forEach((val) => {
if (fatalLevel)
if (scope)
if(fatalLevel)
if(scope)
console.log(chalk`{grey (${date})} {magenta.bold ${scope}} {red.bold.underline [FATAL]}: {red.underline ${val}}`);
else
console.log(chalk`{grey (${date})} {red.bold.underline [FATAL]}: {red.underline ${val}}`);

View file

@ -23,5 +23,10 @@ export enum ELoggingScope {
}
// Interfaces
export interface ICommandOptions {
name: string;
shortDescription: string;
extendedDescription: string;
}
// Type Aliases

55
src/lib/utils/utils.ts Normal file
View file

@ -0,0 +1,55 @@
/*
* This file is part of ArgonBot
*
* ArgonBot is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ArgonBot 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ArgonBot. If not, see <https: //www.gnu.org/licenses/>.
*/
import fs from 'fs';
import path from 'path';
export const walkDir = async (dir: string): Promise<string[]> => {
let results: string[] = [];
return new Promise((resolve, reject) => {
fs.readdir(dir, (err, list) => {
if(err) return reject(err);
let pending = list.length;
if(!pending) return resolve(results);
list.forEach((file) => {
file = path.resolve(dir, file);
fs.stat(file, async (err, stat) => {
if(err) return reject(err);
if(stat && stat.isDirectory()) {
try {
const dir = await walkDir(file);
results = results.concat(dir as unknown as string);
if(!--pending) resolve(results);
} catch(err) {
reject(err);
}
} else {
results.push(file);
if(!--pending) resolve(results);
}
});
});
});
});
};

View file

@ -65,6 +65,9 @@
],
"@utils/*": [
"src/lib/utils/*"
],
"@structures/*": [
"src/lib/structures/*"
]
}
},