66import com .dynxsty .dih4jda .interactions .commands .ContextCommand ;
77import com .dynxsty .dih4jda .interactions .commands .RegistrationType ;
88import com .dynxsty .dih4jda .interactions .commands .SlashCommand ;
9+ import com .dynxsty .dih4jda .interactions .components .ButtonHandler ;
10+ import com .dynxsty .dih4jda .interactions .components .ModalHandler ;
11+ import com .dynxsty .dih4jda .interactions .components .SelectMenuHandler ;
912import com .zaxxer .hikari .HikariDataSource ;
1013import io .sentry .Sentry ;
1114import lombok .Getter ;
12- import lombok .extern .slf4j .Slf4j ;
1315import net .dv8tion .jda .api .JDA ;
1416import net .dv8tion .jda .api .JDABuilder ;
1517import net .dv8tion .jda .api .OnlineStatus ;
1618import net .dv8tion .jda .api .entities .Message ;
19+ import net .dv8tion .jda .api .hooks .ListenerAdapter ;
1720import net .dv8tion .jda .api .requests .GatewayIntent ;
1821import net .dv8tion .jda .api .utils .AllowedMentions ;
1922import net .dv8tion .jda .api .utils .ChunkingFilter ;
2023import net .dv8tion .jda .api .utils .MemberCachePolicy ;
2124import net .dv8tion .jda .api .utils .cache .CacheFlag ;
2225import net .javadiscord .javabot .data .config .BotConfig ;
2326import net .javadiscord .javabot .data .h2db .DbHelper ;
24- import net .javadiscord .javabot .data .h2db .commands .QuickMigrateSubcommand ;
25- import net .javadiscord .javabot .data .h2db .message_cache .MessageCache ;
26- import net .javadiscord .javabot .data .h2db .message_cache .MessageCacheListener ;
27- import net .javadiscord .javabot .listener .*;
28- import net .javadiscord .javabot .systems .help .HelpChannelInteractionManager ;
29- import net .javadiscord .javabot .systems .help .HelpChannelListener ;
30- import net .javadiscord .javabot .systems .moderation .AutoMod ;
31- import net .javadiscord .javabot .systems .moderation .report .ReportManager ;
32- import net .javadiscord .javabot .systems .moderation .server_lock .ServerLockManager ;
33- import net .javadiscord .javabot .systems .qotw .commands .questions_queue .AddQuestionSubcommand ;
34- import net .javadiscord .javabot .systems .qotw .commands .view .QOTWQuerySubcommand ;
35- import net .javadiscord .javabot .systems .qotw .submissions .SubmissionInteractionManager ;
36- import net .javadiscord .javabot .systems .staff_commands .embeds .AddEmbedFieldSubcommand ;
37- import net .javadiscord .javabot .systems .staff_commands .embeds .CreateEmbedSubcommand ;
38- import net .javadiscord .javabot .systems .staff_commands .embeds .EditEmbedSubcommand ;
39- import net .javadiscord .javabot .systems .staff_commands .self_roles .SelfRoleInteractionManager ;
40- import net .javadiscord .javabot .systems .staff_commands .tags .CustomTagManager ;
41- import net .javadiscord .javabot .systems .staff_commands .tags .commands .CreateCustomTagSubcommand ;
42- import net .javadiscord .javabot .systems .staff_commands .tags .commands .EditCustomTagSubcommand ;
43- import net .javadiscord .javabot .systems .starboard .StarboardManager ;
44- import net .javadiscord .javabot .systems .user_commands .leaderboard .ExperienceLeaderboardSubcommand ;
45- import net .javadiscord .javabot .tasks .MetricsUpdater ;
27+ import net .javadiscord .javabot .systems .AutoDetectableComponentHandler ;
4628import net .javadiscord .javabot .tasks .PresenceUpdater ;
47- import net .javadiscord .javabot .tasks .ScheduledTasks ;
4829import net .javadiscord .javabot .util .ExceptionLogger ;
49- import net .javadiscord .javabot .util .InteractionUtils ;
50- import org .jetbrains .annotations .NotNull ;
51- import org .quartz .SchedulerException ;
5230import org .springframework .beans .factory .annotation .Autowired ;
5331import org .springframework .boot .SpringApplication ;
5432import org .springframework .boot .autoconfigure .SpringBootApplication ;
33+ import org .springframework .context .ConfigurableApplicationContext ;
5534import org .springframework .context .annotation .ComponentScan ;
5635import org .springframework .context .annotation .FilterType ;
36+ import org .springframework .scheduling .annotation .EnableScheduling ;
5737
5838import java .nio .file .Path ;
5939import java .time .ZoneOffset ;
40+ import java .util .Arrays ;
6041import java .util .EnumSet ;
42+ import java .util .HashMap ;
6143import java .util .List ;
6244import java .util .Map ;
6345import java .util .TimeZone ;
6446import java .util .concurrent .Executors ;
6547import java .util .concurrent .ScheduledExecutorService ;
6648
49+ import javax .annotation .PostConstruct ;
50+
6751/**
6852 * The main class where the bot is initialized.
6953 */
70- @ Slf4j
7154@ SpringBootApplication
72- @ ComponentScan (includeFilters = @ ComponentScan .Filter (type = FilterType .ASSIGNABLE_TYPE , classes = {SlashCommand .class , ContextCommand .class }))
55+ @ ComponentScan (
56+ includeFilters = @ ComponentScan .Filter (type = FilterType .ASSIGNABLE_TYPE , classes = { SlashCommand .class , ContextCommand .class , ListenerAdapter .class }),
57+ excludeFilters = @ ComponentScan .Filter (type =FilterType .ASSIGNABLE_TYPE , classes = PresenceUpdater .class )
58+ )
59+ @ EnableScheduling
7360public class Bot {
7461
7562 @ Getter
7663 private static BotConfig config ;
7764
78- @ Getter
79- private static AutoMod autoMod ;
80-
8165 @ Getter
8266 private static DIH4JDA dih4jda ;
8367
84- @ Getter
85- private static MessageCache messageCache ;
86-
87- @ Getter
88- private static ServerLockManager serverLockManager ;
89-
90- @ Getter
91- private static CustomTagManager customTagManager ;
92-
9368 @ Getter
9469 private static HikariDataSource dataSource ;
9570
@@ -102,9 +77,10 @@ public class Bot {
10277 *
10378 * @param commands The {@link Autowired} list of {@link SlashCommand}s.
10479 * @param contexts The {@link Autowired} list of {@link ContextCommand}s.
80+ * @param listeners The {@link Autowired} list of {@link ListenerAdapter}s.
10581 */
10682 @ Autowired
107- public Bot (final List <SlashCommand > commands , final List <ContextCommand > contexts ) {
83+ public Bot (final List <SlashCommand > commands , final List <ContextCommand > contexts , final List < ListenerAdapter > listeners ) {
10884 if (!commands .isEmpty ()) {
10985 getDih4jda ().addSlashCommands (commands .toArray (SlashCommand []::new ));
11086 }
@@ -116,6 +92,26 @@ public Bot(final List<SlashCommand> commands, final List<ContextCommand> context
11692 } catch (ReflectiveOperationException e ) {
11793 ExceptionLogger .capture (e , getClass ().getSimpleName ());
11894 }
95+ addEventListeners (listeners );
96+ }
97+
98+ private void addEventListeners (final List <ListenerAdapter > listeners ) {
99+ for (ListenerAdapter listener : listeners ) {
100+ dih4jda .getJDA ().addEventListener (listener );
101+ }
102+ dih4jda .getJDA ().addEventListener (dih4jda );
103+ }
104+
105+ /**
106+ * Initialize Sentry.
107+ */
108+ @ PostConstruct
109+ public void init () {
110+ Sentry .init (options -> {
111+ options .setDsn (config .getSystems ().getSentryDsn ());
112+ options .setTracesSampleRate (1.0 );
113+ options .setDebug (false );
114+ });
119115 }
120116
121117 /**
@@ -136,95 +132,48 @@ public static void main(String[] args) throws Exception {
136132 config = new BotConfig (Path .of ("config" ));
137133 dataSource = DbHelper .initDataSource (config );
138134 asyncPool = Executors .newScheduledThreadPool (config .getSystems ().getAsyncPoolSize ());
139- autoMod = new AutoMod ();
140135 JDA jda = JDABuilder .createDefault (config .getSystems ().getJdaBotToken ())
141136 .setStatus (OnlineStatus .DO_NOT_DISTURB )
142137 .setChunkingFilter (ChunkingFilter .ALL )
143138 .setMemberCachePolicy (MemberCachePolicy .ALL )
144139 .enableCache (CacheFlag .ACTIVITY )
145140 .enableIntents (GatewayIntent .GUILD_MEMBERS , GatewayIntent .GUILD_PRESENCES , GatewayIntent .MESSAGE_CONTENT )
146- .addEventListeners (autoMod , new StateListener ())
147141 .build ();
148142 AllowedMentions .setDefaultMentions (EnumSet .of (Message .MentionType .ROLE , Message .MentionType .CHANNEL , Message .MentionType .USER , Message .MentionType .EMOJI ));
149143 dih4jda = DIH4JDABuilder .setJDA (jda )
150144 .setDefaultCommandType (RegistrationType .GLOBAL )
151145 .disableLogging (DIH4JDALogger .Type .SMART_QUEUE_IGNORED )
152146 .disableAutomaticCommandRegistration ()
153147 .build ();
154- customTagManager = new CustomTagManager (jda , dataSource );
155- messageCache = new MessageCache ();
156- serverLockManager = new ServerLockManager (jda );
157- addEventListeners (jda , dih4jda );
158- addComponentHandler (dih4jda );
159- // initialize Sentry
160- Sentry .init (options -> {
161- options .setDsn (config .getSystems ().getSentryDsn ());
162- options .setTracesSampleRate (1.0 );
163- options .setDebug (false );
164- });
165- try {
166- ScheduledTasks .init (jda );
167- log .info ("Initialized scheduled tasks." );
168- } catch (SchedulerException e ) {
169- ExceptionLogger .capture (e , Bot .class .getSimpleName ());
170- log .error ("Could not initialize all scheduled tasks." , e );
171- jda .shutdown ();
172- }
173- SpringApplication .run (Bot .class , args );
148+ ConfigurableApplicationContext ctx = SpringApplication .run (Bot .class , args );
149+ registerComponentHandlers (ctx );
150+
174151 }
175152
176- /**
177- * Adds all the bots' event listeners to the JDA instance, except for
178- * the {@link AutoMod} instance.
179- *
180- * @param jda The JDA bot instance to add listeners to.
181- * @param dih4jda The {@link DIH4JDA} instance.
182- */
183- private static void addEventListeners (@ NotNull JDA jda , @ NotNull DIH4JDA dih4jda ) {
184- jda .addEventListener (
185- serverLockManager ,
186- PresenceUpdater .standardActivities (),
187- new MessageCacheListener (),
188- new GitHubLinkListener (),
189- new MessageLinkListener (),
190- new GuildJoinListener (),
191- new UserLeaveListener (),
192- new MetricsUpdater (),
193- new SuggestionListener (),
194- new StarboardManager (),
195- new HelpChannelListener (),
196- new ShareKnowledgeVoteListener (),
197- new JobChannelVoteListener (),
198- new PingableNameListener (),
199- new HugListener ()
200- );
201- dih4jda .addEventListener (new DIH4JDAListener ());
153+ private static void registerComponentHandlers (ConfigurableApplicationContext ctx ) {
154+ Map <String , Object > interactionHandlers = ctx .getBeansWithAnnotation (AutoDetectableComponentHandler .class );
155+ Map <List <String >, ButtonHandler > buttonHandlers = new HashMap <>();
156+ Map <List <String >, ModalHandler > modalHandlers = new HashMap <>();
157+ Map <List <String >, SelectMenuHandler > selectMenuHandlers = new HashMap <>();
158+ for (Object handler : interactionHandlers .values ()) {
159+ AutoDetectableComponentHandler annotation = handler .getClass ().getAnnotation (AutoDetectableComponentHandler .class );
160+ List <String > keys = Arrays .asList (annotation .value ());
161+ addHandler (buttonHandlers , keys , handler , ButtonHandler .class );
162+ addHandler (modalHandlers , keys , handler , ModalHandler .class );
163+ addHandler (selectMenuHandlers , keys , handler , SelectMenuHandler .class );
164+ }
165+ dih4jda .addButtonHandlers (buttonHandlers );
166+ dih4jda .addModalHandlers (modalHandlers );
167+ dih4jda .addSelectMenuHandlers (selectMenuHandlers );
202168 }
203169
204- private static void addComponentHandler (@ NotNull DIH4JDA dih4jda ) {
205- dih4jda .addButtonHandlers (Map .of (
206- List .of ("experience-leaderboard" ), new ExperienceLeaderboardSubcommand (),
207- List .of ("utils" ), new InteractionUtils (),
208- List .of ("resolve-report" ), new ReportManager (),
209- List .of ("self-role" ), new SelfRoleInteractionManager (),
210- List .of ("qotw-submission" ), new SubmissionInteractionManager (),
211- List .of ("help-channel" , "help-thank" ), new HelpChannelInteractionManager (),
212- List .of ("qotw-list-questions" ), new QOTWQuerySubcommand ()
213- ));
214- dih4jda .addModalHandlers (Map .of (
215- List .of ("qotw-add-question" ), new AddQuestionSubcommand (),
216- List .of ("embed-create" ), new CreateEmbedSubcommand (),
217- List .of (EditEmbedSubcommand .EDIT_EMBED_ID ), new EditEmbedSubcommand (),
218- List .of ("embed-addfield" ), new AddEmbedFieldSubcommand (),
219- List .of ("quick-migrate" ), new QuickMigrateSubcommand (),
220- List .of ("report" ), new ReportManager (),
221- List .of ("self-role" ), new SelfRoleInteractionManager (),
222- List .of ("tag-create" ), new CreateCustomTagSubcommand (),
223- List .of ("tag-edit" ), new EditCustomTagSubcommand ()
224- ));
225- dih4jda .addSelectMenuHandlers (Map .of (
226- List .of ("qotw-submission-select" ), new SubmissionInteractionManager ()
227- ));
170+ private static <T > void addHandler (Map <List <String >, T > handlers , List <String > keys , Object handler , Class <T > type ) {
171+ if (type .isInstance (handler )) {
172+ T old = handlers .putIfAbsent (keys , type .cast (handler ));
173+ if (old !=null ) {
174+ throw new IllegalStateException ("The same interaction name was registered multiple times" );
175+ }
176+ }
228177 }
229178}
230179
0 commit comments