Skip to content

Commit 8ef8f57

Browse files
committed
replace static state in Bot class with dependency injection
1 parent 7ce98d8 commit 8ef8f57

File tree

138 files changed

+1482
-719
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

138 files changed

+1482
-719
lines changed

src/main/java/net/javadiscord/javabot/Bot.java

Lines changed: 45 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,37 @@
11
package net.javadiscord.javabot;
22

3+
import java.time.ZoneOffset;
4+
import java.util.Arrays;
5+
import java.util.EnumSet;
6+
import java.util.HashMap;
7+
import java.util.List;
8+
import java.util.Map;
9+
import java.util.TimeZone;
10+
11+
import javax.annotation.PostConstruct;
12+
13+
import org.springframework.boot.SpringApplication;
14+
import org.springframework.boot.autoconfigure.SpringBootApplication;
15+
import org.springframework.context.ApplicationContext;
16+
import org.springframework.context.annotation.ComponentScan;
17+
import org.springframework.context.annotation.FilterType;
18+
import org.springframework.scheduling.annotation.EnableScheduling;
19+
320
import com.dynxsty.dih4jda.DIH4JDA;
4-
import com.dynxsty.dih4jda.DIH4JDABuilder;
5-
import com.dynxsty.dih4jda.DIH4JDALogger;
621
import com.dynxsty.dih4jda.interactions.commands.ContextCommand;
7-
import com.dynxsty.dih4jda.interactions.commands.RegistrationType;
822
import com.dynxsty.dih4jda.interactions.commands.SlashCommand;
923
import com.dynxsty.dih4jda.interactions.components.ButtonHandler;
1024
import com.dynxsty.dih4jda.interactions.components.ModalHandler;
1125
import com.dynxsty.dih4jda.interactions.components.SelectMenuHandler;
12-
import com.zaxxer.hikari.HikariDataSource;
1326
import io.sentry.Sentry;
14-
import lombok.Getter;
15-
import net.dv8tion.jda.api.JDA;
16-
import net.dv8tion.jda.api.JDABuilder;
17-
import net.dv8tion.jda.api.OnlineStatus;
27+
import lombok.RequiredArgsConstructor;
1828
import net.dv8tion.jda.api.entities.Message;
1929
import net.dv8tion.jda.api.hooks.ListenerAdapter;
20-
import net.dv8tion.jda.api.requests.GatewayIntent;
2130
import net.dv8tion.jda.api.utils.AllowedMentions;
22-
import net.dv8tion.jda.api.utils.ChunkingFilter;
23-
import net.dv8tion.jda.api.utils.MemberCachePolicy;
24-
import net.dv8tion.jda.api.utils.cache.CacheFlag;
2531
import net.javadiscord.javabot.data.config.BotConfig;
26-
import net.javadiscord.javabot.data.h2db.DbHelper;
2732
import net.javadiscord.javabot.systems.AutoDetectableComponentHandler;
2833
import net.javadiscord.javabot.tasks.PresenceUpdater;
2934
import net.javadiscord.javabot.util.ExceptionLogger;
30-
import org.springframework.beans.factory.annotation.Autowired;
31-
import org.springframework.boot.SpringApplication;
32-
import org.springframework.boot.autoconfigure.SpringBootApplication;
33-
import org.springframework.context.ConfigurableApplicationContext;
34-
import org.springframework.context.annotation.ComponentScan;
35-
import org.springframework.context.annotation.FilterType;
36-
import org.springframework.scheduling.annotation.EnableScheduling;
37-
38-
import java.nio.file.Path;
39-
import java.time.ZoneOffset;
40-
import java.util.Arrays;
41-
import java.util.EnumSet;
42-
import java.util.HashMap;
43-
import java.util.List;
44-
import java.util.Map;
45-
import java.util.TimeZone;
46-
import java.util.concurrent.Executors;
47-
import java.util.concurrent.ScheduledExecutorService;
48-
49-
import javax.annotation.PostConstruct;
5035

