From d0c06cd6bf2bf0ce837bc684faa43c9bfc4c111e Mon Sep 17 00:00:00 2001 From: anthorob Date: Fri, 14 Feb 2025 05:43:49 -0500 Subject: [PATCH] Bunch of improvements to tasks and DB logic Use locks when executing tasks Decouple GuildManager into services Add more logging when failing to load a persistable task Add ping method to WebModule Improve Task interface and implementations Start work on step tasks --- .../bobert/netneutrality/NetNeutrality.java | 2 +- .../command/AbstractMessageMenuCommand.java | 12 +- .../core/context/AbstractContext.java | 1 + .../core/tasks/AbstractBuiltInTask.java | 14 ++- .../core/tasks/AbstractPersistableTask.java | 29 ++++- .../core/tasks/AbstractTask.java | 8 +- .../core/tasks/GenericCustomIdTask.java | 27 +++++ .../core/tasks/GenericRandomIdTask.java | 15 +++ .../core/tasks/impl/StepTask.java | 110 ++++++++++++++++++ .../netneutrality/tasks/ButtonTask.java | 30 ----- .../bobert/netneutrality/tasks/EmojiTask.java | 31 ----- .../bobert/netneutrality/tasks/ModalTask.java | 42 ------- .../tasks/music/AddAllTracksTask.java | 61 ---------- .../tasks/music/CancelLoadTask.java | 45 ------- .../music/LoadTrackFromPlaylistTask.java | 1 + 15 files changed, 204 insertions(+), 224 deletions(-) create mode 100644 src/main/java/me/bobert/netneutrality/core/tasks/GenericCustomIdTask.java create mode 100644 src/main/java/me/bobert/netneutrality/core/tasks/GenericRandomIdTask.java create mode 100644 src/main/java/me/bobert/netneutrality/core/tasks/impl/StepTask.java delete mode 100644 src/main/java/me/bobert/netneutrality/tasks/ButtonTask.java delete mode 100644 src/main/java/me/bobert/netneutrality/tasks/EmojiTask.java delete mode 100644 src/main/java/me/bobert/netneutrality/tasks/ModalTask.java delete mode 100644 src/main/java/me/bobert/netneutrality/tasks/music/AddAllTracksTask.java delete mode 100644 src/main/java/me/bobert/netneutrality/tasks/music/CancelLoadTask.java diff --git a/src/main/java/me/bobert/netneutrality/NetNeutrality.java b/src/main/java/me/bobert/netneutrality/NetNeutrality.java index 04b82f9..845891d 100644 --- a/src/main/java/me/bobert/netneutrality/NetNeutrality.java +++ b/src/main/java/me/bobert/netneutrality/NetNeutrality.java @@ -49,7 +49,7 @@ public class NetNeutrality { options.setEnvironment(env); options.setTracesSampleRate(1.0); options.setDebug(false); - options.setRelease(VERSION); + options.setRelease(Settings.getVersion()); }); } diff --git a/src/main/java/me/bobert/netneutrality/core/command/AbstractMessageMenuCommand.java b/src/main/java/me/bobert/netneutrality/core/command/AbstractMessageMenuCommand.java index 3ea7a84..1dfc4cd 100644 --- a/src/main/java/me/bobert/netneutrality/core/command/AbstractMessageMenuCommand.java +++ b/src/main/java/me/bobert/netneutrality/core/command/AbstractMessageMenuCommand.java @@ -17,9 +17,14 @@ public abstract class AbstractMessageMenuCommand extends AbstractCommand { return null; } + @Override + public boolean isGuildOnly() { + return true; + } + @Override public boolean isSlashCommandOnly() { - return false; + return true; } @Override @@ -27,6 +32,11 @@ public abstract class AbstractMessageMenuCommand extends AbstractCommand { // no options for context commands } + @Override + public CommandCategory getCategory() { + return CommandCategory.UNLISTED; + } + @Override public Type getType() { return Type.MESSAGE; diff --git a/src/main/java/me/bobert/netneutrality/core/context/AbstractContext.java b/src/main/java/me/bobert/netneutrality/core/context/AbstractContext.java index 7d45998..ca55682 100644 --- a/src/main/java/me/bobert/netneutrality/core/context/AbstractContext.java +++ b/src/main/java/me/bobert/netneutrality/core/context/AbstractContext.java @@ -6,6 +6,7 @@ package me.bobert.netneutrality.core.context; */ import io.sentry.Sentry; +import me.bobert.netneutrality.context.command.SlashCommandContext; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/AbstractBuiltInTask.java b/src/main/java/me/bobert/netneutrality/core/tasks/AbstractBuiltInTask.java index ae3e4eb..f334bf4 100644 --- a/src/main/java/me/bobert/netneutrality/core/tasks/AbstractBuiltInTask.java +++ b/src/main/java/me/bobert/netneutrality/core/tasks/AbstractBuiltInTask.java @@ -6,6 +6,7 @@ package me.bobert.netneutrality.core.tasks; */ import me.bobert.netneutrality.core.context.CommandContext; +import me.bobert.netneutrality.core.context.TaskContext; public abstract class AbstractBuiltInTask extends AbstractTask implements BuiltInTask { @@ -19,11 +20,6 @@ public abstract class AbstractBuiltInTask extends AbstractTask implements BuiltI return true; } - @Override - public boolean oneshot() { - return false; - } - @Override public boolean isExpired() { return false; @@ -33,4 +29,12 @@ public abstract class AbstractBuiltInTask extends AbstractTask implements BuiltI public void replyToInteraction(CommandContext context) { // Task is loaded at runtime, this will never be called } + + @Override + public Lifecycle execute(TaskContext context) { + executeTask(context); + return Lifecycle.BUILTIN; + } + + public abstract void executeTask(TaskContext context); } diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/AbstractPersistableTask.java b/src/main/java/me/bobert/netneutrality/core/tasks/AbstractPersistableTask.java index dc71c77..4b03f13 100644 --- a/src/main/java/me/bobert/netneutrality/core/tasks/AbstractPersistableTask.java +++ b/src/main/java/me/bobert/netneutrality/core/tasks/AbstractPersistableTask.java @@ -15,11 +15,6 @@ public abstract class AbstractPersistableTask extends AbstractTask implements Pe return true; } - @Override - public boolean oneshot() { - return false; - } - @Override public boolean isExpired() { return false; @@ -30,6 +25,30 @@ public abstract class AbstractPersistableTask extends AbstractTask implements Pe // Task loaded from database, this will never be called } + @Override + public void insert(CommandContext context) { + if (TaskManager.getInstance().hasTask(getId())) { + throw new RuntimeException("Cannot insert a task that already exists"); + } + + TaskManager.getInstance().insert(context, this); + } + + @Override + public void save() { + if (!TaskManager.getInstance().hasTask(getId())) { + throw new RuntimeException("Cannot save a task that doesn't exist yet"); + } + + TaskManager.getInstance().getTaskService().persistTask(this); + } + + @Override + public void delete() { + TaskManager.getInstance().getTaskService().unpersistTask(this); + TaskManager.getInstance().removeTask(this); + } + @Override public String toPayload() { JSONObject payload = new JSONObject(this); diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/AbstractTask.java b/src/main/java/me/bobert/netneutrality/core/tasks/AbstractTask.java index 56e1bfd..a6b3820 100644 --- a/src/main/java/me/bobert/netneutrality/core/tasks/AbstractTask.java +++ b/src/main/java/me/bobert/netneutrality/core/tasks/AbstractTask.java @@ -5,6 +5,8 @@ package me.bobert.netneutrality.core.tasks; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.core.context.CommandContext; + import java.time.OffsetDateTime; import java.util.Objects; @@ -26,8 +28,8 @@ public abstract class AbstractTask implements Task { } @Override - public TaskButtonCreator createButton() { - return new TaskButtonCreator(getId()); + public void insert(CommandContext context) { + TaskManager.getInstance().insert(context, this); } @Override @@ -46,6 +48,6 @@ public abstract class AbstractTask implements Task { @Override public String toString() { - return String.format("Task{id=%s, class=%s, name=%s, oneshot=%b, creationTime=%s}", getId(), getClass().getSimpleName(), getName(), oneshot(), getCreationTime()); + return String.format("Task{id=%s, lockId=%s, class=%s, name=%s, creationTime=%s}", getId(), getLockId(), getClass().getSimpleName(), getName(), getCreationTime()); } } diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/GenericCustomIdTask.java b/src/main/java/me/bobert/netneutrality/core/tasks/GenericCustomIdTask.java new file mode 100644 index 0000000..8ab28a2 --- /dev/null +++ b/src/main/java/me/bobert/netneutrality/core/tasks/GenericCustomIdTask.java @@ -0,0 +1,27 @@ +package me.bobert.netneutrality.core.tasks; + +/* + * Copyright (c) anthorob + * + * https://discord.gg/qUa6zNFZsd + */ + +import net.dv8tion.jda.api.interactions.components.buttons.Button; + +public abstract class GenericCustomIdTask extends AbstractTask { + private final String customId; + + public GenericCustomIdTask(String id) { + this.customId = id; + } + + @Override + public String getId() { + return customId; + } + + @Override + public Button createButton() { + return null; + } +} diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/GenericRandomIdTask.java b/src/main/java/me/bobert/netneutrality/core/tasks/GenericRandomIdTask.java new file mode 100644 index 0000000..23cde6e --- /dev/null +++ b/src/main/java/me/bobert/netneutrality/core/tasks/GenericRandomIdTask.java @@ -0,0 +1,15 @@ +package me.bobert.netneutrality.core.tasks; + +/* + * Copyright (c) anthorob + * + * https://discord.gg/qUa6zNFZsd + */ + +import java.util.UUID; + +public abstract class GenericRandomIdTask extends GenericCustomIdTask { + public GenericRandomIdTask() { + super(UUID.randomUUID().toString()); + } +} diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/impl/StepTask.java b/src/main/java/me/bobert/netneutrality/core/tasks/impl/StepTask.java new file mode 100644 index 0000000..a17e558 --- /dev/null +++ b/src/main/java/me/bobert/netneutrality/core/tasks/impl/StepTask.java @@ -0,0 +1,110 @@ +package me.bobert.netneutrality.core.tasks.impl; + +/* + * Copyright (c) anthorob + * + * https://discord.gg/qUa6zNFZsd + */ + +import me.bobert.netneutrality.core.context.CommandContext; +import me.bobert.netneutrality.core.context.MessageContext; +import me.bobert.netneutrality.core.context.TaskContext; +import me.bobert.netneutrality.core.tasks.AbstractTask; +import me.bobert.netneutrality.core.tasks.TaskManager; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.interactions.components.buttons.Button; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.OffsetDateTime; +import java.util.UUID; + +public abstract class StepTask extends AbstractTask { + private static final Logger logger = LoggerFactory.getLogger(StepTask.class); + + public enum StepType { + STRING, ROLE, EMOJI + } + + private Guild guild; + private String id = UUID.randomUUID().toString(); + + @Override + public String getId() { + return id; + } + + @Override + public void replyToInteraction(CommandContext context) { + if (context.isFromGuild()) { + guild = context.getGuild(); + } + + if (guild == null && getStepType() == StepType.ROLE) { + throw new IllegalArgumentException("Step task if of type role but it was inserted in a non-guild context"); + } + + if (inDM()) { + context.replyEphemeral("Please follow the instructions sent in DM."); + context.sendMessageInPrivate(getStepDescription() + "\n" + getStepQuestion(), asyncContext -> assignId(asyncContext.getMessageId())); + } else { + context.reply(getStepQuestion(), asyncContext -> id = asyncContext.getMessageId()); + } + + System.out.println("step id : " + id); + } + + @Override + public Lifecycle execute(TaskContext context) { + if (context instanceof MessageContext messageContext) { + Message message = messageContext.getMessage(); + String answer = message.getContentRaw(); + + if (validateAnswer(answer)) { + StepTask nextStep = executeStep(answer); + + //TODO: to finish + } + } + + return Lifecycle.REMOVE_SELF; + } + + @Override + public boolean isExpired() { + return getCreationTime().plusMinutes(30).isBefore(OffsetDateTime.now()); + } + + @Override + public Button createButton() { + return null; + } + + private boolean validateAnswer(String answer) { + + } + + private void assignId(String newId) { + if (newId == null || newId.isBlank()) { + throw new IllegalArgumentException("Task ID cannot be null or empty."); + } + + synchronized (this) { + this.id = newId; + TaskManager.getInstance().activateTask(this); + } + + this.id = newId; + } + + public abstract boolean inDM(); + + public abstract StepType getStepType(); + + public abstract String getStepDescription(); + + public abstract String getStepQuestion(); + + public abstract StepTask executeStep(String answer); +} diff --git a/src/main/java/me/bobert/netneutrality/tasks/ButtonTask.java b/src/main/java/me/bobert/netneutrality/tasks/ButtonTask.java deleted file mode 100644 index 03bf819..0000000 --- a/src/main/java/me/bobert/netneutrality/tasks/ButtonTask.java +++ /dev/null @@ -1,30 +0,0 @@ -package me.bobert.netneutrality.tasks; -/* - * Copyright (c) anthorob - * - * https://discord.gg/qUa6zNFZsd - */ - -import me.bobert.netneutrality.core.tasks.AbstractTask; - -import java.time.OffsetDateTime; -import java.util.UUID; - -public abstract class ButtonTask extends AbstractTask { - private final UUID id = UUID.randomUUID(); - - @Override - public String getId() { - return id.toString(); - } - - @Override - public boolean oneshot() { - return true; - } - - @Override - public boolean isExpired() { - return getCreationTime().plusMinutes(15).isBefore(OffsetDateTime.now()); - } -} diff --git a/src/main/java/me/bobert/netneutrality/tasks/EmojiTask.java b/src/main/java/me/bobert/netneutrality/tasks/EmojiTask.java deleted file mode 100644 index 75a1487..0000000 --- a/src/main/java/me/bobert/netneutrality/tasks/EmojiTask.java +++ /dev/null @@ -1,31 +0,0 @@ -package me.bobert.netneutrality.tasks; -/* - * Copyright (c) anthorob - * - * https://discord.gg/qUa6zNFZsd - */ - -import me.bobert.netneutrality.core.tasks.AbstractPersistableTask; - -public abstract class EmojiTask extends AbstractPersistableTask { - private final String guildId; - private final String messageId; - - public EmojiTask(String guildId, String messageId) { - this.guildId = guildId; - this.messageId = messageId; - } - - public String getGuildId() { - return guildId; - } - - public String getMessageId() { - return messageId; - } - - @Override - public String getId() { - return String.format("%s:%s", getGuildId(), getMessageId()); - } -} diff --git a/src/main/java/me/bobert/netneutrality/tasks/ModalTask.java b/src/main/java/me/bobert/netneutrality/tasks/ModalTask.java deleted file mode 100644 index b55fc10..0000000 --- a/src/main/java/me/bobert/netneutrality/tasks/ModalTask.java +++ /dev/null @@ -1,42 +0,0 @@ -package me.bobert.netneutrality.tasks; -/* - * Copyright (c) anthorob - * - * https://discord.gg/qUa6zNFZsd - */ - -import me.bobert.netneutrality.core.context.TaskContext; -import me.bobert.netneutrality.core.tasks.AbstractTask; -import net.dv8tion.jda.api.interactions.modals.ModalMapping; - -import java.time.OffsetDateTime; -import java.util.List; -import java.util.UUID; - -public abstract class ModalTask extends AbstractTask { - private final UUID id = UUID.randomUUID(); - - @Override - public String getId() { - return id.toString(); - } - - @Override - public boolean oneshot() { - return true; - } - - @Override - public boolean isExpired() { - return getCreationTime().plusMinutes(5).isBefore(OffsetDateTime.now()); - } - - public ModalMapping getValue(String key, TaskContext context) { - List mappings = (List) context.getContextData("values"); - return mappings.stream() - .filter(o -> o instanceof ModalMapping) - .map(o -> (ModalMapping) o) - .filter(mapping -> mapping.getId().equals(key)) - .findFirst().orElse(null); - } -} diff --git a/src/main/java/me/bobert/netneutrality/tasks/music/AddAllTracksTask.java b/src/main/java/me/bobert/netneutrality/tasks/music/AddAllTracksTask.java deleted file mode 100644 index 91114da..0000000 --- a/src/main/java/me/bobert/netneutrality/tasks/music/AddAllTracksTask.java +++ /dev/null @@ -1,61 +0,0 @@ -package me.bobert.netneutrality.tasks.music; -/* - * Copyright (c) anthorob - * - * https://discord.gg/qUa6zNFZsd - */ - -import com.sedmelluq.discord.lavaplayer.track.AudioTrack; -import me.bobert.netneutrality.core.context.CommandContext; -import me.bobert.netneutrality.core.context.TaskContext; -import me.bobert.netneutrality.core.tasks.trait.WithParent; -import me.bobert.netneutrality.music.MusicManager; -import me.bobert.netneutrality.music.SourceFinder; -import me.bobert.netneutrality.tasks.ButtonTask; -import me.bobert.netneutrality.utils.MessageFunction; -import me.bobert.netneutrality.utils.MusicUtils; -import net.dv8tion.jda.api.entities.Member; - -import java.util.List; - -public class AddAllTracksTask extends ButtonTask implements WithParent { - private final LoadPlaylistTask parentTask; - List tracks; - - public AddAllTracksTask(LoadPlaylistTask parentTask, List tracks) { - this.parentTask = parentTask; - this.tracks = tracks; - } - - @Override - public String getName() { - return "add-all-tracks"; - } - - @Override - public void replyToInteraction(CommandContext context) { - - } - - @Override - public void execute(TaskContext context) { - MusicManager manager = MusicManager.get(context.getGuild()); - Member member = context.getGuildUser(); - - if (MusicUtils.connect(context)) { - manager.getQueueManager().queue(tracks, member); - - context.reply(MessageFunction.buildAddingPlaylistMessage(tracks, parentTask.getPlaylist().getName(), member, SourceFinder.AudioSourceType.Youtube)); - } - } - - @Override - public LoadPlaylistTask getParentTask() { - return parentTask; - } - - @Override - public boolean shouldKeepChilds() { - return false; - } -} diff --git a/src/main/java/me/bobert/netneutrality/tasks/music/CancelLoadTask.java b/src/main/java/me/bobert/netneutrality/tasks/music/CancelLoadTask.java deleted file mode 100644 index 563eedb..0000000 --- a/src/main/java/me/bobert/netneutrality/tasks/music/CancelLoadTask.java +++ /dev/null @@ -1,45 +0,0 @@ -package me.bobert.netneutrality.tasks.music; -/* - * Copyright (c) anthorob - * - * https://discord.gg/qUa6zNFZsd - */ - -import me.bobert.netneutrality.core.context.CommandContext; -import me.bobert.netneutrality.core.context.TaskContext; -import me.bobert.netneutrality.core.tasks.trait.NotAcknowledgeable; -import me.bobert.netneutrality.core.tasks.trait.WithParent; -import me.bobert.netneutrality.tasks.ButtonTask; - -public class CancelLoadTask extends ButtonTask implements WithParent, NotAcknowledgeable { - private final LoadPlaylistTask parentTask; - - public CancelLoadTask(LoadPlaylistTask parentTask) { - this.parentTask = parentTask; - } - - @Override - public String getName() { - return "cancel-playlist-loading"; - } - - @Override - public void replyToInteraction(CommandContext context) { - - } - - @Override - public LoadPlaylistTask getParentTask() { - return parentTask; - } - - @Override - public boolean shouldKeepChilds() { - return false; - } - - @Override - public void execute(TaskContext context) { - // Interaction will get removed after execution - } -} diff --git a/src/main/java/me/bobert/netneutrality/tasks/music/LoadTrackFromPlaylistTask.java b/src/main/java/me/bobert/netneutrality/tasks/music/LoadTrackFromPlaylistTask.java index 6c04d29..b19ee15 100644 --- a/src/main/java/me/bobert/netneutrality/tasks/music/LoadTrackFromPlaylistTask.java +++ b/src/main/java/me/bobert/netneutrality/tasks/music/LoadTrackFromPlaylistTask.java @@ -13,6 +13,7 @@ import me.bobert.netneutrality.utils.MessageFunction; import me.bobert.netneutrality.utils.MusicUtils; import net.dv8tion.jda.api.components.buttons.ButtonStyle; import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; public class LoadTrackFromPlaylistTask extends AcceptButton { private final AudioTrack track;