initial bot and in-memory storage

This commit is contained in:
2025-07-07 19:47:52 +02:00
commit ecc9d54c3c
12 changed files with 347 additions and 0 deletions
@@ -0,0 +1,28 @@
package me.youhavetrouble.inviter;
public record DiscordInvite(
String code,
Long guildId,
Long expiresAt
) {
public DiscordInvite {
if (code == null) {
throw new IllegalArgumentException("Code cannot be null");
}
if (guildId == null || guildId <= 0) {
throw new IllegalArgumentException("Guild ID must not be null nor be a negative number");
}
}
/**
* Checks if the invite is expired.
* The invite is considered expired if the current time is more than 5 seconds before the expiration time.
*
* @return true if the invite is expired, false otherwise
*/
public boolean isExpired() {
return System.currentTimeMillis() + 5000 > expiresAt;
}
}
@@ -0,0 +1,49 @@
package me.youhavetrouble.inviter;
import me.youhavetrouble.inviter.storage.MemoryStorage;
import me.youhavetrouble.inviter.storage.Storage;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.requests.GatewayIntent;
import net.dv8tion.jda.api.utils.cache.CacheFlag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Set;
public class Main {
private static final Logger LOGGER = LoggerFactory.getLogger("Inviter");
private static JDA jda;
private static Storage storage;
public static void main(String[] args) throws InterruptedException {
String token = System.getenv("DISCORD_TOKEN");
jda = JDABuilder.create(
token,
Set.of(GatewayIntent.GUILD_INVITES)
)
.disableCache(
CacheFlag.ACTIVITY,
CacheFlag.VOICE_STATE,
CacheFlag.EMOJI,
CacheFlag.STICKER,
CacheFlag.CLIENT_STATUS,
CacheFlag.ONLINE_STATUS,
CacheFlag.SCHEDULED_EVENTS
)
.build();
jda.awaitReady();
storage = new MemoryStorage(jda);
LOGGER.info("Welcome to the Inviter Application!");
}
}
@@ -0,0 +1,75 @@
package me.youhavetrouble.inviter.storage;
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 {
private final Cache<String, DiscordInvite> cache = Caffeine.newBuilder()
.expireAfterWrite(Duration.of(60, ChronoUnit.SECONDS))
.build();
private final JDA jda;
public MemoryStorage(JDA jda) {
this.jda = jda;
}
@Nullable
@Override
public DiscordInvite getInvite(long guildId) {
DiscordInvite discordInvite = cache.getIfPresent(String.valueOf(guildId));
if (discordInvite == null || discordInvite.isExpired()) {
Guild guild = jda.getGuildById(guildId);
if (guild == null) {
return null; // Guild not found
}
DefaultGuildChannelUnion defaultChannel = guild.getDefaultChannel();
if (defaultChannel == null) {
return null; // No default channel found
}
Invite invite = defaultChannel.createInvite()
.setMaxAge(60) // Set the invite to expire after 60 seconds
.complete();
if (invite == null) return null; // Failed to create invite
discordInvite = new DiscordInvite(
invite.getCode(),
guild.getIdLong(),
invite.getTimeCreated().toEpochSecond()
);
}
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,19 @@
package me.youhavetrouble.inviter.storage;
import me.youhavetrouble.inviter.DiscordInvite;
import net.dv8tion.jda.api.entities.Invite;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface Storage {
@Nullable DiscordInvite getInvite(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);
}
+30
View File
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration name="Console">
<Properties>
<Property name="LOG_PATTERN">[%d{yyyy-MM-dd HH:mm:ss}] [%t/%p]: %msg%n</Property>
</Properties>
<Appenders>
<Console name="ConsoleTerminal" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%p]: %msg%n"/>
</Console>
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz" immediateFlush="false">
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] [%t/%p]: %msg%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<OnStartupTriggeringPolicy/>
</Policies>
</RollingRandomAccessFile>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="ConsoleTerminal"/>
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>