Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | 3x 3x 3x 3x 3x 35x 35x 35x 35x 35x 35x 35x 35x 35x 35x 35x 35x 35x 35x 35x 35x 35x 11x 11x 10x 10x 9x 9x 8x 3x 3x 10x 10x 10x 10x 10x 10x 10x 10x 10x 2x 2x 2x 2x 2x 2x 2x 2x 1x 1x 1x 1x 5x 4x 6x 5x 3x 2x 2x 2x 3x | const { Client, GatewayIntentBits } = require('discord.js'); const ConfigurationResolver = require('./core/ConfigurationResolver'); const ComponentOrchestrator = require('./core/ComponentOrchestrator'); const BotLifecycleManager = require('./core/BotLifecycleManager'); const BotStateController = require('./core/BotStateController'); /** * DiscordReactionBot - Main bot coordinator class * Orchestrates specialized components for a clean, maintainable architecture * Now focused purely on coordination and high-level bot lifecycle management */ class DiscordReactionBot { constructor() { // Discord client with necessary intents for reaction roles and proposal system // These specific intents allow reading reactions, messages, and managing member roles this.client = new Client({ intents: [ GatewayIntentBits.Guilds, // Access to guild info GatewayIntentBits.GuildMessages, // Read messages for commands GatewayIntentBits.GuildMessageReactions, // Monitor reaction events GatewayIntentBits.MessageContent, // Access message text for proposal parsing GatewayIntentBits.GuildMembers // Role management capabilities ] }); // Runtime configuration loaded from deployment // These values come from terraform and vary per deployment environment this.config = null; this.guildId = null; this.botToken = null; this.runId = null; this.moderatorRoleId = null; this.memberRoleId = null; this.commandChannelId = null; this.memberCommandChannelId = null; this.eventsTable = null; this.reminderIntervals = null; // Initialize specialized component managers this.configResolver = new ConfigurationResolver(); this.componentOrchestrator = new ComponentOrchestrator(this); this.lifecycleManager = new BotLifecycleManager(this); this.stateController = new BotStateController(this.client); // Initialize components and setup event handlers this.componentOrchestrator.initializeComponents(); this.lifecycleManager.setupEventHandlers(); } /** * Initialize the bot with runtime configuration and start Discord connection */ async initialize() { try { // Load and validate runtime configuration const runtimeConfig = await this.configResolver.loadConfiguration(); // Extract configuration values this.extractConfigurationValues(runtimeConfig); // Initialize components that require configuration await this.componentOrchestrator.initializeConfigurableComponents(runtimeConfig); // Connect to Discord and start processing events // Bot becomes active and responsive after this point console.log('Logging into Discord...'); await this.client.login(this.botToken); console.log('Bot initialized successfully'); } catch (error) { console.error('Failed to initialize bot:', error); process.exit(1); } } /** * Extract configuration values from runtime config */ extractConfigurationValues(runtimeConfig) { // Extract Discord-specific configuration values // These IDs are unique to each Discord server and deployment this.guildId = runtimeConfig.guildId; this.botToken = runtimeConfig.botToken; this.runId = runtimeConfig.runId || 'unknown'; this.moderatorRoleId = runtimeConfig.moderatorRoleId; this.memberRoleId = runtimeConfig.memberRoleId; this.commandChannelId = runtimeConfig.commandChannelId; this.memberCommandChannelId = runtimeConfig.memberCommandChannelId; this.eventsTable = runtimeConfig.eventsTable; this.reminderIntervals = runtimeConfig.reminderIntervals; } // Getter methods for controlled access to bot configuration and components // These provide a clean interface for other modules to access bot state // without exposing the internal structure or allowing direct modification getGuildId() { return this.guildId; } getRunId() { return this.runId; } getModeratorRoleId() { return this.moderatorRoleId; } getMemberRoleId() { return this.memberRoleId; } getCommandChannelId() { return this.commandChannelId; } getMemberCommandChannelId() { return this.memberCommandChannelId; } getEventsTable() { return this.eventsTable; } getReminderIntervals() { return this.reminderIntervals; } // Component access methods getConfig() { return this.configManager.getConfig(); } getConfigManager() { return this.configManager; } getProposalManager() { return this.proposalManager; } getUserValidator() { return this.userValidator; } getEventManager() { return this.eventManager; } // Bot state management delegation enableBot(botId) { return this.stateController.enableBot(botId); } disableBot(botId) { return this.stateController.disableBot(botId); } isBotEnabled(botId) { return this.stateController.isBotEnabled(botId); } isThisBotEnabled() { return this.stateController.isThisBotEnabled(); } getBotId() { return this.stateController.getBotId(); } /** * Cleanup method for graceful shutdown */ async cleanup() { await this.componentOrchestrator.cleanup(); this.client.destroy(); console.log('✅ DiscordReactionBot cleaned up'); } } module.exports = DiscordReactionBot; |