5136
/**
5237
* The main class where the bot is initialized.
@@ -57,43 +42,16 @@
5742
excludeFilters = @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, classes = PresenceUpdater.class)
5843
)
5944
@EnableScheduling
45+
@RequiredArgsConstructor
6046
public class Bot {
6147

62-
@Getter
63-
private static BotConfig config;
64-
65-
@Getter
66-
private static DIH4JDA dih4jda;
67-
68-
@Getter
69-
private static HikariDataSource dataSource;
48+
private final DIH4JDA dih4jda;
49+
private final BotConfig config;
50+
private final List<SlashCommand> commands;
51+
private final List<ContextCommand> contextCommands;
52+
private final List<ListenerAdapter> listeners;
53+
private final ApplicationContext ctx;
7054

71-
@Getter
72-
private static ScheduledExecutorService asyncPool;
73-
74-
/**
75-
* The constructor of this class, which also adds all {@link SlashCommand} and
76-
* {@link ContextCommand} to the {@link DIH4JDA} instance.
77-
*
78-
* @param commands The {@link Autowired} list of {@link SlashCommand}s.
79-
* @param contexts The {@link Autowired} list of {@link ContextCommand}s.
80-
* @param listeners The {@link Autowired} list of {@link ListenerAdapter}s.
81-
*/
82-
@Autowired
83-
public Bot(final List<SlashCommand> commands, final List<ContextCommand> contexts, final List<ListenerAdapter> listeners) {
84-
if (!commands.isEmpty()) {
85-
getDih4jda().addSlashCommands(commands.toArray(SlashCommand[]::new));
86-
}
87-
if (!contexts.isEmpty()) {
88-
getDih4jda().addContextCommands(contexts.toArray(ContextCommand[]::new));
89-
}
90-
try {
91-
getDih4jda().registerInteractions();
92-
} catch (ReflectiveOperationException e) {
93-
ExceptionLogger.capture(e, getClass().getSimpleName());
94-
}
95-
addEventListeners(listeners);
96-
}
9755

9856
private void addEventListeners(final List<ListenerAdapter> listeners) {
9957
for (ListenerAdapter listener : listeners) {
@@ -103,7 +61,7 @@ private void addEventListeners(final List<ListenerAdapter> listeners) {
10361
}
10462

10563
/**
106-
* Initialize Sentry.
64+
* Initializes Sentry, interactions and listeners.
10765
*/
10866
@PostConstruct
10967
public void init() {
@@ -112,6 +70,19 @@ public void init() {
11270
options.setTracesSampleRate(1.0);
11371
options.setDebug(false);
11472
});
73+
if (!commands.isEmpty()) {
74+
dih4jda.addSlashCommands(commands.toArray(SlashCommand[]::new));
75+
}
76+
if (!contextCommands.isEmpty()) {
77+
dih4jda.addContextCommands(contextCommands.toArray(ContextCommand[]::new));
78+
}
79+
try {
80+
dih4jda.registerInteractions();
81+
} catch (ReflectiveOperationException e) {
82+
ExceptionLogger.capture(e, getClass().getSimpleName());
83+
}
84+
addEventListeners(listeners);
85+
registerComponentHandlers(ctx);
11586
}
11687

11788
/**
@@ -129,45 +100,28 @@ public void init() {
129100
*/
130101
public static void main(String[] args) throws Exception {
131102
TimeZone.setDefault(TimeZone.getTimeZone(ZoneOffset.UTC));
132-
config = new BotConfig(Path.of("config"));
133-
dataSource = DbHelper.initDataSource(config);
134-
asyncPool = Executors.newScheduledThreadPool(config.getSystems().getAsyncPoolSize());
135-
JDA jda = JDABuilder.createDefault(config.getSystems().getJdaBotToken())
136-
.setStatus(OnlineStatus.DO_NOT_DISTURB)
137-
.setChunkingFilter(ChunkingFilter.ALL)
138-
.setMemberCachePolicy(MemberCachePolicy.ALL)
139-
.enableCache(CacheFlag.ACTIVITY)
140-
.enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_PRESENCES, GatewayIntent.MESSAGE_CONTENT)
141-
.build();
142103
AllowedMentions.setDefaultMentions(EnumSet.of(Message.MentionType.ROLE, Message.MentionType.CHANNEL, Message.MentionType.USER, Message.MentionType.EMOJI));
143-
dih4jda = DIH4JDABuilder.setJDA(jda)
144-
.setDefaultCommandType(RegistrationType.GLOBAL)
145-
.disableLogging(DIH4JDALogger.Type.SMART_QUEUE_IGNORED)
146-
.disableAutomaticCommandRegistration()
147-
.build();
148-
ConfigurableApplicationContext ctx = SpringApplication.run(Bot.class, args);
149-
registerComponentHandlers(ctx);
150-
104+
SpringApplication.run(Bot.class, args);
151105
}
152106

