2022-12-15 13:07:35 -06:00
/ *
2022-12-16 06:00:03 -06:00
* Konpeki Discord Bot - Main Bot File
2022-12-15 13:07:35 -06:00
* All base level bot setup is done here
* /
// Require filesystem libraries
const fs = require ( 'node:fs' ) ;
const path = require ( 'node:path' ) ;
2022-12-16 02:42:59 -06:00
// Add pm2 metrics - this should NEVER track ANYTHING identifiable. This is purely for basic metrics and bot performance tracking
2022-12-16 03:58:49 -06:00
const metrics = require ( './utils/pm2-metrics.js' ) ;
// Use a custom logging script
const logger = require ( './utils/logging.js' ) ;
2022-12-16 02:42:59 -06:00
2023-09-13 15:11:45 -05:00
// Listen for (Semi-)Permenant Interactions
const interactionListener = require ( './utils/interaction-trigger.js' ) ;
2022-12-15 13:07:35 -06:00
// Require the necessary discord.js classes
const { Client , Collection , Events , GatewayIntentBits } = require ( 'discord.js' ) ;
const { token , botOwner } = require ( './config.json' ) ;
2022-12-16 10:06:38 -06:00
const { activity , status } = require ( './presence.json' ) ;
2022-12-15 13:07:35 -06:00
// Create a new client instance
const client = new Client ( { intents : [ GatewayIntentBits . Guilds ] } ) ;
// Setup the commands collection
client . commands = new Collection ( ) ;
const commandsPath = path . join ( _ _dirname , 'commands' ) ;
const commandFiles = fs . readdirSync ( commandsPath ) . filter ( file => file . endsWith ( '.js' ) ) ;
for ( const file of commandFiles ) {
2023-09-13 01:17:31 -05:00
const filePath = path . join ( commandsPath , file ) ;
const command = require ( filePath ) ;
// Set a new item in the Collection with the key as the command name and the value as the exported module
if ( 'data' in command && 'execute' in command ) {
client . commands . set ( command . data . name , command ) ;
}
else {
logger . log ( logger . logLevels . WARN , ` The command at ${ filePath } is missing a required "data" or "execute" property. ` ) ;
}
2022-12-15 13:07:35 -06:00
}
// When the client is ready, run this code (only once)
// We use 'c' for the event parameter to keep it separate from the already defined 'client'
client . once ( Events . ClientReady , c => {
2023-09-13 01:17:31 -05:00
logger . log ( logger . logLevels . INFO , ` ${ logger . colorText ( 'Ready!' , logger . textColor . Green ) } Logged in as ${ logger . colorText ( c . user . tag , logger . textColor . Blue ) } ` ) ;
client . user . setPresence ( { activities : [ { name : activity } ] , status : status } ) ;
2022-12-16 13:09:42 -06:00
2023-09-13 01:17:31 -05:00
// Track websocket heartbeat with PM2 Histogram
let latency = 0 ;
setInterval ( function ( ) {
latency = c . ws . ping ;
metrics . websocketHeartbeatHist . update ( latency ) ;
} , 1000 ) ;
2022-12-16 13:09:42 -06:00
2023-09-13 01:17:31 -05:00
// Report current server count with PM2 (Servers counted anonymously)
metrics . serverCount . set ( c . guilds . cache . size ) ;
2022-12-16 14:17:43 -06:00
2022-12-15 13:07:35 -06:00
} ) ;
// Client "on" Events
2022-12-16 14:17:43 -06:00
// Someone used an interaction
2022-12-15 13:07:35 -06:00
client . on ( Events . InteractionCreate , async interaction => {
2023-09-13 15:11:45 -05:00
if ( interaction . isChatInputCommand ( ) ) {
const command = interaction . client . commands . get ( interaction . commandName ) ;
if ( ! command ) {
logger . log ( logger . logLevels . ERROR , ` No command matching ${ interaction . commandName } was found. ` ) ;
await interaction . reply ( { content : ` This command no longer exists! Please contact ${ botOwner } to report that this is happening! ` , ephemeral : true } ) ;
// Report error to PM2 dashboard
metrics . interactionErrors . inc ( ) ;
metrics . io . notifyError ( new Error ( 'Interaction doesn\'t exist' ) , {
custom : {
interactionCommand : interaction . commandName ,
} ,
} ) ;
return ;
}
try {
await command . execute ( interaction ) ;
}
catch ( error ) {
logger . log ( logger . logLevels . ERROR , error ) ;
await interaction . reply ( { content : 'There was an error while executing this command!' , ephemeral : true } ) ;
// Report error to PM2 dashboard
metrics . interactionErrors . inc ( ) ;
metrics . io . notifyError ( new Error ( 'Error executing interaction' ) , {
custom : {
interactionCommand : interaction . commandName ,
error : error ,
} ,
} ) ;
}
// Successful Execution, report as a PM2 metric
// If the bot gets a lot of use, consider removing this for performance
metrics . interactionSuccess ( ) ;
2023-09-13 01:17:31 -05:00
}
2023-09-13 15:11:45 -05:00
else if ( interaction . isButton ( ) ) {
interactionListener . buttonInteraction ( interaction ) ;
2023-09-13 01:17:31 -05:00
}
2023-09-13 15:11:45 -05:00
else if ( interaction . isStringSelectMenu ( ) ) {
// respond to the select menu
2023-09-13 01:17:31 -05:00
}
2022-12-15 13:07:35 -06:00
} ) ;
2022-12-16 14:17:43 -06:00
// Joined a server
2022-12-16 14:36:51 -06:00
client . on ( Events . GuildCreate , guild => {
2023-09-13 01:17:31 -05:00
// Report current server count with PM2 (Servers counted anonymously)
metrics . serverCount . set ( guild . client . guilds . cache . size ) ;
2022-12-16 14:17:43 -06:00
} ) ;
// Removed from a server
2022-12-16 14:36:51 -06:00
client . on ( Events . GuildDelete , guild => {
2023-09-13 01:17:31 -05:00
// Report current server count with PM2 (Servers counted anonymously)
metrics . serverCount . set ( guild . client . guilds . cache . size ) ;
2022-12-16 14:17:43 -06:00
} ) ;
2022-12-15 13:07:35 -06:00
// Log in to Discord with your client's token
client . login ( token ) ;