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": "", "token": "",
"logLevel": "info" "logLevel": "",
"prefix": ""
} }

View file

@ -156,6 +156,16 @@
"license-header.txt" "license-header.txt"
], ],
"no-case-declarations": "off", "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" "@typescript-eslint/no-non-null-assertion": "off"
}, },
"reportUnusedDisableDirectives": true "reportUnusedDisableDirectives": true
@ -186,6 +196,7 @@
"@": "dist", "@": "dist",
"@src": "dist/src", "@src": "dist/src",
"@lib": "dist/src/lib", "@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 chalk from 'chalk';
import { Validator } from 'jsonschema'; import { Validator } from 'jsonschema';
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import { Client } from 'discord.js'; import { Client, Collection } from 'discord.js';
import { debug, error, info, verbose } from '@utils/logger'; import { debug, error, fatal, info, verbose } from '@utils/logger';
import { ELoggingScope } from '@utils/types'; import { ELoggingScope } from '@utils/types';
import { Defaults } from '@utils/defaults'; 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); info('Starting bot... Please wait!', ELoggingScope.Startup);
debug('Checking config JSON schema', ELoggingScope.Startup); debug('Checking config JSON schema', ELoggingScope.Startup);
@ -62,11 +68,50 @@ const client = new Client({
intents: ['GUILDS', 'GUILD_MESSAGES'], 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 Servers: ${client.guilds.cache.size}`, ELoggingScope.Startup);
debug(`Total number of Users: ${client.users.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) => { 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', logLevel: 'info',
}, },
configSchema: { configSchema: {
$id: 'http://example.com/example.json', required: ['token', 'logLevel', 'prefix'],
$schema: 'http://json-schema.org/draft-07/schema',
required: ['token', 'logLevel'],
type: 'object', type: 'object',
properties: { properties: {
token: { token: {
@ -40,6 +38,10 @@ export const Defaults = {
'fatal', 'fatal',
], ],
}, },
prefix: {
$id: '#/properties/prefix',
type: 'string',
},
}, },
additionalProperties: false, additionalProperties: false,
}, },

View file

@ -23,5 +23,10 @@ export enum ELoggingScope {
} }
// Interfaces // Interfaces
export interface ICommandOptions {
name: string;
shortDescription: string;
extendedDescription: string;
}
// Type Aliases // 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/*": [ "@utils/*": [
"src/lib/utils/*" "src/lib/utils/*"
],
"@structures/*": [
"src/lib/structures/*"
] ]
} }
}, },