refactor: 🚸 refactor and improve ux in heplers and middlewares

This commit is contained in:
Axel Olausson Holtenäs 2022-12-25 02:39:32 +01:00
parent d62baa0b9c
commit 193032e3ba
11 changed files with 140 additions and 111 deletions

View file

@ -16,7 +16,7 @@ export default async (interaction: ChatInputCommandInteraction) => {
const { client, commandName } = interaction; const { client, commandName } = interaction;
const currentCommand = client.commands.get(commandName); const currentCommand = client.commands.get(commandName);
if (!currentCommand) throw new Error(`Unknown command ${commandName}`); if (!currentCommand) throw new Error("Command unavailable");
await currentCommand.execute(interaction).catch((error: Error) => { await currentCommand.execute(interaction).catch((error: Error) => {
const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents( const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(

View file

@ -12,7 +12,11 @@ export const options: IEventOptions = {
// Execute the event // Execute the event
export const execute = async (client: Client) => { export const execute = async (client: Client) => {
logger.info("Discord's API client is ready!"); if (!client.user) throw new Error("Client user unavailable");
logger.info({
message: `Connected to Discord!`,
});
updatePresence(client); updatePresence(client);
await deployCommands(client); await deployCommands(client);

View file

@ -6,32 +6,30 @@ import logger from "../../middlewares/logger";
// Register the commands. // Register the commands.
export const register = async (client: Client) => { export const register = async (client: Client) => {
logger.info("🔧 Started command management"); await checkDirectory("commands").then(async (commandNames) => {
for await (const commandName of commandNames) {
const commandProfiler = logger.startTimer();
const commandNames = await checkDirectory("commands"); await import(`../../commands/${commandName}`)
if (!commandNames) return logger.warn("No available commands found"); .then((command: ICommand) => {
client.commands.set(command.builder.name, command);
const totalCommands = commandNames.length; commandProfiler.done({
let loadedCommands = 0; commandName,
message: `Registered command '${commandName}'`,
level: "debug",
});
logger.info(`🔧 Loading ${totalCommands} commands`); return command;
})
// Import an command. .catch((error) => {
const importCommand = async (name: string) => { commandProfiler.done({
const command: ICommand = await import(`../../commands/${name}`); message: `Failed to register command '${commandName}'`,
commandName,
client.commands.set(command.builder.name, command); error,
return loadedCommands++; level: "error",
}; });
});
for await (const commandName of commandNames) {
await importCommand(commandName).then(() => {
return logger.verbose(`🔧 Loaded command "${commandName}"`);
});
if (loadedCommands === totalCommands) {
return logger.info("🔧 All commands loaded");
} }
} });
return true;
}; };

View file

@ -14,6 +14,12 @@ prisma.$use(async (params, next) => {
`Query ${params.model}.${params.action} took ${after - before}ms` `Query ${params.model}.${params.action} took ${after - before}ms`
); );
if (after - before >= 50) {
logger.warn(
`Query ${params.model}.${params.action} took ${after - before}ms`
);
}
return result; return result;
}); });

View file

@ -1,5 +1,5 @@
import { BaseInteraction, EmbedBuilder } from "discord.js"; import { BaseInteraction, EmbedBuilder } from "discord.js";
import getEmbedConfig from "../../helpers/getEmbedData"; import getEmbedData from "../../helpers/getEmbedData";
export default async (interaction: BaseInteraction, ephemeral: boolean) => { export default async (interaction: BaseInteraction, ephemeral: boolean) => {
if (!interaction.isRepliable()) if (!interaction.isRepliable())
@ -9,7 +9,7 @@ export default async (interaction: BaseInteraction, ephemeral: boolean) => {
ephemeral, ephemeral,
}); });
const embedConfig = await getEmbedConfig(interaction.guild); const embedConfig = await getEmbedData(interaction.guild);
await interaction.editReply({ await interaction.editReply({
embeds: [ embeds: [

View file

@ -1,39 +1,29 @@
import { Client, RESTPostAPIApplicationCommandsJSONBody } from "discord.js"; import { Client, RESTPostAPIApplicationCommandsJSONBody } from "discord.js";
import { ICommand } from "../../interfaces/Command";
import logger from "../../middlewares/logger"; import logger from "../../middlewares/logger";
export default async (client: Client) => { export default async (client: Client) => {
// 1. Destructure the client.
const { application } = client; const { application } = client;
if (!application) throw new Error("No application found"); if (!application) throw new Error("No application found");
// 2. Log that we are starting the command management. const builders: Array<RESTPostAPIApplicationCommandsJSONBody> = [];
logger.info("🔧 Started command deployment");
// 3. Get the commands. client.commands.forEach((command) => {
const commands: Array<RESTPostAPIApplicationCommandsJSONBody> = []; builders.push(command.builder.toJSON());
client.commands.forEach((command: ICommand) => {
commands.push(command.builder.toJSON());
logger.verbose(`🔧 Loaded command "${command.builder.name}"`);
}); });
// 4. Set the commands. await application.commands.set(builders).then(() => {
await application.commands.set(commands).then(() => { logger.info({ builders, message: "Registered commands to users!" });
logger.info("🔧 Deployed commands globally");
}); });
// 5. Tell the user that development mode is enabled.
if (process.env.NODE_ENV === "development") { if (process.env.NODE_ENV === "development") {
logger.info("🔧 Development mode enabled");
await application.commands await application.commands
.set(commands, process.env.DISCORD_GUILD_ID) .set(builders, process.env.DISCORD_GUILD_ID)
.then(() => { .then(() => {
logger.info(`🔧 Deployed commands to guild`); logger.info({
builders,
devGuildId: process.env.DISCORD_GUILD_ID,
message: "Registered commands to development guild!",
});
}); });
} }
// 6. Log that we are done with the command management.
logger.info("🔧 Finished command deployment");
}; };

View file

@ -6,49 +6,51 @@ import logger from "../../middlewares/logger";
// Registers all available events. // Registers all available events.
export const register = async (client: Client) => { export const register = async (client: Client) => {
logger.info("📡 Started event management"); const profiler = logger.startTimer();
const eventNames = await checkDirectory("events"); await checkDirectory("events").then(async (eventNames) => {
if (!eventNames) return logger.warn("No available events found"); const totalEvents = eventNames.length;
let loadedEvents = 0;
const totalEvents = eventNames.length; // Import an event.
let loadedEvents = 0; const importEvent = async (name: string) => {
await import(`../../events/${name}`).then((event: IEvent) => {
// Create a new event execute function.
const eventExecutor = async (...args: Promise<void>[]) => {
await event.execute(...args);
};
logger.info(`📡 Loading ${totalEvents} events`); switch (event.options.type) {
case "once":
client.once(name, eventExecutor);
break;
// Import an event. case "on":
const importEvent = async (name: string) => { client.on(name, eventExecutor);
const event: IEvent = await import(`../../events/${name}`); break;
default:
throw new Error(`Unknown event type`);
}
// Create a new event execute function. logger.debug({
const eventExecutor = async (...args: Promise<void>[]) => { eventName: name,
await event.execute(...args); type: event.options.type,
message: `Listening to event '${name}'`,
});
return loadedEvents++;
});
}; };
switch (event.options.type) { for await (const eventName of eventNames) {
case "once": await importEvent(eventName);
client.once(name, eventExecutor);
break;
case "on": if (loadedEvents === totalEvents) {
client.on(name, eventExecutor); return profiler.done({
break; message: "Successfully listening to all events!",
default: });
throw new Error(`📡 Invalid event type for event: ${name}`); }
} }
return loadedEvents++; return true;
}; });
for await (const eventName of eventNames) {
await importEvent(eventName).then(() => {
return logger.verbose(`📡 Loaded event "${eventName}"`);
});
if (loadedEvents === totalEvents) {
return logger.info("📡 All events loaded");
}
}
return true;
}; };

View file

@ -6,19 +6,25 @@ import logger from "../../middlewares/logger";
// Start all jobs that are in the schedules directory // Start all jobs that are in the schedules directory
export const start = async (client: Client) => { export const start = async (client: Client) => {
logger.info("⏰ Started job management");
const jobNames = await checkDirectory("schedules"); const jobNames = await checkDirectory("schedules");
if (!jobNames) return logger.warn("⏰ No available jobs found"); if (!jobNames) return logger.warn("⏰ No available jobs found");
return await Promise.all( return await Promise.all(
jobNames.map(async (jobName) => { jobNames.map(async (jobName) => {
const job: IJob = await import(`../../schedules/${jobName}`); await import(`../../schedules/${jobName}`)
.then((job: IJob) => {
return schedule.scheduleJob(job.options.schedule, async () => { return schedule.scheduleJob(job.options.schedule, async () => {
logger.verbose(`⏰ Performed the job "${jobName}"`); logger.verbose(`⏰ Performed the job "${jobName}"`);
await job.execute(client); await job.execute(client);
}); });
})
.catch((error) => {
logger.warn({
jobName,
message: `Failed to start job ${jobName}`,
error,
});
});
}) })
); );
}; };

View file

@ -1,5 +1,5 @@
// Dependencies // Dependencies
import { ActivityType, Client } from "discord.js"; import { ActivitiesOptions, ActivityType, Client } from "discord.js";
import logger from "../../middlewares/logger"; import logger from "../../middlewares/logger";
// Function // Function
@ -12,18 +12,27 @@ export default (client: Client) => {
const memberCount = guilds.cache.reduce((a, g) => a + g.memberCount, 0); const memberCount = guilds.cache.reduce((a, g) => a + g.memberCount, 0);
const guildCount = guilds.cache.size; const guildCount = guilds.cache.size;
const activities: ActivitiesOptions[] = [
{
name: `${guildCount} guilds`,
type: ActivityType.Watching,
},
{
name: `${memberCount} members`,
type: ActivityType.Watching,
},
];
const activity = activities[Math.floor(Math.random() * activities.length)];
// 3. Set the presence. // 3. Set the presence.
user.setPresence({ user.setActivity(activity);
activities: [
{
name: `${guildCount} guilds | ${memberCount} members`,
type: ActivityType.Watching,
},
],
});
// 4. Log the presence. // 4. Log the presence.
return logger.info( return logger.debug({
`👀 Presence set to "${guildCount} guilds | ${memberCount} members"` guildCount,
); memberCount,
message: `Presence updated`,
activity,
});
}; };

View file

@ -1,7 +1,16 @@
import fs from "fs"; import fs from "fs";
import logger from "../../middlewares/logger";
const fsPromises = fs.promises; const fsPromises = fs.promises;
export default async (path: string) => { export default async (path: string) => {
const result = await fsPromises.readdir(`${__dirname}/../../${path}`); const directoryPath = `${process.cwd()}/dist/${path}`;
return result;
return await fsPromises.readdir(directoryPath).then((result) => {
logger.debug({
message: `Checked directory ${path}`,
directoryPath,
result,
});
return result;
});
}; };

View file

@ -1,17 +1,17 @@
import winston from "winston"; import winston from "winston";
import "winston-daily-rotate-file"; import "winston-daily-rotate-file";
const { combine, timestamp, printf, errors, colorize, align, json } = const { combine, timestamp, json, errors, colorize, align, printf } =
winston.format; winston.format;
const logger = winston.createLogger({
export default winston.createLogger({
level: process.env.LOG_LEVEL || "info", level: process.env.LOG_LEVEL || "info",
format: combine(errors({ stack: true }), timestamp(), json()),
transports: [ transports: [
new winston.transports.DailyRotateFile({ new winston.transports.DailyRotateFile({
filename: "logs/combined-%DATE%.log", filename: "logs/combined-%DATE%.log",
datePattern: "YYYY-MM-DD", datePattern: "YYYY-MM-DD",
maxFiles: "14d", maxFiles: "14d",
format: combine(timestamp(), json()), format: combine(errors({ stack: true }), timestamp(), json()),
}), }),
new winston.transports.Console({ new winston.transports.Console({
format: combine( format: combine(
@ -21,8 +21,13 @@ export default winston.createLogger({
format: "YYYY-MM-DD HH:MM:ss", format: "YYYY-MM-DD HH:MM:ss",
}), }),
align(), align(),
printf((info) => `[${info.timestamp}] ${info.level}: ${info.message}`) printf(
(info) =>
`[${info.timestamp}] ${info.level}: ${info.stack || info.message}`
)
), ),
}), }),
], ],
}); });
export default logger;