initial bot and in-memory storage
This commit is contained in:
+39
@@ -0,0 +1,39 @@
|
|||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
logs/
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea/modules.xml
|
||||||
|
.idea/jarRepositories.xml
|
||||||
|
.idea/compiler.xml
|
||||||
|
.idea/libraries/
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### Eclipse ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
### Mac OS ###
|
||||||
|
.DS_Store
|
||||||
Generated
+10
@@ -0,0 +1,10 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Environment-dependent path to Maven home directory
|
||||||
|
/mavenHomeManager.xml
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
Generated
+7
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding">
|
||||||
|
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+14
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
|
<component name="MavenProjectsManager">
|
||||||
|
<option name="originalFiles">
|
||||||
|
<list>
|
||||||
|
<option value="$PROJECT_DIR$/pom.xml" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="openjdk-21" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>me.youhavetrouble.inviter</groupId>
|
||||||
|
<artifactId>Inviter</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-core</artifactId>
|
||||||
|
<version>2.23.1</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-api</artifactId>
|
||||||
|
<version>2.23.1</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-slf4j2-impl</artifactId>
|
||||||
|
<version>2.23.1</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||||
|
<artifactId>caffeine</artifactId>
|
||||||
|
<version>3.1.8</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xerial</groupId>
|
||||||
|
<artifactId>sqlite-jdbc</artifactId>
|
||||||
|
<version>3.46.1.2</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.zaxxer</groupId>
|
||||||
|
<artifactId>HikariCP</artifactId>
|
||||||
|
<version>5.1.0</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.dv8tion</groupId>
|
||||||
|
<artifactId>JDA</artifactId>
|
||||||
|
<version>5.6.1</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>club.minnced</groupId>
|
||||||
|
<artifactId>opus-java</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Inviter
|
||||||
|
|
||||||
|
Discord bot that allows users to set up personalized invite links for their servers and have rotating invite codes
|
||||||
@@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
Reference in New Issue
Block a user