import { Client, GatewayIntentBits, Guild, Collection, GuildMember, Message, TextChannel } from 'discord.js' import * as dotenv from 'dotenv' import { DyFM_Error, DyFM_Log, hour, week } from '@futdevpro/fsm-dynamo' import { DyNTS_DiBo_Routines_ControlService } from './dibo-routines.control-service' import { DyNTS_DiBo_Commands_ControlService } from './dibo-commands.control-service' import { DyNTS_SingletonService } from '../../../_services/base/singleton.service' import { DyNTS_DiBo_Main_ControlService } from './dibo-main.control-service' import { DyNTS_global_settings } from '../../../_collections/global-settings.const' import { DyNTS_DiBo_global_settings } from '../_collections/dibo-global-settings.conts' /* type T_Main_CS = DyNTS_DiBo_Main_ControlService; */ export abstract class DyNTS_DiBo_IO_ControlService extends DyNTS_SingletonService { /* static getInstance(): DyNTS_DiBo_IO_ControlService { return DyNTS_DiBo_IO_ControlService.getSingletonInstance(); } */ protected abstract getMainDiscordBotControlService(): DyNTS_DiBo_Main_ControlService; protected abstract mainDiscordBot_CS: DyNTS_DiBo_Main_ControlService; /* protected abstract readonly mainDiscordBot_CS: DyNTS_DiBo_Main_ControlService; */ get discordServer(): Guild { return this.mainDiscordBot_CS?.discordServer; } get botClientId(): string { return this.mainDiscordBot_CS.botClientId; } get botDisplayName(): string { return this.mainDiscordBot_CS.botDisplayName; } protected abstract getCommandsControlService(): DyNTS_DiBo_Commands_ControlService; protected commands_CS: DyNTS_DiBo_Commands_ControlService; dontSendErrorReply?: boolean; /* protected constructor() { super(); } */ async setup(issuer: string): Promise { try { this.mainDiscordBot_CS = this.getMainDiscordBotControlService(); this.commands_CS = this.getCommandsControlService(); if (!this.mainDiscordBot_CS) { throw new DyFM_Error({ ...this.getDefaultErrorSettings('setup', new Error('Main Discord Bot Control Service not found'), issuer), errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-DiBo-IO-S01`, }) } if (!this.commands_CS) { throw new DyFM_Error({ ...this.getDefaultErrorSettings('setup', new Error('Commands Control Service not found'), issuer), errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-DiBo-IO-S02`, }) } } catch (error) { throw new DyFM_Error({ ...this.getDefaultErrorSettings('setup', error, issuer), errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-DiBo-IO-S000`, }) } } async start(issuer: string): Promise { try { if (!this.discordServer) { throw new DyFM_Error({ ...this.getDefaultErrorSettings('start', new Error('Discord server not found'), issuer), errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-DiBo-IO-ST00`, }) } } catch (error) { throw new DyFM_Error({ ...this.getDefaultErrorSettings('start', error, issuer), errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-DiBo-IO-ST00`, }) } } async handleNewMessage(message: Message, issuer: string): Promise { try { if (DyNTS_DiBo_global_settings.debugLevel >= 1) { DyFM_Log.H_log(`incoming message (${message.author.displayName}):\n${message.content}`) } const isForYou = await this.getMessageIsForBotToHandle(message, issuer); if (!isForYou) { return; } const isHandledAsCommand = await this.handleIfCommand(message, issuer); if (isHandledAsCommand) { return; } await this.handleMessage(message, issuer); } catch (error) { DyFM_Error.logSimple('โŒโŒ Error handleNewMessage:', error); if (!this.dontSendErrorReply && DyNTS_DiBo_global_settings.debugLevel >= 1) { await message.reply( `[SYSTEM|ERROR|${DyNTS_global_settings.systemShortCodeName}|DyNTS-DiBo-IO-H0] Error occurred while handling the message:\n` + DyFM_Error.getAnyMessage(error) ).catch(error => { DyFM_Error.logSimple('โŒโŒ Error sending message to report channel:', error); }); } throw new DyFM_Error({ ...this.getDefaultErrorSettings('handleNewMessage', error, issuer), errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-DiBo-MCS-H0`, }) } } abstract handleMessage(message: Message, issuer: string): Promise; async getMessageIsForBotToHandle( message: Message, issuer: string, dontRemovePing?: boolean ): Promise { try { if (!this.discordServer || !this.mainDiscordBot_CS || !this.botClientId) { DyFM_Log.H_error( '๐ŸšซโŒ Bot not initialized yet. END wont respond to message:', message.content, new Error('Bot not initialized yet').stack ) //await this.mainDiscordBot_CS.start(issuer); if (!this.discordServer || !this.mainDiscordBot_CS || !this.botClientId) { DyFM_Log.H_error( '๐ŸšซโŒโŒ can not start bot. END wont respond to message:', message.content, new Error('can not start bot').stack ) } return false; } const messageIsReplyTo: Message = message.channel.messages.cache.get( message?.reference?.messageId ); const isReplyForYou = messageIsReplyTo && messageIsReplyTo.author.id === this.botClientId; const isPinged = message.content.includes(this.botClientId) || message.cleanContent.includes(`@${this.botDisplayName}`) || isReplyForYou; const isOwnMessage = message.author.id === this.botClientId || message.author.displayName === this.botDisplayName; const haveSkipFlags = DyNTS_DiBo_global_settings.messageSettings.skipFlags.some( flag => message.content.includes(flag) ); const channelName = (message.channel as TextChannel)?.name; const isDMChannel = message.channel.isDMBased(); const isInDefaultChannel = DyNTS_DiBo_global_settings.channelSettings.defaultChannels.includes( channelName ) || (isDMChannel && DyNTS_DiBo_global_settings.channelSettings.dmIsAllowed); const isAllowedChannel = DyNTS_DiBo_global_settings.channelSettings.allowedChannels.includes( channelName ) || (isDMChannel && DyNTS_DiBo_global_settings.channelSettings.dmIsAllowed); if (!isAllowedChannel) { if (DyNTS_DiBo_global_settings.debugLevel >= 2) { DyFM_Log.warn('๐ŸšซโŒ not allowed channel. END') } if (!isOwnMessage && isPinged) { message.reply( `[SYSTEM|REFUSE|CHANNEL] I'm sorry, but I'm not allowed to answer you in this channel!` ) } return false; } if (isOwnMessage) { if (DyNTS_DiBo_global_settings.debugLevel >= 2) { DyFM_Log.warn('๐Ÿšซ๐Ÿค– will not answer; own message') } return false; } if (haveSkipFlags) { if (DyNTS_DiBo_global_settings.debugLevel >= 2) { DyFM_Log.warn('๐Ÿšซ๐Ÿณ๏ธ not for me; this message have some skip flags:', DyNTS_DiBo_global_settings.messageSettings.skipFlags.filter( flag => message.content.includes(flag) ), message.content ) } return false; } if ( //isPinged && //!isOwnMessage && vรณtmรก message.author.bot && !DyNTS_DiBo_global_settings.allowBotsInteractEachOther ) { if (isPinged && DyNTS_DiBo_global_settings.debugLevel >= 2) { DyFM_Log.warn('๐Ÿšซ๐Ÿค–โŒ not for me; this message is from a bot') message.reply('[SYSTEM|REFUSE|BOT] You should not ping me!') } return false; } if (!isPinged /* && !isOwnMessage vรณtmรก */ && !isInDefaultChannel) { if (DyNTS_DiBo_global_settings.debugLevel >= 2) { DyFM_Log.warn('๐Ÿšซ not for me; not pinged, and not my message, and not in default channel') } return false; } const isAllowedUser = DyNTS_DiBo_global_settings.allowedUsers === 'all' || DyNTS_DiBo_global_settings.allowedUsers.includes(message.author.id) || DyNTS_DiBo_global_settings.allowedUsers.includes(message.author.username) || DyNTS_DiBo_global_settings.allowedUsers.includes(message.author.displayName); if (!isAllowedUser) { if (DyNTS_DiBo_global_settings.debugLevel >= 2) { DyFM_Log.warn('๐ŸšซโŒ not allowed user. END', message.author.username, message.author.displayName) message.reply( `[SYSTEM|REFUSE|USER] I'm sorry, but I'm not allowed to answer you!` ) } return false; } if (!message.channel.isTextBased()) { if (DyNTS_DiBo_global_settings.debugLevel >= 2) { DyFM_Log.warn('๐ŸšซโŒ not text based channel. END') } return false; } return true; } catch (error) { throw new DyFM_Error({ ...this.getDefaultErrorSettings('getMessageIsForBotToHandle', error, issuer), errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-DiBo-MCS-G0`, }) } } async handleIfCommand(message: Message, issuer: string): Promise { try { const isCommand = await this.isCommand(message, issuer); if (isCommand) { await this.commands_CS.handleCommand(message, issuer); } return Boolean(isCommand); } catch (error) { throw new DyFM_Error({ ...this.getDefaultErrorSettings('handleIfCommand', error, issuer), errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-DiBo-IO-HIC0`, }) } } async isCommand(message: Message, issuer: string): Promise { try { let haveCommandOperator = false; if (!DyNTS_DiBo_global_settings.commandSettings.commandOperator) { haveCommandOperator = true; } else if ( message.content.trim().startsWith(DyNTS_DiBo_global_settings.commandSettings.commandOperator) ) { haveCommandOperator = true; } if (!haveCommandOperator) { return false; } const commandExists = DyNTS_DiBo_global_settings.commandSettings.commands.find( (command) => message.content.trim().startsWith( `${DyNTS_DiBo_global_settings.commandSettings.commandOperator}${command.command}` ) ); return Boolean(commandExists); } catch (error) { throw new DyFM_Error({ ...this.getDefaultErrorSettings('isCommand', error, issuer), errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-DiBo-IO-IC0`, }) } } }