Skip to content
Draft
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,5 @@
}
}
}
},
"postCreateCommand": {
"config": "cp application/config.json.template application/config.json"
}
}
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ gradle-app.setting

# End of https://www.toptal.com/developers/gitignore/api/netbeans,intellij,java,gradle,eclipse
application/db/
config.json
secrets.json
application/config.json
*.db
*.db-shm
Expand Down
9 changes: 9 additions & 0 deletions application/secrets.json.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"token": "<put_your_token_here>",
"githubApiKey": "<your_github_personal_access_token>",
"logInfoChannelWebhook": "<put_your_webhook_here>",
"logErrorChannelWebhook": "<put_your_webhook_here>",
"openaiApiKey": "<check pins in #tjbot_discussion for the key>",
"jshellBaseUrl": "<put_jshell_rest_api_url_here>",
"wolframAlphaAppId": "79J52T-6239TVXHR7"
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
import org.togetherjava.tjbot.features.system.BotCore;
import org.togetherjava.tjbot.logging.LogMarkers;
import org.togetherjava.tjbot.logging.discord.DiscordLogging;
import org.togetherjava.tjbot.secrets.Secrets;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.SQLException;
Expand All @@ -33,7 +36,8 @@ private Application() {
}

private static final Logger logger = LoggerFactory.getLogger(Application.class);
private static final String DEFAULT_CONFIG_PATH = "config.json";
private static final String DEFAULT_CONFIG_PATH = "/config.json";
private static final String DEFAULT_SECRETS_PATH = "secrets.json";

