diff --git a/src/bot.ts b/src/bot.ts index 194aa1f..5eab81f 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -1,194 +1,208 @@ import { - CacheType, - Client, - GatewayIntentBits, - Interaction, - Message, - OAuth2Scopes, - PermissionFlagsBits, - VoiceState + CacheType, + Client, + GatewayIntentBits, + Interaction, + Message, + OAuth2Scopes, + PermissionFlagsBits, + VoiceState } from 'discord.js'; import { Logger } from './utils/log'; import { config } from './utils/config'; type BotEventListeners = { - 'messageCreate': (message: Message) => void; - 'interactionCreate': (interaction: Interaction) => void; - 'voiceStateUpdate': (oldState: VoiceState, newState: VoiceState) => void; + messageCreate: (message: Message) => void; + interactionCreate: (interaction: Interaction) => void; + voiceStateUpdate: (oldState: VoiceState, newState: VoiceState) => void; }; type BotEventListener = BotEventListeners[K]; export class Bot { - private client: Client | undefined; + private client: Client | undefined; - private readonly token: string; - private readonly clientId: string; + private readonly token: string; + private readonly clientId: string; - private readonly log: Logger; + private readonly log: Logger; - private eventListeners: { - [K in keyof BotEventListeners]?: BotEventListener[]; - } = {}; + private eventListeners: { + [K in keyof BotEventListeners]?: BotEventListener[]; + } = {}; - /* + /* event methods */ - public on( - event: K, - listener: BotEventListener - ): void { - if (!this.eventListeners[event]) { - this.eventListeners[event] = []; - } - (this.eventListeners[event] as BotEventListener[]).push(listener); - } + public on( + event: K, + listener: BotEventListener + ): void { + if (!this.eventListeners[event]) { + this.eventListeners[event] = []; + } + (this.eventListeners[event] as BotEventListener[]).push(listener); + } - public off( - event: K, - listener: BotEventListener - ): boolean { - const listeners = this.eventListeners[event]; - if (!listeners) return false; + public off( + event: K, + listener: BotEventListener + ): boolean { + const listeners = this.eventListeners[event]; + if (!listeners) return false; - const index = (listeners as BotEventListener[]).indexOf(listener); - if (index > -1) { - (listeners as BotEventListener[]).splice(index, 1); - return true; - } - return false; - } + const index = (listeners as BotEventListener[]).indexOf(listener); + if (index > -1) { + (listeners as BotEventListener[]).splice(index, 1); + return true; + } + return false; + } - public once( - event: K, - listener: BotEventListener - ): void { - const onceWrapper = ((...args: Parameters>) => { - this.off(event, onceWrapper as BotEventListener); - (listener as (...args: unknown[]) => void)(...args); - }) as BotEventListener; - - this.on(event, onceWrapper); - } + public once( + event: K, + listener: BotEventListener + ): void { + const onceWrapper = ((...args: Parameters>) => { + this.off(event, onceWrapper as BotEventListener); + (listener as (...args: unknown[]) => void)(...args); + }) as BotEventListener; - private emit( - event: K, - ...args: Parameters> - ): void { - const listeners = this.eventListeners[event]; - if (listeners) { - for (const listener of listeners as BotEventListener[]) { - try { - (listener as (...args: unknown[]) => void)(...args); - } catch (error) { - this.log.error(`Error in event listener for ${String(event)}:`, error); - } - } - } - } + this.on(event, onceWrapper); + } - /* + private emit( + event: K, + ...args: Parameters> + ): void { + const listeners = this.eventListeners[event]; + if (listeners) { + for (const listener of listeners as BotEventListener[]) { + try { + (listener as (...args: unknown[]) => void)(...args); + } catch (error) { + this.log.error( + `Error in event listener for ${String(event)}:`, + error + ); + } + } + } + } + + /* class methods */ - private constructor() { - this.log = new Logger('Bot'); + private constructor() { + this.log = new Logger('Bot'); - this.token = config.token; - this.clientId = config.client_id; - } + this.token = config.token; + this.clientId = config.client_id; + } - public async init(): Promise { - this.log.info('Bot init'); + public async init(): Promise { + this.log.info('Bot init'); - if (this.client) - throw new Error('Client already exists, was init called twice?'); + if (this.client) + throw new Error('Client already exists, was init called twice?'); - this.log.info('Instantiating client'); - this.client = new Client({ - intents: [ - GatewayIntentBits.Guilds, - GatewayIntentBits.GuildMessages, - GatewayIntentBits.GuildVoiceStates, - GatewayIntentBits.MessageContent - ] - }); + this.log.info('Instantiating client'); + this.client = new Client({ + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.GuildVoiceStates, + GatewayIntentBits.MessageContent + ] + }); - this.log.info('Registering callbacks'); - this.client.on('clientReady', () => this.onReady()); - this.client.on('error', (err) => this.onError(err, false)); - this.client.on('shardError', (err) => this.onError(err, true)); - this.client.on('messageCreate', (message: Message) => this.onMessage(message)); - this.client.on('interactionCreate', (interaction: Interaction) => this.onInteraction(interaction)); - this.client.on('voiceStateUpdate', (oldState: VoiceState, newState: VoiceState) => this.onVoiceStateUpdate(oldState, newState)); + this.log.info('Registering callbacks'); + this.client.on('clientReady', () => this.onReady()); + this.client.on('error', (err) => this.onError(err, false)); + this.client.on('shardError', (err) => this.onError(err, true)); + this.client.on('messageCreate', (message: Message) => + this.onMessage(message) + ); + this.client.on('interactionCreate', (interaction: Interaction) => + this.onInteraction(interaction) + ); + this.client.on( + 'voiceStateUpdate', + (oldState: VoiceState, newState: VoiceState) => + this.onVoiceStateUpdate(oldState, newState) + ); - this.log.info('Logging in...'); - await this.client.login(this.token); - } + this.log.info('Logging in...'); + await this.client.login(this.token); + } - /* + /* event listeners */ - private onReady(): void { - this.log.info('Logged in'); + private onReady(): void { + this.log.info('Logged in'); - const inviteLink = this.client?.generateInvite({ - scopes: [OAuth2Scopes.ApplicationsCommands, OAuth2Scopes.Bot], - permissions: [ - PermissionFlagsBits.AddReactions, - PermissionFlagsBits.AttachFiles, - PermissionFlagsBits.ChangeNickname, - PermissionFlagsBits.Connect, - PermissionFlagsBits.Speak, - PermissionFlagsBits.ViewChannel, - PermissionFlagsBits.ReadMessageHistory, - PermissionFlagsBits.SendMessages, - PermissionFlagsBits.SendMessagesInThreads, - PermissionFlagsBits.SendVoiceMessages, - PermissionFlagsBits.EmbedLinks - ] - }); + const inviteLink = this.client?.generateInvite({ + scopes: [OAuth2Scopes.ApplicationsCommands, OAuth2Scopes.Bot], + permissions: [ + PermissionFlagsBits.AddReactions, + PermissionFlagsBits.AttachFiles, + PermissionFlagsBits.ChangeNickname, + PermissionFlagsBits.Connect, + PermissionFlagsBits.Speak, + PermissionFlagsBits.ViewChannel, + PermissionFlagsBits.ReadMessageHistory, + PermissionFlagsBits.SendMessages, + PermissionFlagsBits.SendMessagesInThreads, + PermissionFlagsBits.SendVoiceMessages, + PermissionFlagsBits.EmbedLinks + ] + }); - this.log.info('Invite link: %s', inviteLink); - } + this.log.info('Invite link: %s', inviteLink); + } - private onError(error: Error, isShardError: boolean): void { - if (isShardError) - this.log.error( - 'A shard error ocurred: %s - %s - %s', - error.name, - error.message, - error.stack - ); - else - this.log.error( - 'An error ocurred: %s - %s - %s', - error.name, - error.message, - error.stack - ); - } + private onError(error: Error, isShardError: boolean): void { + if (isShardError) + this.log.error( + 'A shard error ocurred: %s - %s - %s', + error.name, + error.message, + error.stack + ); + else + this.log.error( + 'An error ocurred: %s - %s - %s', + error.name, + error.message, + error.stack + ); + } - /* + /* public event listeners */ - private async onInteraction(interaction: Interaction): Promise { - this.emit('interactionCreate', interaction); - } + private async onInteraction(interaction: Interaction): Promise { + this.emit('interactionCreate', interaction); + } - private async onMessage(message: Message): Promise { - this.emit('messageCreate', message); - } + private async onMessage(message: Message): Promise { + this.emit('messageCreate', message); + } - private async onVoiceStateUpdate(oldState: VoiceState, newState: VoiceState): Promise { - this.emit('voiceStateUpdate', oldState, newState); - } + private async onVoiceStateUpdate( + oldState: VoiceState, + newState: VoiceState + ): Promise { + this.emit('voiceStateUpdate', oldState, newState); + } - /* + /* singleton logic */ - static #instance: Bot | null = null; + static #instance: Bot | null = null; - public static get get(): Bot { - if (!Bot.#instance) Bot.#instance = new Bot(); - return Bot.#instance; - } + public static get get(): Bot { + if (!Bot.#instance) Bot.#instance = new Bot(); + return Bot.#instance; + } }