diff --git a/pom.xml b/pom.xml
index 70c62a2..a822342 100644
--- a/pom.xml
+++ b/pom.xml
@@ -88,6 +88,23 @@
+
+ org.xerial
+ sqlite-jdbc
+ 3.46.0.0
+ compile
+
+
+ com.zaxxer
+ HikariCP
+ 5.1.0
+ compile
+
+
+ com.github.ben-manes.caffeine
+ caffeine
+ 3.1.8
+
\ No newline at end of file
diff --git a/src/main/java/me/youhavetrouble/noted/Main.java b/src/main/java/me/youhavetrouble/noted/Main.java
index d912981..d87c346 100644
--- a/src/main/java/me/youhavetrouble/noted/Main.java
+++ b/src/main/java/me/youhavetrouble/noted/Main.java
@@ -13,12 +13,15 @@ import java.io.*;
import java.util.Collections;
import java.util.Properties;
import java.util.concurrent.Executors;
+import java.util.logging.Logger;
public class Main {
+ private static final Logger logger = Logger.getLogger("Main");
private static final Properties properties = new Properties();
private static String version = "Unknown version";
+ private static Storage storage;
public static JDA jda;
public static void main(String[] args) throws InterruptedException {
@@ -28,13 +31,17 @@ public class Main {
if (resource != null) {
version = new String(resource.readAllBytes());
} else {
- System.err.println("Version file missing.");
+ logger.severe("Version file missing.");
}
} catch (IOException e) {
throw new RuntimeException(e);
}
- System.out.println("Starting " + version);
+ storage = new Storage();
+
+ Runtime.getRuntime().addShutdownHook(new Thread(Main::shutdown));
+
+ logger.info("Starting " + version);
jda = JDABuilder.createLight(properties.getProperty("DISCORD_TOKEN"), Collections.emptyList())
.setCallbackPool(Executors.newVirtualThreadPerTaskExecutor())
@@ -73,7 +80,7 @@ public class Main {
try (InputStream resource = Main.class.getClassLoader().getResourceAsStream("noted.properites");
OutputStream outputStream = new FileOutputStream(file)) {
if (resource == null) {
- System.err.println("Default noted.properties missing.");
+ logger.severe("Default noted.properties missing.");
return;
}
outputStream.write(resource.readAllBytes());
@@ -86,4 +93,9 @@ public class Main {
return version;
}
+ private static void shutdown() {
+ jda.shutdown();
+ storage.shutdown();
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/me/youhavetrouble/noted/SlashCommandListener.java b/src/main/java/me/youhavetrouble/noted/SlashCommandListener.java
index af330e0..ed60b44 100644
--- a/src/main/java/me/youhavetrouble/noted/SlashCommandListener.java
+++ b/src/main/java/me/youhavetrouble/noted/SlashCommandListener.java
@@ -4,7 +4,6 @@ import me.youhavetrouble.noted.note.Note;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
-import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
public class SlashCommandListener extends ListenerAdapter {
@@ -15,35 +14,42 @@ public class SlashCommandListener extends ListenerAdapter {
OptionMapping noteIdOption = event.getOption("note-id");
OptionMapping ephemeralOption = event.getOption("ephemeral");
if (noteIdOption == null) {
- event.reply("Please provide a note ID.").setEphemeral(true).queue();
+ event.reply("Please provide a note ID.")
+ .setEphemeral(true)
+ .queue();
return;
}
- Note note = new Note(
- "Sample Note Title",
- null,
- "Bottom text",
- null,
- null,
- null,
- null,
- null,
- null,
- null
- );
- ReplyCallbackAction action = event.replyEmbeds(note.toEmbed());
- if (ephemeralOption != null && ephemeralOption.getAsBoolean()) {
- action = action.setEphemeral(true);
+ boolean ephemeral;
+ try {
+ ephemeral = ephemeralOption != null && ephemeralOption.getAsBoolean();
+ } catch (IllegalArgumentException e) {
+ event.reply("Invalid value for ephemeral.")
+ .setEphemeral(true)
+ .queue();
+ return;
}
- action.queue();
-
+ String noteId = noteIdOption.getAsString();
+ getNote(event, noteId, ephemeral);
}
- default -> {
- event.reply("Unknown command.").setEphemeral(true).queue();
- return;
- }
+ default -> event.reply("Unknown command.")
+ .setEphemeral(true)
+ .queue();
}
}
+ private void getNote(SlashCommandInteractionEvent event, String noteId, boolean ephemeral) {
+ Note note = Note.cache.getIfPresent(noteId);
+ if (note == null) {
+ event.reply("Note with ID %s not found.".formatted(noteId))
+ .setEphemeral(true)
+ .queue();
+ return;
+ }
+ event.replyEmbeds(note.toEmbed())
+ .setEphemeral(ephemeral)
+ .queue();
+ }
+
}
diff --git a/src/main/java/me/youhavetrouble/noted/Storage.java b/src/main/java/me/youhavetrouble/noted/Storage.java
new file mode 100644
index 0000000..1a65bf8
--- /dev/null
+++ b/src/main/java/me/youhavetrouble/noted/Storage.java
@@ -0,0 +1,80 @@
+package me.youhavetrouble.noted;
+
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+
+import javax.sql.DataSource;
+import java.io.File;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.logging.Logger;
+
+
+
+public class Storage {
+
+ private final Logger logger = Logger.getLogger("Storage");
+
+ private final DataSource dataSource;
+
+ public Storage() {
+ File dataFolder = new File("data");
+ if (!dataFolder.exists()) {
+ if (!dataFolder.mkdir()) {
+ 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("SELECT 1");
+ config.setMaxLifetime(60000); // 60 Sec
+ config.setMaximumPoolSize(Math.min(1, Runtime.getRuntime().availableProcessors() / 4));
+ dataSource = new HikariDataSource(config);
+
+ try (Connection connection = dataSource.getConnection()) {
+ connection.createStatement().execute("PRAGMA journal_mode=WAL;");
+ } catch (SQLException e) {
+ logger.warning("Failed to set journal mode to WAL");
+ }
+
+ createTables();
+
+ }
+
+ protected void shutdown() {
+ if (dataSource instanceof HikariDataSource) {
+ ((HikariDataSource) dataSource).close();
+ }
+ }
+
+ private void createTables() {
+ try (Connection connection = dataSource.getConnection()) {
+ connection.createStatement().execute("""
+ CREATE TABLE IF NOT EXISTS notes (
+ id VARCHAR(36) NOT NULL PRIMARY KEY,
+ title VARCHAR(256),
+ title_url VARCHAR(2000),
+ description VARCHAR(4096),
+ image_url VARCHAR(2000),
+ thumbnail_url VARCHAR(2000),
+ color INTEGER,
+ author VARCHAR(256),
+ author_url VARCHAR(2000),
+ footer VARCHAR(256),
+ footer_url VARCHAR(2000)
+ )
+ """);
+ connection.createStatement().execute("""
+ CREATE TABLE IF NOT EXISTS aliases (
+ alias VARCHAR(256) NOT NULL UNIQUE PRIMARY KEY,
+ note_id VARCHAR(36) NOT NULL
+ )
+ """);
+ } catch (SQLException e) {
+ logger.warning("Failed to create tables");
+ }
+ }
+
+}
diff --git a/src/main/java/me/youhavetrouble/noted/note/Note.java b/src/main/java/me/youhavetrouble/noted/note/Note.java
index bd7a874..889beaf 100644
--- a/src/main/java/me/youhavetrouble/noted/note/Note.java
+++ b/src/main/java/me/youhavetrouble/noted/note/Note.java
@@ -1,23 +1,56 @@
package me.youhavetrouble.noted.note;
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.MessageEmbed;
+
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.Color;
+import java.time.Duration;
-public record Note(
- @NotNull String title,
- @Nullable String titleUrl,
- @NotNull String content,
- @Nullable String imageUrl,
- @Nullable String thumbnailUrl,
- @Nullable Color color,
- @Nullable String author,
- @Nullable String authorUrl,
- @Nullable String footer,
- @Nullable String footerUrl
- ) {
+public class Note {
+
+ public static final Cache cache = Caffeine.newBuilder()
+ .maximumSize(100)
+ .expireAfterWrite(Duration.ofMinutes(1))
+ .build();
+
+ public final String title;
+ public final String titleUrl;
+ public final String content;
+ public final String imageUrl;
+ public final String thumbnailUrl;
+ public final Color color;
+ public final String author;
+ public final String authorUrl;
+ public final String footer;
+ public final String footerUrl;
+
+ private Note(
+ @NotNull String title,
+ @Nullable String titleUrl,
+ @NotNull String content,
+ @Nullable String imageUrl,
+ @Nullable String thumbnailUrl,
+ @Nullable Color color,
+ @Nullable String author,
+ @Nullable String authorUrl,
+ @Nullable String footer,
+ @Nullable String footerUrl
+ ) {
+ this.title = title;
+ this.titleUrl = titleUrl;
+ this.content = content;
+ this.imageUrl = imageUrl;
+ this.thumbnailUrl = thumbnailUrl;
+ this.color = color;
+ this.author = author;
+ this.authorUrl = authorUrl;
+ this.footer = footer;
+ this.footerUrl = footerUrl;
+ }
public MessageEmbed toEmbed() {
return new EmbedBuilder()