start storage implementation

This commit is contained in:
2024-08-06 00:04:18 +02:00
parent 82055cbe3a
commit 0b8607d03b
5 changed files with 186 additions and 38 deletions
+17
View File
@@ -88,6 +88,23 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.46.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.1.8</version>
</dependency>
</dependencies> </dependencies>
</project> </project>
@@ -13,12 +13,15 @@ import java.io.*;
import java.util.Collections; import java.util.Collections;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.logging.Logger;
public class Main { public class Main {
private static final Logger logger = Logger.getLogger("Main");
private static final Properties properties = new Properties(); private static final Properties properties = new Properties();
private static String version = "Unknown version"; private static String version = "Unknown version";
private static Storage storage;
public static JDA jda; public static JDA jda;
public static void main(String[] args) throws InterruptedException { public static void main(String[] args) throws InterruptedException {
@@ -28,13 +31,17 @@ public class Main {
if (resource != null) { if (resource != null) {
version = new String(resource.readAllBytes()); version = new String(resource.readAllBytes());
} else { } else {
System.err.println("Version file missing."); logger.severe("Version file missing.");
} }
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(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()) jda = JDABuilder.createLight(properties.getProperty("DISCORD_TOKEN"), Collections.emptyList())
.setCallbackPool(Executors.newVirtualThreadPerTaskExecutor()) .setCallbackPool(Executors.newVirtualThreadPerTaskExecutor())
@@ -73,7 +80,7 @@ public class Main {
try (InputStream resource = Main.class.getClassLoader().getResourceAsStream("noted.properites"); try (InputStream resource = Main.class.getClassLoader().getResourceAsStream("noted.properites");
OutputStream outputStream = new FileOutputStream(file)) { OutputStream outputStream = new FileOutputStream(file)) {
if (resource == null) { if (resource == null) {
System.err.println("Default noted.properties missing."); logger.severe("Default noted.properties missing.");
return; return;
} }
outputStream.write(resource.readAllBytes()); outputStream.write(resource.readAllBytes());
@@ -86,4 +93,9 @@ public class Main {
return version; return version;
} }
private static void shutdown() {
jda.shutdown();
storage.shutdown();
}
} }
@@ -4,7 +4,6 @@ import me.youhavetrouble.noted.note.Note;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
public class SlashCommandListener extends ListenerAdapter { public class SlashCommandListener extends ListenerAdapter {
@@ -15,35 +14,42 @@ public class SlashCommandListener extends ListenerAdapter {
OptionMapping noteIdOption = event.getOption("note-id"); OptionMapping noteIdOption = event.getOption("note-id");
OptionMapping ephemeralOption = event.getOption("ephemeral"); OptionMapping ephemeralOption = event.getOption("ephemeral");
if (noteIdOption == null) { if (noteIdOption == null) {
event.reply("Please provide a note ID.").setEphemeral(true).queue(); event.reply("Please provide a note ID.")
.setEphemeral(true)
.queue();
return; return;
} }
Note note = new Note(
"Sample Note Title",
null,
"Bottom text",
null,
null,
null,
null,
null,
null,
null
);
ReplyCallbackAction action = event.replyEmbeds(note.toEmbed()); boolean ephemeral;
if (ephemeralOption != null && ephemeralOption.getAsBoolean()) { try {
action = action.setEphemeral(true); ephemeral = ephemeralOption != null && ephemeralOption.getAsBoolean();
} } catch (IllegalArgumentException e) {
action.queue(); event.reply("Invalid value for ephemeral.")
.setEphemeral(true)
} .queue();
default -> {
event.reply("Unknown command.").setEphemeral(true).queue();
return; return;
} }
String noteId = noteIdOption.getAsString();
getNote(event, noteId, ephemeral);
}
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();
}
} }
@@ -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");
}
}
}
@@ -1,12 +1,34 @@
package me.youhavetrouble.noted.note; 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.EmbedBuilder;
import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.MessageEmbed;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.awt.Color; import java.awt.Color;
import java.time.Duration;
public record Note( public class Note {
public static final Cache<String, Note> 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, @NotNull String title,
@Nullable String titleUrl, @Nullable String titleUrl,
@NotNull String content, @NotNull String content,
@@ -18,6 +40,17 @@ public record Note(
@Nullable String footer, @Nullable String footer,
@Nullable String footerUrl @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() { public MessageEmbed toEmbed() {
return new EmbedBuilder() return new EmbedBuilder()