-
-
Notifications
You must be signed in to change notification settings - Fork 108
Expand file tree
/
Copy pathApplication.java
More file actions
126 lines (106 loc) · 4.88 KB
/
Application.java
File metadata and controls
126 lines (106 loc) · 4.88 KB
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
package org.togetherjava.tjbot;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.exceptions.InvalidTokenException;
import net.dv8tion.jda.api.requests.GatewayIntent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.togetherjava.tjbot.config.Config;
import org.togetherjava.tjbot.db.Database;
import org.togetherjava.tjbot.features.Features;
import org.togetherjava.tjbot.features.SlashCommandAdapter;
import org.togetherjava.tjbot.features.analytics.Metrics;
import org.togetherjava.tjbot.features.system.BotCore;
import org.togetherjava.tjbot.logging.LogMarkers;
import org.togetherjava.tjbot.logging.discord.DiscordLogging;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.SQLException;
/**
* Main class of the application. Use {@link #main(String[])} to start an instance of it.
* <p>
* New commands can be created by implementing {@link SlashCommandInteractionEvent} or extending
* {@link SlashCommandAdapter}. They can then be registered in {@link Features}.
*/
public class Application {
private Application() {
throw new UnsupportedOperationException("Utility class, construction not supported");
}
private static final Logger logger = LoggerFactory.getLogger(Application.class);
private static final String DEFAULT_CONFIG_PATH = "config.json";
/**
* Starts the application.
*
* @param args command line arguments - [the path to the configuration file (optional, by
* default "config.json")]
*/
public static void main(final String[] args) {
if (args.length > 1) {
throw new IllegalArgumentException("Expected no or one argument but " + args.length
+ " arguments were provided. The first argument is the path to the configuration file. If no argument was provided, '"
+ DEFAULT_CONFIG_PATH + "' will be assumed.");
}
Path configPath = Path.of(args.length == 1 ? args[0] : DEFAULT_CONFIG_PATH);
Config config;
try {
config = Config.load(configPath);
} catch (IOException e) {
logger.error("Unable to load the configuration file from path '{}'",
configPath.toAbsolutePath(), e);
return;
}
Thread.setDefaultUncaughtExceptionHandler(Application::onUncaughtException);
Runtime.getRuntime().addShutdownHook(new Thread(Application::onShutdown));
DiscordLogging.startDiscordLogging(config);
runBot(config);
}
/**
* Runs an instance of the bot, connecting to the given token and using the given database.
*
* @param config the configuration to run the bot with
*/
@SuppressWarnings("WeakerAccess")
public static void runBot(Config config) {
logger.info("Starting bot...");
Path databasePath = Path.of(config.getDatabasePath());
try {
Path parentDatabasePath = databasePath.toAbsolutePath().getParent();
if (parentDatabasePath != null) {
Files.createDirectories(parentDatabasePath);
}
Database database = new Database("jdbc:sqlite:" + databasePath.toAbsolutePath());
Metrics metrics = new Metrics(database);
JDA jda = JDABuilder.createDefault(config.getToken())
.enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.MESSAGE_CONTENT)
.build();
jda.awaitReady();
BotCore core = new BotCore(jda, database, config, metrics);
CommandReloading.reloadCommands(jda, core);
core.scheduleRoutines(jda);
jda.addEventListener(core);
logger.info("Bot is ready");
} catch (InvalidTokenException e) {
logger.error(LogMarkers.SENSITIVE, "Failed to login", e);
} catch (InterruptedException e) {
logger.error("Interrupted while waiting for setup to complete", e);
Thread.currentThread().interrupt();
} catch (SQLException e) {
logger.error("Failed to create database", e);
} catch (IOException e) {
logger.error("Failed to create path to the database at: {}",
databasePath.toAbsolutePath(), e);
}
}
private static void onShutdown() {
// This may be called during JVM shutdown via a hook and hence only has minimal time to
// react.
// There is no guarantee that this method can be executed fully - it should run as
// fast as possible and only do the minimal necessary actions.
logger.info("Bot has been stopped");
}
private static void onUncaughtException(Thread failingThread, Throwable failure) {
logger.error("Unknown error in thread {}.", failingThread.getName(), failure);
}
}