/**
* Starts the application.
Expand All @@ -48,30 +52,46 @@ public static void main(final String[] args) {
+ DEFAULT_CONFIG_PATH + "' will be assumed.");
}

Path configPath = Path.of(args.length == 1 ? args[0] : DEFAULT_CONFIG_PATH);
String configPath = args.length == 1 ? args[0] : DEFAULT_CONFIG_PATH;
Config config;

try (InputStream stream = Application.class.getResourceAsStream(configPath)) {
if (stream == null) {
throw new IOException("InputStream is null when loading " + configPath);
}

config = Config.load(new String(stream.readAllBytes(), StandardCharsets.UTF_8));

} catch (IOException e) {
logger.error("Unable to load the configuration file from path '{}'", configPath, e);
return;
}

Path secretsPath = Path.of(args.length == 1 ? args[0] : DEFAULT_SECRETS_PATH);
Secrets secrets;
try {
config = Config.load(configPath);
secrets = Secrets.load(secretsPath);
} catch (IOException e) {
logger.error("Unable to load the configuration file from path '{}'",
configPath.toAbsolutePath(), e);
secretsPath.toAbsolutePath(), e);
return;
}

Thread.setDefaultUncaughtExceptionHandler(Application::onUncaughtException);
Runtime.getRuntime().addShutdownHook(new Thread(Application::onShutdown));
DiscordLogging.startDiscordLogging(config);
DiscordLogging.startDiscordLogging(config, secrets);

runBot(config);
runBot(config, secrets);
}

/**
* 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
* @param secrets the secrets to run the bot with
*/
@SuppressWarnings("WeakerAccess")
public static void runBot(Config config) {
public static void runBot(Config config, Secrets secrets) {
logger.info("Starting bot...");

Path databasePath = Path.of(config.getDatabasePath());
Expand All @@ -82,13 +102,13 @@ public static void runBot(Config config) {
}
Database database = new Database("jdbc:sqlite:" + databasePath.toAbsolutePath());

JDA jda = JDABuilder.createDefault(config.getToken())
JDA jda = JDABuilder.createDefault(secrets.getToken())
.enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.MESSAGE_CONTENT)
.build();

jda.awaitReady();

BotCore core = new BotCore(jda, database, config);
BotCore core = new BotCore(jda, database, config, secrets);
CommandReloading.reloadCommands(jda, core);
core.scheduleRoutines(jda);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,15 @@
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import java.io.IOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Objects;


/**
* Configuration of the application. Create instances using {@link #load(Path)}.
* Configuration of the application. Create instances using {@link #load(String)}.
*/
public final class Config {
private final String token;
private final String githubApiKey;
private final String databasePath;
private final String projectWebsite;
private final String discordGuildInvite;
Expand All @@ -32,15 +29,11 @@ public final class Config {
private final SuggestionsConfig suggestions;
private final String quarantinedRolePattern;
private final ScamBlockerConfig scamBlocker;
private final String wolframAlphaAppId;
private final HelpSystemConfig helpSystem;
private final List<String> blacklistedFileExtension;
private final String mediaOnlyChannelPattern;
private final String logInfoChannelWebhook;
private final String logErrorChannelWebhook;
private final String githubReferencingEnabledChannelPattern;
private final List<Long> githubRepositories;
private final String openaiApiKey;
private final String sourceCodeBaseUrl;
private final JShellConfig jshell;
private final HelperPruneConfig helperPruneConfig;
Expand All @@ -52,9 +45,7 @@ public final class Config {

@SuppressWarnings("ConstructorWithTooManyParameters")
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
private Config(@JsonProperty(value = "token", required = true) String token,
@JsonProperty(value = "githubApiKey", required = true) String githubApiKey,
@JsonProperty(value = "databasePath", required = true) String databasePath,
private Config(@JsonProperty(value = "databasePath", required = true) String databasePath,
@JsonProperty(value = "projectWebsite", required = true) String projectWebsite,
@JsonProperty(value = "discordGuildInvite", required = true) String discordGuildInvite,
@JsonProperty(value = "modAuditLogChannelPattern",
Expand All @@ -76,21 +67,15 @@ private Config(@JsonProperty(value = "token", required = true) String token,
@JsonProperty(value = "quarantinedRolePattern",
required = true) String quarantinedRolePattern,
@JsonProperty(value = "scamBlocker", required = true) ScamBlockerConfig scamBlocker,
@JsonProperty(value = "wolframAlphaAppId", required = true) String wolframAlphaAppId,
@JsonProperty(value = "helpSystem", required = true) HelpSystemConfig helpSystem,
@JsonProperty(value = "mediaOnlyChannelPattern",
required = true) String mediaOnlyChannelPattern,
@JsonProperty(value = "blacklistedFileExtension",
required = true) List<String> blacklistedFileExtension,
@JsonProperty(value = "logInfoChannelWebhook",
required = true) String logInfoChannelWebhook,
@JsonProperty(value = "logErrorChannelWebhook",
required = true) String logErrorChannelWebhook,
@JsonProperty(value = "githubReferencingEnabledChannelPattern",
required = true) String githubReferencingEnabledChannelPattern,
@JsonProperty(value = "githubRepositories",
required = true) List<Long> githubRepositories,
@JsonProperty(value = "openaiApiKey", required = true) String openaiApiKey,
@JsonProperty(value = "sourceCodeBaseUrl", required = true) String sourceCodeBaseUrl,
@JsonProperty(value = "jshell", required = true) JShellConfig jshell,
@JsonProperty(value = "memberCountCategoryPattern",
Expand All @@ -103,8 +88,6 @@ private Config(@JsonProperty(value = "token", required = true) String token,
@JsonProperty(value = "selectRolesChannelPattern",
required = true) String selectRolesChannelPattern,
@JsonProperty(value = "topHelpers", required = true) TopHelpersConfig topHelpers) {
this.token = Objects.requireNonNull(token);
this.githubApiKey = Objects.requireNonNull(githubApiKey);
this.databasePath = Objects.requireNonNull(databasePath);
this.projectWebsite = Objects.requireNonNull(projectWebsite);
this.memberCountCategoryPattern = Objects.requireNonNull(memberCountCategoryPattern);
Expand All @@ -121,16 +104,12 @@ private Config(@JsonProperty(value = "token", required = true) String token,
this.suggestions = Objects.requireNonNull(suggestions);
this.quarantinedRolePattern = Objects.requireNonNull(quarantinedRolePattern);
this.scamBlocker = Objects.requireNonNull(scamBlocker);
this.wolframAlphaAppId = Objects.requireNonNull(wolframAlphaAppId);
this.helpSystem = Objects.requireNonNull(helpSystem);
this.mediaOnlyChannelPattern = Objects.requireNonNull(mediaOnlyChannelPattern);
this.blacklistedFileExtension = Objects.requireNonNull(blacklistedFileExtension);
this.logInfoChannelWebhook = Objects.requireNonNull(logInfoChannelWebhook);
this.logErrorChannelWebhook = Objects.requireNonNull(logErrorChannelWebhook);
this.githubReferencingEnabledChannelPattern =
Objects.requireNonNull(githubReferencingEnabledChannelPattern);
this.githubRepositories = Objects.requireNonNull(githubRepositories);
this.openaiApiKey = Objects.requireNonNull(openaiApiKey);
this.sourceCodeBaseUrl = Objects.requireNonNull(sourceCodeBaseUrl);
this.jshell = Objects.requireNonNull(jshell);
this.helperPruneConfig = Objects.requireNonNull(helperPruneConfig);
Expand All @@ -143,13 +122,13 @@ private Config(@JsonProperty(value = "token", required = true) String token,
/**
* Loads the configuration from the given file.
*
* @param path the configuration file, as JSON object
* @param content the configuration file, as Stringified JSON object
* @return the loaded configuration
* @throws IOException if the file could not be loaded
*/
public static Config load(Path path) throws IOException {
public static Config load(String content) throws IOException {
return new ObjectMapper().registerModule(new JavaTimeModule())
.readValue(path.toFile(), Config.class);
.readValue(content, Config.class);
}

/**
Expand Down Expand Up @@ -191,27 +170,6 @@ public String getProjectsChannelPattern() {
return projectsChannelPattern;
}

/**
* Gets the token of the Discord bot to connect this application to.
*
* @return the Discord bot token
*/
public String getToken() {
return token;
}

/**
* Gets the API Key of GitHub.
*
* @return the API Key
* @see <a href=
* "https://docs.github.com/en/enterprise-server@3.4/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token">Create
* a GitHub key</a>
*/
public String getGitHubApiKey() {
return githubApiKey;
}

/**
* Gets the path where the database of the application is located at.
*
Expand Down Expand Up @@ -306,15 +264,6 @@ public ScamBlockerConfig getScamBlocker() {
return scamBlocker;
}

/**
* Gets the application ID used to connect to the WolframAlpha API.
*
* @return the application ID for the WolframAlpha API
*/
public String getWolframAlphaAppId() {
return wolframAlphaAppId;
}

/**
* Gets the config for the help system.
*
Expand Down Expand Up @@ -356,33 +305,6 @@ public List<Long> getGitHubRepositories() {
return githubRepositories;
}

/**
* The Discord channel webhook for posting log messages with levels INFO, DEBUG and TRACE.
*
* @return the webhook URL
*/
public String getLogInfoChannelWebhook() {
return logInfoChannelWebhook;
}

/**
* The Discord channel webhook for posting log messages with levels FATAL, ERROR and WARNING.
*
* @return the webhook URL
*/
public String getLogErrorChannelWebhook() {
return logErrorChannelWebhook;
}

/**
* The OpenAI token needed for communicating with OpenAI ChatGPT.
*
* @return the OpenAI API Token
*/
public String getOpenaiApiKey() {
return openaiApiKey;
}

/**
* The base URL of the source code of this bot. E.g.
* {@code getSourceCodeBaseUrl() + "/org/togetherjava/tjbot/config/Config.java"} would point to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,25 @@

import org.togetherjava.tjbot.features.utils.RateLimiter;

import java.util.Objects;

/**
* JShell config.
*
* @param baseUrl the base url of the JShell REST API
*
* @param rateLimitWindowSeconds the number of seconds of the {@link RateLimiter rate limiter} for
* jshell commands and code actions
* @param rateLimitRequestsInWindow the number of requests of the {@link RateLimiter rate limiter}
* for jshell commands and code actions
*/
public record JShellConfig(String baseUrl, int rateLimitWindowSeconds,
int rateLimitRequestsInWindow) {
public record JShellConfig(int rateLimitWindowSeconds, int rateLimitRequestsInWindow) {
/**
* Creates a JShell config.
*
* @param baseUrl the base url of the JShell REST API, must be not null
* @param rateLimitWindowSeconds the number of seconds of the {@link RateLimiter rate limiter}
* for jshell commands and code actions, must be higher than 0
* @param rateLimitRequestsInWindow the number of requests of the {@link RateLimiter rate
* limiter} for jshell commands and code actions, must be higher than 0
*/
public JShellConfig {
Objects.requireNonNull(baseUrl);
if (rateLimitWindowSeconds < 0) {
throw new IllegalArgumentException(
"Illegal rateLimitWindowSeconds : " + rateLimitWindowSeconds);
Expand Down
Loading
Loading