mirror of
https://github.com/ahmadk953/poixpixel-discord-bot.git
synced 2025-05-10 10:43:06 +00:00
Added code coments, refactored db.ts and redis.ts, and added two new commands
This commit is contained in:
parent
b3fbd2358b
commit
890ca26c78
30 changed files with 1899 additions and 462 deletions
|
@ -19,7 +19,7 @@ const command: Command = {
|
|||
execute: async (interaction) => {
|
||||
let members = await getAllMembers();
|
||||
members = members.sort((a, b) =>
|
||||
a.discordUsername.localeCompare(b.discordUsername),
|
||||
(a.discordUsername ?? '').localeCompare(b.discordUsername ?? ''),
|
||||
);
|
||||
|
||||
const ITEMS_PER_PAGE = 15;
|
||||
|
|
203
src/commands/util/reconnect.ts
Normal file
203
src/commands/util/reconnect.ts
Normal file
|
@ -0,0 +1,203 @@
|
|||
import {
|
||||
CommandInteraction,
|
||||
PermissionsBitField,
|
||||
SlashCommandBuilder,
|
||||
} from 'discord.js';
|
||||
|
||||
import { SubcommandCommand } from '../../types/CommandTypes.js';
|
||||
import { loadConfig } from '../../util/configLoader.js';
|
||||
import {
|
||||
initializeDatabaseConnection,
|
||||
ensureDbInitialized,
|
||||
} from '../../db/db.js';
|
||||
import { isRedisConnected } from '../../db/redis.js';
|
||||
import {
|
||||
NotificationType,
|
||||
notifyManagers,
|
||||
} from '../../util/notificationHandler.js';
|
||||
|
||||
const command: SubcommandCommand = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('reconnect')
|
||||
.setDescription('(Manager Only) Force reconnection to database or Redis')
|
||||
.addSubcommand((subcommand) =>
|
||||
subcommand
|
||||
.setName('database')
|
||||
.setDescription('(Manager Only) Force reconnection to the database'),
|
||||
)
|
||||
.addSubcommand((subcommand) =>
|
||||
subcommand
|
||||
.setName('redis')
|
||||
.setDescription('(Manager Only) Force reconnection to Redis cache'),
|
||||
)
|
||||
.addSubcommand((subcommand) =>
|
||||
subcommand
|
||||
.setName('status')
|
||||
.setDescription(
|
||||
'(Manager Only) Check connection status of database and Redis',
|
||||
),
|
||||
),
|
||||
|
||||
execute: async (interaction) => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
|
||||
const config = loadConfig();
|
||||
const managerRoleId = config.roles.staffRoles.find(
|
||||
(role) => role.name === 'Manager',
|
||||
)?.roleId;
|
||||
|
||||
const member = await interaction.guild?.members.fetch(interaction.user.id);
|
||||
const hasManagerRole = member?.roles.cache.has(managerRoleId || '');
|
||||
|
||||
if (
|
||||
!hasManagerRole &&
|
||||
!interaction.memberPermissions?.has(
|
||||
PermissionsBitField.Flags.Administrator,
|
||||
)
|
||||
) {
|
||||
await interaction.reply({
|
||||
content:
|
||||
'You do not have permission to use this command. This command is restricted to users with the Manager role.',
|
||||
flags: ['Ephemeral'],
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const subcommand = interaction.options.getSubcommand();
|
||||
|
||||
await interaction.deferReply({ flags: ['Ephemeral'] });
|
||||
|
||||
try {
|
||||
if (subcommand === 'database') {
|
||||
await handleDatabaseReconnect(interaction);
|
||||
} else if (subcommand === 'redis') {
|
||||
await handleRedisReconnect(interaction);
|
||||
} else if (subcommand === 'status') {
|
||||
await handleStatusCheck(interaction);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error in reconnect command (${subcommand}):`, error);
|
||||
await interaction.editReply({
|
||||
content: `An error occurred while processing the reconnect command: \`${error}\``,
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle database reconnection
|
||||
*/
|
||||
async function handleDatabaseReconnect(interaction: CommandInteraction) {
|
||||
await interaction.editReply('Attempting to reconnect to the database...');
|
||||
|
||||
try {
|
||||
const success = await initializeDatabaseConnection();
|
||||
|
||||
if (success) {
|
||||
await interaction.editReply(
|
||||
'✅ **Database reconnection successful!** All database functions should now be operational.',
|
||||
);
|
||||
|
||||
notifyManagers(
|
||||
interaction.client,
|
||||
NotificationType.DATABASE_CONNECTION_RESTORED,
|
||||
`Database connection manually restored by ${interaction.user.tag}`,
|
||||
);
|
||||
} else {
|
||||
await interaction.editReply(
|
||||
'❌ **Database reconnection failed.** Check the logs for more details.',
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error reconnecting to database:', error);
|
||||
await interaction.editReply(
|
||||
`❌ **Database reconnection failed with error:** \`${error}\``,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Redis reconnection
|
||||
*/
|
||||
async function handleRedisReconnect(interaction: CommandInteraction) {
|
||||
await interaction.editReply('Attempting to reconnect to Redis...');
|
||||
|
||||
try {
|
||||
const redisModule = await import('../../db/redis.js');
|
||||
|
||||
await redisModule.ensureRedisConnection();
|
||||
|
||||
const isConnected = redisModule.isRedisConnected();
|
||||
|
||||
if (isConnected) {
|
||||
await interaction.editReply(
|
||||
'✅ **Redis reconnection successful!** Cache functionality is now available.',
|
||||
);
|
||||
|
||||
notifyManagers(
|
||||
interaction.client,
|
||||
NotificationType.REDIS_CONNECTION_RESTORED,
|
||||
`Redis connection manually restored by ${interaction.user.tag}`,
|
||||
);
|
||||
} else {
|
||||
await interaction.editReply(
|
||||
'❌ **Redis reconnection failed.** The bot will continue to function without caching capabilities.',
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error reconnecting to Redis:', error);
|
||||
await interaction.editReply(
|
||||
`❌ **Redis reconnection failed with error:** \`${error}\``,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle status check for both services
|
||||
*/
|
||||
async function handleStatusCheck(interaction: any) {
|
||||
await interaction.editReply('Checking connection status...');
|
||||
|
||||
try {
|
||||
const dbStatus = await (async () => {
|
||||
try {
|
||||
await ensureDbInitialized();
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
})();
|
||||
|
||||
const redisStatus = isRedisConnected();
|
||||
|
||||
const statusEmbed = {
|
||||
title: '🔌 Service Connection Status',
|
||||
fields: [
|
||||
{
|
||||
name: 'Database',
|
||||
value: dbStatus ? '✅ Connected' : '❌ Disconnected',
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: 'Redis Cache',
|
||||
value: redisStatus
|
||||
? '✅ Connected'
|
||||
: '⚠️ Disconnected (caching disabled)',
|
||||
inline: true,
|
||||
},
|
||||
],
|
||||
color:
|
||||
dbStatus && redisStatus ? 0x00ff00 : dbStatus ? 0xffaa00 : 0xff0000,
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
|
||||
await interaction.editReply({ content: '', embeds: [statusEmbed] });
|
||||
} catch (error) {
|
||||
console.error('Error checking connection status:', error);
|
||||
await interaction.editReply(
|
||||
`❌ **Error checking connection status:** \`${error}\``,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default command;
|
93
src/commands/util/restart.ts
Normal file
93
src/commands/util/restart.ts
Normal file
|
@ -0,0 +1,93 @@
|
|||
import { PermissionsBitField, SlashCommandBuilder } from 'discord.js';
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
|
||||
import { Command } from '../../types/CommandTypes.js';
|
||||
import { loadConfig } from '../../util/configLoader.js';
|
||||
import {
|
||||
NotificationType,
|
||||
notifyManagers,
|
||||
} from '../../util/notificationHandler.js';
|
||||
import { isRedisConnected } from '../../db/redis.js';
|
||||
import { ensureDatabaseConnection } from '../../db/db.js';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
const command: Command = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('restart')
|
||||
.setDescription('(Manager Only) Restart the bot'),
|
||||
execute: async (interaction) => {
|
||||
const config = loadConfig();
|
||||
const managerRoleId = config.roles.staffRoles.find(
|
||||
(role) => role.name === 'Manager',
|
||||
)?.roleId;
|
||||
|
||||
const member = await interaction.guild?.members.fetch(interaction.user.id);
|
||||
const hasManagerRole = member?.roles.cache.has(managerRoleId || '');
|
||||
|
||||
if (
|
||||
!hasManagerRole &&
|
||||
!interaction.memberPermissions?.has(
|
||||
PermissionsBitField.Flags.Administrator,
|
||||
)
|
||||
) {
|
||||
await interaction.reply({
|
||||
content:
|
||||
'You do not have permission to restart the bot. This command is restricted to users with the Manager role.',
|
||||
flags: ['Ephemeral'],
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await interaction.reply({
|
||||
content: 'Restarting the bot... This may take a few moments.',
|
||||
flags: ['Ephemeral'],
|
||||
});
|
||||
|
||||
const dbConnected = await ensureDatabaseConnection();
|
||||
const redisConnected = isRedisConnected();
|
||||
let statusInfo = '';
|
||||
|
||||
if (!dbConnected) {
|
||||
statusInfo += '⚠️ Database is currently disconnected\n';
|
||||
}
|
||||
|
||||
if (!redisConnected) {
|
||||
statusInfo += '⚠️ Redis caching is currently unavailable\n';
|
||||
}
|
||||
|
||||
if (dbConnected && redisConnected) {
|
||||
statusInfo = '✅ All services are operational\n';
|
||||
}
|
||||
|
||||
await notifyManagers(
|
||||
interaction.client,
|
||||
NotificationType.BOT_RESTARTING,
|
||||
`Restart initiated by ${interaction.user.tag}\n\nCurrent service status:\n${statusInfo}`,
|
||||
);
|
||||
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
console.log(
|
||||
`Bot restart initiated by ${interaction.user.tag} (${interaction.user.id})`,
|
||||
);
|
||||
|
||||
await execAsync('yarn restart');
|
||||
} catch (error) {
|
||||
console.error('Failed to restart the bot:', error);
|
||||
try {
|
||||
await interaction.followUp({
|
||||
content:
|
||||
'Failed to restart the bot. Check the console for details.',
|
||||
flags: ['Ephemeral'],
|
||||
});
|
||||
} catch {
|
||||
// If this fails too, we can't do much
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
};
|
||||
|
||||
export default command;
|
Loading…
Add table
Add a link
Reference in a new issue