153-
private static void registerComponentHandlers(ConfigurableApplicationContext ctx) {
107+
private void registerComponentHandlers(ApplicationContext ctx) {
154108
Map<String, Object> interactionHandlers = ctx.getBeansWithAnnotation(AutoDetectableComponentHandler.class);
155109
Map<List<String>, ButtonHandler> buttonHandlers = new HashMap<>();
156110
Map<List<String>, ModalHandler> modalHandlers = new HashMap<>();
157111
Map<List<String>, SelectMenuHandler> selectMenuHandlers = new HashMap<>();
158112
for (Object handler : interactionHandlers.values()) {
159113
AutoDetectableComponentHandler annotation = handler.getClass().getAnnotation(AutoDetectableComponentHandler.class);
160114
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);
115+
addComponentHandler(buttonHandlers, keys, handler, ButtonHandler.class);
116+
addComponentHandler(modalHandlers, keys, handler, ModalHandler.class);
117+
addComponentHandler(selectMenuHandlers, keys, handler, SelectMenuHandler.class);
164118
}
165119
dih4jda.addButtonHandlers(buttonHandlers);
166120
dih4jda.addModalHandlers(modalHandlers);
167121
dih4jda.addSelectMenuHandlers(selectMenuHandlers);
168122
}
169123

170-
private static <T> void addHandler(Map<List<String>, T> handlers, List<String> keys, Object handler, Class<T> type) {
124+
private <T> void addComponentHandler(Map<List<String>, T> handlers, List<String> keys, Object handler, Class<T> type) {
171125
if (type.isInstance(handler)) {
172126
T old = handlers.putIfAbsent(keys, type.cast(handler));
173127
if(old!=null) {
Lines changed: 80 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,102 @@
11
package net.javadiscord.javabot;
22

3-
import net.dv8tion.jda.api.JDA;
4-
import net.javadiscord.javabot.tasks.PresenceUpdater;
3+
import java.nio.file.Path;
4+
import java.util.concurrent.Executors;
5+
import java.util.concurrent.ScheduledExecutorService;
56

7+
import javax.security.auth.login.LoginException;
68
import javax.sql.DataSource;
79

810
import org.springframework.context.annotation.Bean;
911
import org.springframework.context.annotation.Configuration;
1012

13+
import com.dynxsty.dih4jda.DIH4JDA;
14+
import com.dynxsty.dih4jda.DIH4JDABuilder;
15+
import com.dynxsty.dih4jda.DIH4JDALogger;
16+
import com.dynxsty.dih4jda.exceptions.DIH4JDAException;
17+
import com.dynxsty.dih4jda.interactions.commands.RegistrationType;
18+
19+
import lombok.RequiredArgsConstructor;
20+
import net.dv8tion.jda.api.JDA;
21+
import net.dv8tion.jda.api.JDABuilder;
22+
import net.dv8tion.jda.api.OnlineStatus;
23+
import net.dv8tion.jda.api.requests.GatewayIntent;
24+
import net.dv8tion.jda.api.utils.ChunkingFilter;
25+
import net.dv8tion.jda.api.utils.MemberCachePolicy;
26+
import net.dv8tion.jda.api.utils.cache.CacheFlag;
27+
import net.javadiscord.javabot.data.config.BotConfig;
28+
import net.javadiscord.javabot.data.config.SystemsConfig;
29+
import net.javadiscord.javabot.data.h2db.DbHelper;
30+
import net.javadiscord.javabot.listener.StateListener;
31+
import net.javadiscord.javabot.tasks.PresenceUpdater;
32+
1133
/**
1234
* This class holds all configuration settings and {@link Bean}s.
1335
*/
1436
@Configuration
37+
@RequiredArgsConstructor
1538
public class SpringConfig {
1639
@Bean
17-
public JDA getJDA() {
18-
return Bot.getDih4jda().getJDA();
40+
public PresenceUpdater standardActivityPresenceUpdater() {
41+
return PresenceUpdater.standardActivities();
1942
}
2043

2144
@Bean
22-
public PresenceUpdater standardActivityPresenceUpdater() {
23-
return PresenceUpdater.standardActivities();
45+
public DataSource getDataSource(BotConfig config) {
46+
return DbHelper.initDataSource(config);
47+
}
48+
49+
@Bean
50+
public ScheduledExecutorService asyncPool(BotConfig config) {
51+
return Executors.newScheduledThreadPool(config.getSystems().getAsyncPoolSize());
52+
}
53+
54+
@Bean
55+
public BotConfig config() {
56+
return new BotConfig(Path.of("config"));
57+
}
58+
59+
@Bean
60+
public SystemsConfig systemsConfig(BotConfig botConfig) {
61+
return botConfig.getSystems();
62+
}
63+
64+
/**
65+
* Initializes the {@link JDA} instances.
66+
* @param botConfig the main configuration of the bot
67+
* @param stateListener The {@link StateListener} which is listening for JDA lifecycle events and needs to be added before JDA is fully initialized
68+
* @return the initialized {@link JDA} object
69+
* @throws LoginException if the token is invalid
70+
*/
71+
@Bean
72+
public JDA jda(BotConfig botConfig, StateListener stateListener) throws LoginException {
73+
return JDABuilder.createDefault(botConfig.getSystems().getJdaBotToken())
74+
.setStatus(OnlineStatus.DO_NOT_DISTURB)
75+
.setChunkingFilter(ChunkingFilter.ALL)
76+
.setMemberCachePolicy(MemberCachePolicy.ALL)
77+
.enableCache(CacheFlag.ACTIVITY)
78+
.enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_PRESENCES, GatewayIntent.MESSAGE_CONTENT)
79+
.addEventListeners(stateListener)
80+
.build();
81+
}
82+
83+
/**
84+
* Initializes {@link DIH4JDA}.
85+
* @param jda the initialized {@link JDA} instance
86+
* @return the initialized {@link DIH4JDA} object
87+
* @throws DIH4JDAException if an error occurs while initializing {@link DIH4JDA}
88+
*/
89+
@Bean
90+
public DIH4JDA initializeDIH4JDA(JDA jda) throws DIH4JDAException {
91+
return DIH4JDABuilder.setJDA(jda)
92+
.setDefaultCommandType(RegistrationType.GLOBAL)
93+
.disableLogging(DIH4JDALogger.Type.SMART_QUEUE_IGNORED)
94+
.disableAutomaticCommandRegistration()
95+
.build();
2496
}
2597

2698
@Bean
27-
public DataSource getDataSource() {
28-
return Bot.getDataSource();
99+
public BotConfig botConfig() {
100+
return new BotConfig(Path.of("config"));
29101
}
30102
}

src/main/java/net/javadiscord/javabot/api/TomcatConfig.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package net.javadiscord.javabot.api;
22

3-
import net.javadiscord.javabot.Bot;
3+
import net.javadiscord.javabot.data.config.SystemsConfig;
4+
45
import org.apache.catalina.connector.Connector;
56
import org.apache.coyote.ajp.AjpNioProtocol;
67
import org.springframework.beans.factory.annotation.Value;
78
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
89
import org.springframework.context.annotation.Bean;
910
import org.springframework.context.annotation.Configuration;
1011

12+
1113
/**
1214
* Holds all configuration for the {@link org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat}
1315
* web service.
@@ -16,12 +18,19 @@
1618
public class TomcatConfig {
1719

1820
private final int ajpPort;
19-
2021
private final boolean tomcatAjpEnabled;
22+
private final SystemsConfig systemsConfig;
2123

22-
public TomcatConfig(@Value("${tomcat.ajp.port}") int ajpPort, @Value("${tomcat.ajp.enabled}") boolean tomcatAjpEnabled) {
24+
/**
25+
* Initializes this object.
26+
* @param ajpPort The port to run AJP under
27+
* @param tomcatAjpEnabled <code>true</code> if AJP is enabled, else <code>false</code>
28+
* @param systemsConfig an object representing the configuration of various systems
29+
*/
30+
public TomcatConfig(@Value("${tomcat.ajp.port}") int ajpPort, @Value("${tomcat.ajp.enabled}") boolean tomcatAjpEnabled, SystemsConfig systemsConfig) {
2331
this.ajpPort = ajpPort;
2432
this.tomcatAjpEnabled = tomcatAjpEnabled;
33+
this.systemsConfig = systemsConfig;
2534
}
2635

2736
/**
@@ -36,7 +45,7 @@ public TomcatServletWebServerFactory servletContainer() {
3645
if (tomcatAjpEnabled) {
3746
Connector ajpConnector = new Connector("org.apache.coyote.ajp.AjpNioProtocol");
3847
AjpNioProtocol protocol= (AjpNioProtocol) ajpConnector.getProtocolHandler();
39-
protocol.setSecret(Bot.getConfig().getSystems().getApiConfig().getAjpSecret());
48+
protocol.setSecret(systemsConfig.getApiConfig().getAjpSecret());
4049
ajpConnector.setPort(ajpPort);
4150
ajpConnector.setSecure(true);
4251
tomcat.addAdditionalTomcatConnectors(ajpConnector);

0 commit comments

Comments
 (0)