Create initial bot framework (#7)

#1

Reviewed-on: https://gitea.vylpes.xyz/External/card-drop/pulls/7
Co-authored-by: Ethan Lane <ethan@vylpes.com>
Co-committed-by: Ethan Lane <ethan@vylpes.com>
This commit is contained in:
Ethan Lane 2023-08-19 16:56:22 +01:00 committed by Vylpes
parent cb548898ce
commit c706737369
35 changed files with 5876 additions and 0 deletions

75
src/client/client.ts Normal file
View file

@ -0,0 +1,75 @@
import { Client } from "discord.js";
import * as dotenv from "dotenv";
import { EventType } from "../constants/EventType";
import ICommandItem from "../contracts/ICommandItem";
import IEventItem from "../contracts/IEventItem";
import { Command } from "../type/command";
import { Events } from "./events";
import { Util } from "./util";
import AppDataSource from "../database/dataSources/appDataSource";
export class CoreClient extends Client {
private static _commandItems: ICommandItem[];
private static _eventItems: IEventItem[];
private _events: Events;
private _util: Util;
public static get commandItems(): ICommandItem[] {
return this._commandItems;
}
public static get eventItems(): IEventItem[] {
return this._eventItems;
}
constructor(intents: number[]) {
super({ intents: intents });
dotenv.config();
CoreClient._commandItems = [];
CoreClient._eventItems = [];
this._events = new Events();
this._util = new Util();
}
public async start() {
if (!process.env.BOT_TOKEN) {
console.error("BOT_TOKEN is not defined in .env");
return;
}
await AppDataSource.initialize()
.then(() => console.log("Data Source Initialized"))
.catch((err) => console.error("Error Initialising Data Source", err));
super.on("interactionCreate", this._events.onInteractionCreate);
super.on("ready", this._events.onReady);
await super.login(process.env.BOT_TOKEN);
this._util.loadEvents(this, CoreClient._eventItems);
this._util.loadSlashCommands(this);
}
public static RegisterCommand(name: string, command: Command, serverId?: string) {
const item: ICommandItem = {
Name: name,
Command: command,
ServerId: serverId,
};
CoreClient._commandItems.push(item);
}
public static RegisterEvent(eventType: EventType, func: Function) {
const item: IEventItem = {
EventType: eventType,
ExecutionFunction: func,
};
CoreClient._eventItems.push(item);
}
}

33
src/client/events.ts Normal file
View file

@ -0,0 +1,33 @@
import { Interaction } from "discord.js";
import ICommandItem from "../contracts/ICommandItem";
import { CoreClient } from "./client";
export class Events {
public async onInteractionCreate(interaction: Interaction) {
if (!interaction.isChatInputCommand()) return;
if (!interaction.guildId) return;
const item = CoreClient.commandItems.find(x => x.Name == interaction.commandName && !x.ServerId);
const itemForServer = CoreClient.commandItems.find(x => x.Name == interaction.commandName && x.ServerId == interaction.guildId);
let itemToUse: ICommandItem;
if (!itemForServer) {
if (!item) {
await interaction.reply('Command not found');
return;
}
itemToUse = item;
} else {
itemToUse = itemForServer;
}
itemToUse.Command.execute(interaction);
}
// Emit when bot is logged in and ready to use
public onReady() {
console.log("Ready");
}
}

95
src/client/util.ts Normal file
View file

@ -0,0 +1,95 @@
import { Client, REST, Routes, SlashCommandBuilder } from "discord.js";
import { EventType } from "../constants/EventType";
import IEventItem from "../contracts/IEventItem";
import { CoreClient } from "./client";
export class Util {
public loadSlashCommands(client: Client) {
const registeredCommands = CoreClient.commandItems;
const globalCommands = registeredCommands.filter(x => !x.ServerId);
const guildCommands = registeredCommands.filter(x => x.ServerId);
const globalCommandData: SlashCommandBuilder[] = globalCommands
.filter(x => x.Command.CommandBuilder)
.flatMap(x => x.Command.CommandBuilder);
const guildIds: string[] = [];
for (let command of guildCommands) {
if (!guildIds.find(x => x == command.ServerId)) {
guildIds.push(command.ServerId!);
}
}
const rest = new REST({ version: '10' }).setToken(process.env.BOT_TOKEN!);
rest.put(
Routes.applicationCommands(process.env.BOT_CLIENTID!),
{
body: globalCommandData
}
);
for (let guild of guildIds) {
const guildCommandData = guildCommands.filter(x => x.ServerId == guild)
.filter(x => x.Command.CommandBuilder)
.flatMap(x => x.Command.CommandBuilder);
if (!client.guilds.cache.has(guild)) continue;
rest.put(
Routes.applicationGuildCommands(process.env.BOT_CLIENTID!, guild),
{
body: guildCommandData
}
)
}
}
// Load the events
loadEvents(client: Client, events: IEventItem[]) {
events.forEach((e) => {
switch(e.EventType) {
case EventType.ChannelCreate:
client.on('channelCreate', (channel) => e.ExecutionFunction(channel));
break;
case EventType.ChannelDelete:
client.on('channelDelete', (channel) => e.ExecutionFunction(channel));
break;
case EventType.ChannelUpdate:
client.on('channelUpdate', (channel) => e.ExecutionFunction(channel));
break;
case EventType.GuildBanAdd:
client.on('guildBanAdd', (ban) => e.ExecutionFunction(ban));
break;
case EventType.GuildBanRemove:
client.on('guildBanRemove', (ban) => e.ExecutionFunction(ban));
break;
case EventType.GuildCreate:
client.on('guildCreate', (guild) => e.ExecutionFunction(guild));
break;
case EventType.GuildMemberAdd:
client.on('guildMemberAdd', (member) => e.ExecutionFunction(member));
break;
case EventType.GuildMemberRemove:
client.on('guildMemberRemove', (member) => e.ExecutionFunction(member));
break;
case EventType.GuildMemberUpdate:
client.on('guildMemberUpdate', (oldMember, newMember) => e.ExecutionFunction(oldMember, newMember));
break;
case EventType.MessageCreate:
client.on('messageCreate', (message) => e.ExecutionFunction(message));
break;
case EventType.MessageDelete:
client.on('messageDelete', (message) => e.ExecutionFunction(message));
break;
case EventType.MessageUpdate:
client.on('messageUpdate', (oldMessage, newMessage) => e.ExecutionFunction(oldMessage, newMessage));
break;
default:
console.error('Event not implemented.');
}
});
}
}