From bbe6474498cd26fd61b8fde094f267652c64e10a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tina=C3=ABl=20Devresse?= <9126633-hunteroi@users.noreply.gitlab.com> Date: Thu, 24 Oct 2024 23:23:46 +0200 Subject: [PATCH] refactor(events): apply same strategy of loading commands to events Adapt helper to log information as well. Fix dockerfile warning with stage names --- Dockerfile | 6 +++--- src/datadrop.ts | 28 ++++++++++++++++------------ src/events/guildMemberAdd.ts | 11 ++++++++--- src/events/guildMemberRemove.ts | 11 ++++++++--- src/events/interactionCreate.ts | 9 +++++++-- src/events/ready.ts | 12 +++++++++--- src/helpers.ts | 26 ++++++++++++++++++-------- src/models/Event.ts | 7 +++++++ 8 files changed, 76 insertions(+), 34 deletions(-) create mode 100644 src/models/Event.ts diff --git a/Dockerfile b/Dockerfile index 218f1c3..0ca3ec0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:lts-alpine AS BUILD +FROM node:lts-alpine AS build WORKDIR /app @@ -12,13 +12,13 @@ RUN yarn install --production RUN zip -r app.zip ./node_modules ./build ./yarn.lock ./.env # ------------------------------------------------------------ -FROM node:lts-alpine AS APP +FROM node:lts-alpine AS app WORKDIR /app RUN apk --no-cache add unzip -COPY --from=BUILD /app/app.zip . +COPY --from=build /app/app.zip . RUN unzip app.zip && rm app.zip && mv ./build/* . && rm -rf ./build CMD ["sh", "-c", "sleep 2 && node ./index.js"] diff --git a/src/datadrop.ts b/src/datadrop.ts index c3711bd..2b922a6 100644 --- a/src/datadrop.ts +++ b/src/datadrop.ts @@ -14,6 +14,7 @@ import { readConfig } from './config.js'; import { User } from './models/User.js'; import { IDatabaseService } from './models/IDatabaseService.js'; import { Command } from './models/Command.js'; +import { Event } from './models/Event.js'; export class DatadropClient extends Client { #config: Configuration; @@ -145,22 +146,25 @@ export class DatadropClient extends Client { }); } - #bindEvents(): void { + async #bindEvents(): Promise { const eventDirectory = path.join(import.meta.dirname, 'events'); - this.logger.debug(`Chargement de ${eventDirectory}`); - readFilesFrom(eventDirectory, (eventName: string, props: any) => { - this.logger.info(`Event '${eventName}' chargé`); - this.on(eventName, props.bind(null, this)); - }); + await readFilesFrom(eventDirectory, (eventFileName: string, event: Event) => { + this.logger.info(`Event '${event.name}' ('${eventFileName}') chargé`); + + if (event.once) { + this.once(event.name, event.execute.bind(null, this)); + } else { + this.on(event.name, event.execute.bind(null, this)); + } + }, this.logger); } - #bindCommands(): void { + async #bindCommands(): Promise { const commandDirectory = path.join(import.meta.dirname, 'commands'); - this.logger.debug(`Chargement de ${commandDirectory}`); - readFilesFrom(commandDirectory, (commandFileName: string, props: any) => { + await readFilesFrom(commandDirectory, (commandFileName: string, props: Command) => { this.logger.info(`Commande '${props.data.name}' ('${commandFileName}') chargée`); this.commands.set(props.data.name, props); - }); + }, this.logger); } async start(): Promise { @@ -170,8 +174,8 @@ export class DatadropClient extends Client { this.#listenToTempChannelsEvents(); this.#listenToVerificationEvents(); - this.#bindEvents(); - this.#bindCommands(); + await this.#bindEvents(); + await this.#bindCommands(); await this.database?.start(); this.login(); diff --git a/src/events/guildMemberAdd.ts b/src/events/guildMemberAdd.ts index 022967c..642b173 100644 --- a/src/events/guildMemberAdd.ts +++ b/src/events/guildMemberAdd.ts @@ -1,10 +1,15 @@ -import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, GuildMember } from 'discord.js'; +import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, Events, GuildMember } from 'discord.js'; import { AnnounceConfiguration } from '../models/Configuration.js'; import { DatadropClient } from '../datadrop.js'; -export default async function guildMemberAdd(client: DatadropClient, member: GuildMember) { +export default { + name: Events.GuildMemberAdd, + execute: guildMemberAdd +}; + +async function guildMemberAdd(client: DatadropClient, member: GuildMember) { if (member.user.bot) return; client.logger.info(`L'utilisateur <${member.displayName} a rejoint le serveur.`); @@ -35,7 +40,7 @@ export default async function guildMemberAdd(client: DatadropClient, member: Gui } catch (err: unknown) { client.logger.error((err).message); } -}; +} function generateEmbed(informationsChannelid: string, faqChannelid: string, comiteeChannelid: string, rolesChannelid: string, announce: AnnounceConfiguration) { const fields = [ diff --git a/src/events/guildMemberRemove.ts b/src/events/guildMemberRemove.ts index af34769..a2db596 100644 --- a/src/events/guildMemberRemove.ts +++ b/src/events/guildMemberRemove.ts @@ -1,8 +1,13 @@ -import { GuildMember } from 'discord.js'; +import { Events, GuildMember } from 'discord.js'; import { DatadropClient } from '../datadrop.js'; -export default async function guildMemberRemove(client: DatadropClient, member: GuildMember) { +export default { + name: Events.GuildMemberRemove, + execute: guildMemberRemove +}; + +async function guildMemberRemove(client: DatadropClient, member: GuildMember) { if (member.user.bot) return; if (member.guild.id !== client.config.guildId) return; client.logger.info(`L'utilisateur <${member.displayName} a quitté le serveur.`); @@ -12,4 +17,4 @@ export default async function guildMemberRemove(client: DatadropClient, member: } catch (err: unknown) { client.logger.error((err).message); } -}; +} diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts index 528e8a9..04b74a2 100644 --- a/src/events/interactionCreate.ts +++ b/src/events/interactionCreate.ts @@ -1,9 +1,14 @@ -import { ActionRowBuilder, ButtonBuilder, ButtonInteraction, ButtonStyle, Interaction, italic, ModalBuilder, ModalSubmitInteraction, RepliableInteraction, TextInputBuilder, TextInputStyle } from 'discord.js'; +import { ActionRowBuilder, ButtonBuilder, ButtonInteraction, ButtonStyle, Events, Interaction, italic, ModalBuilder, ModalSubmitInteraction, RepliableInteraction, TextInputBuilder, TextInputStyle } from 'discord.js'; import { DatadropClient } from 'src/datadrop.js'; import { CommandHandler } from '../services/CommandHandler.js'; -export default async function interactionCreate(client: DatadropClient, interaction: Interaction) { +export default { + name: Events.InteractionCreate, + execute: interactionCreate +}; + +async function interactionCreate(client: DatadropClient, interaction: Interaction) { if (interaction.isChatInputCommand() || interaction.isMessageContextMenuCommand()) { const commandHandler = new CommandHandler(client); if (commandHandler.shouldExecute(interaction)) { diff --git a/src/events/ready.ts b/src/events/ready.ts index a73bfac..37907d4 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -1,11 +1,17 @@ -import { Role, roleMention, bold, Snowflake, ButtonStyle } from 'discord.js'; +import { Role, roleMention, bold, Snowflake, ButtonStyle, Events } from 'discord.js'; import { RoleToEmojiData } from '@hunteroi/discord-selfrole'; import { DatadropClient } from '../datadrop.js'; import { Configuration } from '../models/Configuration.js'; -export default async function ready(client: DatadropClient) { +export default { + name: Events.ClientReady, + once: true, + execute: ready +}; + +async function ready(client: DatadropClient) { const { config } = client; await registerRolesChannels(client, config); await registerDynamicChannels(client, config); @@ -14,7 +20,7 @@ export default async function ready(client: DatadropClient) { if (config.version) client.user?.setActivity({ name: config.version }); client.logger.info(`Connecté en tant que ${client.user?.tag}, version ${config.version}!`); -}; +} async function registerRolesChannels(client: DatadropClient, config: Configuration): Promise { const { rolesChannelid, first, second, third, alumni, tutor, announce } = config; diff --git a/src/helpers.ts b/src/helpers.ts index 012ce23..7b6357e 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -1,23 +1,33 @@ -import * as fs from 'fs'; +import * as fsp from 'fs/promises'; import * as path from 'path'; +import { ConsoleLogger, DefaultLogger } from '@hunteroi/advanced-logger'; -export function readFilesFrom(directory: string, callback: (name: string, props: any) => void): void { - fs.readdir(directory, async (err, files) => { - if (err) return console.error; +const console = new ConsoleLogger(); + +export async function readFilesFrom(directory: string, callback: (name: string, props: any) => void, logger: DefaultLogger = console): Promise { + try { + logger.debug(`Lecture du répertoire ${directory}`); + + const files = await fsp.readdir(directory); for (const file of files) { const filePath = path.join(directory, file); - const stats = fs.statSync(filePath); + const stats = await fsp.stat(filePath); + if (stats.isDirectory()) { - readFilesFrom(filePath, callback); + await readFilesFrom(filePath, callback, logger); continue; } - if (stats.isFile() && !file.endsWith('.js')) return; + if (stats.isFile() && !file.endsWith('.js')) continue; + + logger.debug(`Lecture du fichier ${filePath}`); const props = await import(filePath); callback(file.replace('.js', ''), props.default); } - }); + } catch (err) { + logger.error(getErrorMessage(err)); + } } export function clean(text: any): string { diff --git a/src/models/Event.ts b/src/models/Event.ts new file mode 100644 index 0000000..35f0d7c --- /dev/null +++ b/src/models/Event.ts @@ -0,0 +1,7 @@ +import { DatadropClient } from '../datadrop.js'; + +export interface Event { + name: string; + once?: boolean; + execute(client: DatadropClient, ...args: any[]): Promise; +}