refactors and persistent server settings
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
package me.youhavetrouble.inviter;
|
||||
|
||||
import me.youhavetrouble.inviter.http.ApiServer;
|
||||
import me.youhavetrouble.inviter.storage.MemoryStorage;
|
||||
import me.youhavetrouble.inviter.discord.DiscordInviteManager;
|
||||
import me.youhavetrouble.inviter.storage.SqliteStorage;
|
||||
import me.youhavetrouble.inviter.storage.Storage;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.JDABuilder;
|
||||
@@ -18,8 +19,9 @@ public class Main {
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger("Inviter");
|
||||
|
||||
private static JDA jda;
|
||||
private static Storage storage;
|
||||
private static DiscordInviteManager discordInviteManager;
|
||||
private static ApiServer apiServer;
|
||||
private static Storage storage;
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
|
||||
@@ -69,6 +71,8 @@ public class Main {
|
||||
}
|
||||
}
|
||||
|
||||
storage = new SqliteStorage();
|
||||
|
||||
jda = JDABuilder.create(
|
||||
token,
|
||||
Set.of(GatewayIntent.GUILD_INVITES)
|
||||
@@ -86,7 +90,10 @@ public class Main {
|
||||
|
||||
jda.awaitReady();
|
||||
|
||||
storage = new MemoryStorage(jda);
|
||||
jda.getGuilds().parallelStream().forEach(guild -> storage.saveDefaultGuildSettings(guild.getIdLong()));
|
||||
// TODO make sure to save default settings for guilds bot joins on runtime
|
||||
|
||||
discordInviteManager = new DiscordInviteManager(jda);
|
||||
|
||||
try {
|
||||
apiServer = new ApiServer(hostname, port);
|
||||
@@ -98,8 +105,8 @@ public class Main {
|
||||
LOGGER.info("Welcome to the Inviter Application!");
|
||||
}
|
||||
|
||||
public static Storage getStorage() {
|
||||
return storage;
|
||||
public static DiscordInviteManager getDiscordInviteMenager() {
|
||||
return discordInviteManager;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package me.youhavetrouble.inviter;
|
||||
package me.youhavetrouble.inviter.discord;
|
||||
|
||||
public record DiscordInvite(
|
||||
String code,
|
||||
+3
-27
@@ -1,19 +1,17 @@
|
||||
package me.youhavetrouble.inviter.storage;
|
||||
package me.youhavetrouble.inviter.discord;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import me.youhavetrouble.inviter.DiscordInvite;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Invite;
|
||||
import net.dv8tion.jda.api.entities.channel.unions.DefaultGuildChannelUnion;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
public class MemoryStorage implements Storage {
|
||||
public class DiscordInviteManager {
|
||||
|
||||
private final Cache<String, DiscordInvite> cache = Caffeine.newBuilder()
|
||||
.expireAfterWrite(Duration.of(60, ChronoUnit.SECONDS))
|
||||
@@ -21,13 +19,11 @@ public class MemoryStorage implements Storage {
|
||||
|
||||
private final JDA jda;
|
||||
|
||||
public MemoryStorage(JDA jda) {
|
||||
public DiscordInviteManager(JDA jda) {
|
||||
this.jda = jda;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public DiscordInvite getInvite(long guildId) {
|
||||
DiscordInvite discordInvite = cache.getIfPresent(String.valueOf(guildId));
|
||||
if (discordInvite == null || discordInvite.isExpired()) {
|
||||
@@ -52,24 +48,4 @@ public class MemoryStorage implements Storage {
|
||||
return discordInvite;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DiscordInvite saveInvite(Invite invite) {
|
||||
|
||||
if (invite == null) {
|
||||
throw new IllegalArgumentException("Invite cannot be null");
|
||||
}
|
||||
if (invite.getGuild() == null) {
|
||||
throw new IllegalArgumentException("Invite must be associated with a guild");
|
||||
}
|
||||
|
||||
DiscordInvite discordInvite = new DiscordInvite(
|
||||
invite.getCode(),
|
||||
invite.getGuild().getIdLong(),
|
||||
invite.getTimeCreated().toEpochSecond()
|
||||
);
|
||||
|
||||
cache.put(invite.getGuild().getId(), discordInvite);
|
||||
return discordInvite;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package me.youhavetrouble.inviter.discord;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public record GuildSettings(
|
||||
boolean apiEnabled,
|
||||
@Nullable String apiHostname
|
||||
) {
|
||||
|
||||
}
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
package me.youhavetrouble.inviter.http.endpoints;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import me.youhavetrouble.inviter.DiscordInvite;
|
||||
import me.youhavetrouble.inviter.discord.DiscordInvite;
|
||||
import me.youhavetrouble.inviter.Main;
|
||||
import me.youhavetrouble.inviter.storage.Storage;
|
||||
import me.youhavetrouble.inviter.discord.DiscordInviteManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -38,7 +38,7 @@ public class GetDiscordInviteByGuildId implements EndpointHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
Storage storage = Main.getStorage();
|
||||
DiscordInviteManager storage = Main.getDiscordInviteMenager();
|
||||
DiscordInvite invite = storage.getInvite(guildIdLong);
|
||||
|
||||
if (invite == null) {
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
package me.youhavetrouble.inviter.storage;
|
||||
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import me.youhavetrouble.inviter.discord.GuildSettings;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.File;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class SqliteStorage implements Storage {
|
||||
|
||||
private final DataSource dataSource;
|
||||
|
||||
public SqliteStorage() {
|
||||
File dataFolder = new File("data");
|
||||
if (!dataFolder.exists()) {
|
||||
if (!dataFolder.mkdirs()) {
|
||||
throw new RuntimeException("Failed to create data folder");
|
||||
}
|
||||
}
|
||||
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setPoolName("DataSQLitePool");
|
||||
config.setDriverClassName("org.sqlite.JDBC");
|
||||
config.setJdbcUrl("jdbc:sqlite:data/data.db");
|
||||
config.setConnectionTestQuery("PRAGMA journal_mode=WAL;");
|
||||
config.setMaxLifetime(60000); // 60 Sec
|
||||
config.setMaximumPoolSize(Math.min(4, Runtime.getRuntime().availableProcessors() / 4));
|
||||
dataSource = new HikariDataSource(config);
|
||||
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
// Initialize the database schema if necessary
|
||||
// For example, you might want to create a table for guild settings
|
||||
connection.createStatement().execute("""
|
||||
CREATE TABLE IF NOT EXISTS guild_settings (
|
||||
guild_id LONG PRIMARY KEY,
|
||||
api_enabled BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
api_hostname VARCHAR(256) DEFAULT NULL
|
||||
);
|
||||
"""
|
||||
);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("Failed to initialize database", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GuildSettings getGuildSettings(long guildId) {
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
var statement = connection.prepareStatement(
|
||||
"SELECT * FROM guild_settings WHERE guild_id = ?"
|
||||
);
|
||||
statement.setLong(1, guildId);
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
|
||||
if (resultSet.next()) {
|
||||
boolean apiEnabled = resultSet.getBoolean("api_enabled");
|
||||
String apiHostname = resultSet.getString("api_hostname");
|
||||
return new GuildSettings(apiEnabled, apiHostname);
|
||||
}
|
||||
return new GuildSettings(false, null);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("Failed to retrieve guild settings", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveDefaultGuildSettings(long guildId) {
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
var statement = connection.prepareStatement(
|
||||
"INSERT OR IGNORE INTO guild_settings (guild_id) VALUES (?)"
|
||||
);
|
||||
statement.setLong(1, guildId);
|
||||
statement.executeUpdate();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to save default guild settings", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDiscordApiEnabled(long guildId, boolean enabled) {
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
var statement = connection.prepareStatement(
|
||||
"UPDATE guild_settings SET api_enabled = ? WHERE guild_id = ?"
|
||||
);
|
||||
statement.setBoolean(1, enabled);
|
||||
statement.setLong(2, guildId);
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("Failed to update Discord API enabled status", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDiscordApiHostname(long guildId, @Nullable String hostname) {
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
var statement = connection.prepareStatement(
|
||||
"UPDATE guild_settings SET api_hostname = ? WHERE guild_id = ?"
|
||||
);
|
||||
if (hostname == null || hostname.isEmpty()) {
|
||||
statement.setNull(1, java.sql.Types.VARCHAR);
|
||||
} else {
|
||||
statement.setString(1, hostname);
|
||||
}
|
||||
statement.setLong(2, guildId);
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("Failed to update Discord API hostname", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,18 @@
|
||||
package me.youhavetrouble.inviter.storage;
|
||||
|
||||
import me.youhavetrouble.inviter.DiscordInvite;
|
||||
import net.dv8tion.jda.api.entities.Invite;
|
||||
|
||||
import me.youhavetrouble.inviter.discord.GuildSettings;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface Storage {
|
||||
|
||||
@Nullable DiscordInvite getInvite(long guildId);
|
||||
@NotNull GuildSettings getGuildSettings(long guildId);
|
||||
|
||||
/**
|
||||
* Saves the invite to the storage and returns the saved invite.
|
||||
* @param invite JDA invite object to save
|
||||
* @return the saved DiscordInvite object
|
||||
*/
|
||||
@NotNull DiscordInvite saveInvite(Invite invite);
|
||||
void saveDefaultGuildSettings(long guildId);
|
||||
|
||||
void updateDiscordApiEnabled(long guildId, boolean enabled);
|
||||
|
||||
void updateDiscordApiHostname(long guildId, @Nullable String hostname);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user