import Role from '../models/Role' ; import Configuration from '../models/Configuration' ; import { Client , CommandoGuild } from 'discord.js-commando' ; import { RoleManager } from './role.manager' ; import { ConfigurationManager } from './configuration.manager' ; import { Activity , Presence , TextChannel } from 'discord.js' ; export interface BotDeveloper { name : string ; link : string ; } /**
 * Manages the Discord client instance.
 *
 * Can set up and initialize necessary objects, and load data to the local storage.
 */ export class ClientManager { /**
     * Singleton instance of ClientManager.
     */ private static instance : ClientManager | undefined ; /**
     * Whether the singleton instance is initialized.
     */ protected initialized : boolean ; /**
     * Instance of the Discord client.
     */ protected client : Client | undefined ; /**
     * Timestamp of when the client was loaded up.
     */ protected startedAt : Date | undefined ; protected constructor ( ) { this . initialized = false ; } /**
     * Get the instance of ClientManager.
     */ static get ( ) { if ( this . instance === undefined ) { this . instance = new ClientManager ; } return this . instance ; } param client init ( client ) { if ( this . initialized ) { return ; } this . client = client ; this . startedAt = new Date ( ) ; this . initialized = true ; } /**
     * Initialize all necessary objects.
     */ async load ( ) { if ( ! this . isInitialized ( ) ) { throw new Error ( 'The instance is not initialized!' ) ; } const roles = await Role . all ( ) ; RoleManager . get ( ) . fetchRoles ( roles ) ; await Configuration . createDefaultConfigurations ( ) ; const configurations = await Configuration . all ( ) ; ConfigurationManager . get ( ) . fetchConfigurations ( configurations ) ; } /**
     * Determine whether all necessary objects have been initialized.
     */ isInitialized ( ) { return this . initialized ; } /**
     * Get the instance of the Date class of when the bot was loaded up.
     */ getStartedAt ( ) { return this . startedAt ; } /**
     * Get the developers of the bot.
     *
     * If you feel like you contributed a fair part to the bot, do not hesitate
     * to add yourself with a link to your portfolio (or a Github profile).
     *
     * Any advertisement or promotional links will not be accepted!
     */ getDevelopers ( ) { return [ { name : 'TruckersMP' , link : 'https://truckersmp.com' } , { name : '3v' , link : 'https://3v.fi/' } , ] ; } /**
     * Gets called when the client is ready.
     */ async onReady ( ) { if ( ! this . isInitialized ( ) ) { throw new Error ( 'The instance is not initialized!' ) ; } this . updateCommandPrefix ( ) ; setInterval ( ( client ) => ClientManager . setActivity ( client ) , 60 * 1000 , this . client ) ; await ClientManager . setActivity ( this . client ) ; await this . clearConfigurations ( ) ; await this . clearReactionRoles ( ) ; } /**
     * Load the command prefix for all guilds from the configuration.
     *
     * In the development mode, the command prefix is kept to default.
     */ protected updateCommandPrefix ( ) { if ( global . LOCAL ) { return ; } for ( const [ guildId , guild ] of this . client . guilds . cache ) { const commandoGuild = < CommandoGuild > guild ; commandoGuild . commandPrefix = ConfigurationManager . get ( ) . getConfiguration ( 'prefix' , guildId ) ; } } /**
     * Clear all configurations of guilds which the client is not in anymore.
     */ protected async clearConfigurations ( ) { if ( process . env . CLEAR_GUILD === 'false' ) { return ; } for ( const guild of ConfigurationManager . get ( ) . getGuilds ( true ) ) { if ( this . client . guilds . resolve ( guild ) ) { continue ; } await Configuration . deleteGuildConfigurations ( guild ) ; ConfigurationManager . get ( ) . removeGuild ( guild ) ; } } /**
     * Clear all reaction roles of channels and messages that have been
     * removed. Guild roles will be removed only if the cleanup is enabled.
     */ protected async clearReactionRoles ( ) { for ( const guildId of RoleManager . get ( ) . getManagedGuilds ( ) ) { await this . clearGuildRoles ( guildId ) ; } } param guildID async clearGuildRoles ( guildID ) { const guild = this . client . guilds . resolve ( guildID ) ; if ( ! guild ) { if ( process . env . CLEAR_GUILD === 'false' ) { return ; } await Role . deleteGuildRoles ( guildID ) ; RoleManager . get ( ) . removeGuild ( guildID ) ; return ; } const channels = [ ] ; const messages = new Map < string , string [ ] > ( ) ; for ( const role of RoleManager . get ( ) . getManagedRoles ( ) ) { if ( role . guildID !== guildID ) { continue ; } if ( ! channels . includes ( role . channelID ) ) { channels . push ( role . channelID ) ; messages . set ( role . channelID , [ ] ) ; } if ( ! messages . get ( role . channelID ) . includes ( role . messageID ) ) { messages . get ( role . channelID ) . push ( role . messageID ) ; } } for ( const channelID of channels ) { const channel = guild . channels . resolve ( channelID ) ; if ( ! channel ) { await Role . deleteChannelRoles ( channelID ) ; RoleManager . get ( ) . removeChannel ( guildID , channelID ) ; continue ; } const textChannel = < TextChannel > channel ; for ( const messageID of messages . get ( channelID ) ) { const message = await textChannel . messages . fetch ( messageID ) ; if ( ! message ) { await Role . deleteMessageRoles ( messageID ) ; RoleManager . get ( ) . removeMessage ( guildID , channelID , messageID ) ; } } } } param client protected static async setActivity ( client ) { const user = await client . user . fetch ( ) ; if ( ! this . isPlaying ( user . presence ) ) { await client . user . setActivity ( { name : 'TruckersMP' , url : 'https://truckersmp.com' , type : 'PLAYING' , } ) ; } } param presence protected static isPlaying ( presence ) { return presence . activities . find ( ( activity ) => activity . type === 'PLAYING' ) !== undefined ; } }