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