diff --git a/.env.example b/.env.example index f548c3f..c02e4e3 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,7 @@ NETNEUTRALITY_BOT_ENV=dev NETNEUTRALITY_BOT_TOKEN= NETNEUTRALITY_BOT_PREFIX=$ NETNEUTRALITY_BOT_OWNER= +NETNEUTRALITY_BOT_INVITE= NETNEUTRALITY_API_PORT=9000 MYSQL_HOST=127.0.0.1 diff --git a/bot.properties.example b/bot.properties.example index 895405b..7ad94bc 100644 --- a/bot.properties.example +++ b/bot.properties.example @@ -2,6 +2,7 @@ NETNEUTRALITY_BOT_ENV=dev NETNEUTRALITY_BOT_TOKEN= NETNEUTRALITY_BOT_PREFIX= NETNEUTRALITY_BOT_OWNER= +NETNEUTRALITY_BOT_INVITE= NETNEUTRALITY_API_PORT=9000 MYSQL_HOST=127.0.0.1 diff --git a/docker-compose-webapp.yml b/docker-compose-webapp.yml deleted file mode 100644 index 52c3955..0000000 --- a/docker-compose-webapp.yml +++ /dev/null @@ -1,64 +0,0 @@ -services: - db: - image: mariadb:lts@sha256:4b1e7958f820681b1b93b9cf9ea05a76e0785da12699a1fb1d05e0eb2137e56b - container_name: db - restart: unless-stopped - volumes: - - netneutrality-db:/var/lib/mysql - - ./sql:/docker-entrypoint-initdb.d - environment: - MYSQL_USER: 'java' - MYSQL_PASSWORD: 'password' - MYSQL_DATABASE: 'netneutrality' - MYSQL_ROOT_PASSWORD: 'password' - MARIADB_AUTO_UPGRADE: '1' - ports: - - "3306" - networks: - - internal - - bot: - container_name: bot - build: ./ - restart: unless-stopped - depends_on: - - db - volumes: - - ./logs:/app/logs - environment: - MYSQL_HOST: 'db' - MYSQL_USER: 'java' - MYSQL_PASSWORD: 'password' - MYSQL_DATABASE: 'netneutrality' - ports: - - "9000:9000" - networks: - - internal - - webapp: - image: bot-webapp:dev - build: ../netneutrality-webapp - restart: always - depends_on: - - db - - bot - volumes: - - ./logs:/app/logs - environment: - DB_CONNECTION: 'mysql' - DB_HOST: 'db' - DB_PORT: '3306' - DB_DATABASE: 'netneutrality' - DB_USERNAME: 'java' - DB_PASSWORD: 'password' - BOT_URL: 'http://bot:9000' - ports: - - '8080:80' - networks: - - internal - -volumes: - netneutrality-db: - -networks: - internal: \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 79bbec0..056f464 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: netneutrality-db: - image: mariadb:lts@sha256:4b1e7958f820681b1b93b9cf9ea05a76e0785da12699a1fb1d05e0eb2137e56b + image: mariadb:11 container_name: db restart: unless-stopped networks: diff --git a/pom.xml b/pom.xml index 2b8ceef..58262bf 100644 --- a/pom.xml +++ b/pom.xml @@ -259,11 +259,6 @@ commons-lang3 3.17.0 - - commons-codec - commons-codec - 1.18.0 - commons-io commons-io diff --git a/renovate.json b/renovate.json index 2061c05..ec277d3 100644 --- a/renovate.json +++ b/renovate.json @@ -9,7 +9,15 @@ { "groupName": "hibernate orm", "matchPackageNames": [ - "org.hibernate.orm:**" + "org.hibernate.orm:**", + "com.mysql:**" + ] + }, + { + "groupName": "apache commons", + "matchPackageNames": [ + "commons:**", + "org.apache.commons:**" ] } ] diff --git a/src/main/java/me/bobert/netneutrality/NetNeutrality.java b/src/main/java/me/bobert/netneutrality/NetNeutrality.java index ddeddf3..a942b82 100644 --- a/src/main/java/me/bobert/netneutrality/NetNeutrality.java +++ b/src/main/java/me/bobert/netneutrality/NetNeutrality.java @@ -12,11 +12,11 @@ import me.bobert.netneutrality.core.command.CommandManager; import me.bobert.netneutrality.core.db.DatabaseMigration; import me.bobert.netneutrality.core.db.SessionManager; import me.bobert.netneutrality.core.tasks.TaskManager; +import me.bobert.netneutrality.core.thread.ScheduledTaskManager; import me.bobert.netneutrality.core.thread.ThreadManager; import me.bobert.netneutrality.hooks.EventsHandler; import me.bobert.netneutrality.http.server.WebApi; import me.bobert.netneutrality.music.MusicManager; -import me.bobert.netneutrality.thread.ShutdownThread; import me.bobert.netneutrality.utils.Settings; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; @@ -79,7 +79,7 @@ public class NetNeutrality { new WebApi(Integer.parseInt(Settings.getInstance().get("NETNEUTRALITY_API_PORT", "9000"))); jda.getPresence().setActivity(Activity.watching("you")); - Runtime.getRuntime().addShutdownHook(new ShutdownThread(this)); + Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown)); } public static NetNeutrality getInstance() { @@ -108,6 +108,7 @@ public class NetNeutrality { public void shutdown() { System.out.println("[Net Neutrality] Shutting down..."); + ScheduledTaskManager.cancelAll(); MusicManager.disconnectPlayers(); ThreadManager.shutdownExecutor(); disconnect(); diff --git a/src/main/java/me/bobert/netneutrality/command/basic/HelpCommand.java b/src/main/java/me/bobert/netneutrality/command/basic/HelpCommand.java index 7ad68cf..4275ad3 100644 --- a/src/main/java/me/bobert/netneutrality/command/basic/HelpCommand.java +++ b/src/main/java/me/bobert/netneutrality/command/basic/HelpCommand.java @@ -13,7 +13,7 @@ import me.bobert.netneutrality.core.command.CommandOptionsBuilder; import me.bobert.netneutrality.core.command.impl.AbstractCommand; import me.bobert.netneutrality.core.command.options.CommandOption; import me.bobert.netneutrality.core.context.CommandContext; -import me.bobert.netneutrality.core.tasks.BuiltInTask; +import me.bobert.netneutrality.core.tasks.Task; import me.bobert.netneutrality.tasks.help.BotInfo; import me.bobert.netneutrality.tasks.help.CommandHelp; import me.bobert.netneutrality.tasks.help.ReportBug; @@ -65,9 +65,9 @@ public class HelpCommand extends AbstractCommand { public CommandExecutionResult execute(CommandContext context) { String command = context.getOption("command", null, CommandOption::getAsString); if (command == null) { - Button commands = BuiltInTask.createButton(CommandHelp.class); - Button info = BuiltInTask.createButton(BotInfo.class); - Button reportbug = BuiltInTask.createButton(ReportBug.class); + Button commands = Task.createButton(CommandHelp.class); + Button info = Task.createButton(BotInfo.class); + Button reportbug = Task.createButton(ReportBug.class); ActionRow row = ActionRow.of(commands, info, reportbug); context.replyEphemeral("Thanks for using the Net Neutrality Bot! What do you need help with?", List.of(row)); return CommandExecutionResult.none(); diff --git a/src/main/java/me/bobert/netneutrality/core/command/CommandManager.java b/src/main/java/me/bobert/netneutrality/core/command/CommandManager.java index 79c8607..a33f22c 100644 --- a/src/main/java/me/bobert/netneutrality/core/command/CommandManager.java +++ b/src/main/java/me/bobert/netneutrality/core/command/CommandManager.java @@ -5,6 +5,7 @@ package me.bobert.netneutrality.core.command; * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.utils.ReflectionHelper; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.interactions.InteractionContextType; import net.dv8tion.jda.api.interactions.commands.build.CommandData; @@ -12,9 +13,7 @@ import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.reflections.Reflections; -import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -39,34 +38,27 @@ public class CommandManager { } public static void initCommands() { - Set> classes = new Reflections("me.bobert.netneutrality.command").getSubTypesOf(Command.class); - for (Class s : classes) { - try { - if (Modifier.isAbstract(s.getModifiers())) { - continue; - } - - Command command = s.getConstructor().newInstance(); - if (!command.isEnabled()) { - continue; - } - - if (command.getCommandName() == null) { - throw new IllegalArgumentException("Command name is null"); - } - - if (command.getDescription() == null && command.getType() == Command.Type.SLASH) { - throw new IllegalArgumentException("Command description is null"); - } - - CommandContainer container = new CommandContainer(command); - if (!commands.containsKey(command.getCommandName())) { - commands.put(command.getCommandName(), container); - } - } catch (Exception e) { - logger.error("Failed to load command {}: {}", s.getSimpleName(), e.getMessage()); + ReflectionHelper.loadCommands(Command.class, command -> { + if (!command.isEnabled()) { + logger.info("Skipping command {} as it is disabled", command.getClass().getName()); + return; } - } + + if (command.getCommandName() == null) { + logger.error("Failed to load command {}: Command name is null", command.getClass().getName()); + return; + } + + if (command.getDescription() == null && command.getType() == Command.Type.SLASH) { + logger.error("Failed to load command {}: Command description is null", command.getClass().getName()); + return; + } + + CommandContainer container = new CommandContainer(command); + if (!commands.containsKey(command.getCommandName())) { + commands.put(command.getCommandName(), container); + } + }); } public static void registerSlashCommands(JDA jda) { diff --git a/src/main/java/me/bobert/netneutrality/core/command/CommandProcessor.java b/src/main/java/me/bobert/netneutrality/core/command/CommandProcessor.java index 77615ba..8260eed 100644 --- a/src/main/java/me/bobert/netneutrality/core/command/CommandProcessor.java +++ b/src/main/java/me/bobert/netneutrality/core/command/CommandProcessor.java @@ -65,7 +65,7 @@ public class CommandProcessor { } try { - logger.info("Context ID: {}", context.getId()); + logger.debug("Context ID: {}", context.getId()); logger.info("Executing command {} on guild {}", command.getCommandName(), context.getGuild() == null ? "PrivateMessage" : context.getGuild().getId()); configureSentry(command); diff --git a/src/main/java/me/bobert/netneutrality/core/context/Context.java b/src/main/java/me/bobert/netneutrality/core/context/Context.java index d9a5504..2127c62 100644 --- a/src/main/java/me/bobert/netneutrality/core/context/Context.java +++ b/src/main/java/me/bobert/netneutrality/core/context/Context.java @@ -151,6 +151,10 @@ public interface Context { replyEphemeralWithLimit(message); } + default void replyEphemeral(String message, LayoutComponent component) { + replyEphemeral(message, List.of(component)); + } + default void replyEphemeral(String message, List components) { replyEphemeral(MessageCreateData.fromContent(message), components); } diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/BuiltInTask.java b/src/main/java/me/bobert/netneutrality/core/tasks/BuiltInTask.java index a64fa2d..ceb185c 100644 --- a/src/main/java/me/bobert/netneutrality/core/tasks/BuiltInTask.java +++ b/src/main/java/me/bobert/netneutrality/core/tasks/BuiltInTask.java @@ -5,7 +5,7 @@ package me.bobert.netneutrality.core.tasks; * https://discord.gg/qUa6zNFZsd */ -import net.dv8tion.jda.api.interactions.components.buttons.Button; +import me.bobert.netneutrality.core.context.TaskContext; /** * Represents a task that has a known ID and is loaded at runtime. @@ -13,13 +13,5 @@ import net.dv8tion.jda.api.interactions.components.buttons.Button; */ public interface BuiltInTask extends Task { - static Button createButton(Class clazz) { - BuiltInTask builtInTask = TaskManager.getInstance().findBuiltInTaskByClass(clazz); - - if (builtInTask == null) { - throw new IllegalArgumentException("Task class " + clazz.getName() + " was not registered by the task manager."); - } - - return builtInTask.createButton(); - } + void executeTask(TaskContext context); } diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/ScheduledTask.java b/src/main/java/me/bobert/netneutrality/core/tasks/ScheduledTask.java new file mode 100644 index 0000000..d7a3c3e --- /dev/null +++ b/src/main/java/me/bobert/netneutrality/core/tasks/ScheduledTask.java @@ -0,0 +1,64 @@ +package me.bobert.netneutrality.core.tasks; + +/* + * Copyright (c) anthorob + * + * https://discord.gg/qUa6zNFZsd + */ + +import java.util.concurrent.TimeUnit; + +public interface ScheduledTask { + + class TimeFrame { + private final int interval; + private final TimeUnit unit; + + private TimeFrame(int interval, TimeUnit unit) { + this.interval = interval; + this.unit = unit; + } + + public static TimeFrame minutely() { + return new TimeFrame(1, TimeUnit.MINUTES); + } + + public static TimeFrame minutely(int interval) { + return new TimeFrame(interval, TimeUnit.MINUTES); + } + + public static TimeFrame hourly() { + return new TimeFrame(1, TimeUnit.HOURS); + } + + public static TimeFrame hourly(int interval) { + return new TimeFrame(interval, TimeUnit.HOURS); + } + + public static TimeFrame daily() { + return new TimeFrame(1, TimeUnit.DAYS); + } + + public static TimeFrame daily(int interval) { + return new TimeFrame(interval, TimeUnit.DAYS); + } + + public static TimeFrame custom(int interval, TimeUnit unit) { + return new TimeFrame(interval, unit); + } + + public int getInterval() { + return interval; + } + + public TimeUnit getUnit() { + return unit; + } + } + + String getId(); + + TimeFrame getTimeFrame(); + + void run(); +} diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/IStepTask.java b/src/main/java/me/bobert/netneutrality/core/tasks/StepTask.java similarity index 99% rename from src/main/java/me/bobert/netneutrality/core/tasks/IStepTask.java rename to src/main/java/me/bobert/netneutrality/core/tasks/StepTask.java index fee1dbb..d14bc51 100644 --- a/src/main/java/me/bobert/netneutrality/core/tasks/IStepTask.java +++ b/src/main/java/me/bobert/netneutrality/core/tasks/StepTask.java @@ -6,7 +6,7 @@ package me.bobert.netneutrality.core.tasks; * https://discord.gg/qUa6zNFZsd */ -public interface IStepTask { +public interface StepTask { /** * Defines the type of input expected for a step. diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/Task.java b/src/main/java/me/bobert/netneutrality/core/tasks/Task.java index 3b337bb..7db15f0 100644 --- a/src/main/java/me/bobert/netneutrality/core/tasks/Task.java +++ b/src/main/java/me/bobert/netneutrality/core/tasks/Task.java @@ -7,6 +7,7 @@ package me.bobert.netneutrality.core.tasks; import me.bobert.netneutrality.core.context.CommandContext; import me.bobert.netneutrality.core.context.TaskContext; +import me.bobert.netneutrality.core.tasks.trait.WithButton; import me.bobert.netneutrality.core.tasks.trait.WithChildren; import net.dv8tion.jda.api.interactions.components.buttons.Button; @@ -64,8 +65,6 @@ public interface Task { OffsetDateTime getCreationTime(); - Button createButton(); - /** *

This method is used to reply to the interaction that triggered this task.

*

If the task is implementing {@link WithChildren}, the child tasks must be instanciated in this method.

@@ -80,4 +79,14 @@ public interface Task { Lifecycle execute(TaskContext context); void insert(CommandContext context); + + static Button createButton(Class clazz) { + WithButton withButton = TaskManager.getInstance().findButtonTaskByClass(clazz); + + if (withButton == null) { + throw new IllegalArgumentException("Task " + clazz.getName() + " was not registered by the task manager."); + } + + return withButton.createButton(); + } } diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/TaskManager.java b/src/main/java/me/bobert/netneutrality/core/tasks/TaskManager.java index 99e2b54..6d4cf93 100644 --- a/src/main/java/me/bobert/netneutrality/core/tasks/TaskManager.java +++ b/src/main/java/me/bobert/netneutrality/core/tasks/TaskManager.java @@ -11,28 +11,24 @@ import me.bobert.netneutrality.core.context.InteractionContext; import me.bobert.netneutrality.core.context.TaskContext; import me.bobert.netneutrality.core.tasks.trait.Deletable; import me.bobert.netneutrality.core.tasks.trait.NotAcknowledgeable; +import me.bobert.netneutrality.core.tasks.trait.WithButton; import me.bobert.netneutrality.core.tasks.trait.WithChildren; import me.bobert.netneutrality.core.tasks.trait.WithParent; -import me.bobert.netneutrality.core.thread.ThreadManager; +import me.bobert.netneutrality.core.thread.ScheduledTaskManager; import me.bobert.netneutrality.db.service.TaskService; import me.bobert.netneutrality.exceptions.GracefulContextError; import me.bobert.netneutrality.exceptions.TaskExecutionException; -import me.bobert.netneutrality.thread.CleanupTaskThread; +import me.bobert.netneutrality.utils.ReflectionHelper; import net.dv8tion.jda.api.interactions.InteractionHook; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.reflections.Reflections; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Modifier; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; @@ -63,12 +59,11 @@ public class TaskManager { public void init() { loadBuiltInTasks(); + loadScheduledTasks(); taskService.loadTasks(); - - ThreadManager.getScheduledExecutor().scheduleWithFixedDelay(new CleanupTaskThread(), 1, 5, TimeUnit.MINUTES); } - protected TaskService getTaskService() { + public TaskService getTaskService() { return taskService; } @@ -101,7 +96,7 @@ public class TaskManager { taskService.persistTask(persistableTask); } - if (task instanceof IStepTask) { + if (task instanceof StepTask) { pendingTasks.add(task); } else { tasks.put(id, task); @@ -176,7 +171,7 @@ public class TaskManager { } } - logger.debug("Executing task: {}", taskId); + logger.info("Executing task: {}", taskId); Task.Lifecycle status = task.execute(context); handleTaskLifecycle(task, status); @@ -205,7 +200,7 @@ public class TaskManager { public Optional findTaskByPartialId(Class clazz, String partialId) { List tasks = findTasksByPartialId(clazz, partialId); - return Optional.ofNullable(tasks.isEmpty() ? null : tasks.get(0)); + return Optional.ofNullable(tasks.isEmpty() ? null : tasks.getFirst()); } public List findTasksByPartialId(Class clazz, String partialId) { @@ -216,10 +211,10 @@ public class TaskManager { .collect(Collectors.toList()); } - public BuiltInTask findBuiltInTaskByClass(Class clazz) { + public WithButton findButtonTaskByClass(Class clazz) { return tasks.values().stream() .filter(clazz::isInstance) - .map(task -> (BuiltInTask) task) + .map(task -> (WithButton) task) .findFirst() .orElse(null); } @@ -237,22 +232,27 @@ public class TaskManager { private void loadBuiltInTasks() { logger.info("Loading built-in tasks..."); - Set> classes = new Reflections("me.bobert.netneutrality.tasks").getSubTypesOf(BuiltInTask.class); - for (Class s : classes) { - try { - if (Modifier.isAbstract(s.getModifiers())) { - continue; - } - - BuiltInTask task = s.getConstructor().newInstance(); - - logger.info("Loaded task: {}", task); - tasks.put(task.getId(), task); - } catch (InstantiationException | IllegalAccessException | IllegalArgumentException - | InvocationTargetException | NoSuchMethodException | SecurityException e) { - logger.error("Failed to instantiate built-in task", e); + ReflectionHelper.loadTasks(BuiltInTask.class, builtInTask -> { + if (builtInTask.isInsertable()) { + logger.info("Loaded task: {}", builtInTask.getClass().getName()); + tasks.put(builtInTask.getId(), builtInTask); } - } + }); + } + + private void loadScheduledTasks() { + logger.info("Loading scheduled tasks..."); + + ReflectionHelper.loadTasks(ScheduledTask.class, scheduledTask -> { + String taskId = scheduledTask.getId(); + + if (taskId == null || taskId.trim().isEmpty()) { + logger.error("Cannot load scheduled task {}: task ID is null or empty", scheduledTask.getClass().getName()); + return; + } + + ScheduledTaskManager.schedule(scheduledTask); + }); } private void deleteInteraction(Task task) { diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/AbstractBuiltInTask.java b/src/main/java/me/bobert/netneutrality/core/tasks/impl/AbstractBuiltInTask.java similarity index 88% rename from src/main/java/me/bobert/netneutrality/core/tasks/AbstractBuiltInTask.java rename to src/main/java/me/bobert/netneutrality/core/tasks/impl/AbstractBuiltInTask.java index f334bf4..61dbbbd 100644 --- a/src/main/java/me/bobert/netneutrality/core/tasks/AbstractBuiltInTask.java +++ b/src/main/java/me/bobert/netneutrality/core/tasks/impl/AbstractBuiltInTask.java @@ -1,4 +1,4 @@ -package me.bobert.netneutrality.core.tasks; +package me.bobert.netneutrality.core.tasks.impl; /* * Copyright (c) anthorob * @@ -7,6 +7,7 @@ package me.bobert.netneutrality.core.tasks; import me.bobert.netneutrality.core.context.CommandContext; import me.bobert.netneutrality.core.context.TaskContext; +import me.bobert.netneutrality.core.tasks.BuiltInTask; public abstract class AbstractBuiltInTask extends AbstractTask implements BuiltInTask { @@ -35,6 +36,4 @@ public abstract class AbstractBuiltInTask extends AbstractTask implements BuiltI 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/impl/AbstractPersistableTask.java similarity index 89% rename from src/main/java/me/bobert/netneutrality/core/tasks/AbstractPersistableTask.java rename to src/main/java/me/bobert/netneutrality/core/tasks/impl/AbstractPersistableTask.java index 4b03f13..820aad8 100644 --- a/src/main/java/me/bobert/netneutrality/core/tasks/AbstractPersistableTask.java +++ b/src/main/java/me/bobert/netneutrality/core/tasks/impl/AbstractPersistableTask.java @@ -1,4 +1,4 @@ -package me.bobert.netneutrality.core.tasks; +package me.bobert.netneutrality.core.tasks.impl; /* * Copyright (c) anthorob * @@ -6,6 +6,8 @@ package me.bobert.netneutrality.core.tasks; */ import me.bobert.netneutrality.core.context.CommandContext; +import me.bobert.netneutrality.core.tasks.PersistableTask; +import me.bobert.netneutrality.core.tasks.TaskManager; import org.json.JSONObject; public abstract class AbstractPersistableTask extends AbstractTask implements PersistableTask { diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/impl/StepTask.java b/src/main/java/me/bobert/netneutrality/core/tasks/impl/AbstractStepTask.java similarity index 93% rename from src/main/java/me/bobert/netneutrality/core/tasks/impl/StepTask.java rename to src/main/java/me/bobert/netneutrality/core/tasks/impl/AbstractStepTask.java index f0466ab..3876037 100644 --- a/src/main/java/me/bobert/netneutrality/core/tasks/impl/StepTask.java +++ b/src/main/java/me/bobert/netneutrality/core/tasks/impl/AbstractStepTask.java @@ -9,13 +9,11 @@ package me.bobert.netneutrality.core.tasks.impl; 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.IStepTask; +import me.bobert.netneutrality.core.tasks.StepTask; 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.entities.Role; -import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.fellbaum.jemoji.Emoji; import net.fellbaum.jemoji.EmojiManager; @@ -27,7 +25,7 @@ import java.util.UUID; * Represents a task that consists of multiple sequential steps. The task starts with an initial message (question) * and expects a user response. Each step can lead to another step, forming a workflow. */ -public abstract class StepTask extends AbstractTask implements IStepTask { +public abstract class AbstractStepTask extends AbstractTask implements StepTask { private final Object stepLock = new Object(); private CommandContext commandContext; private Guild guild; @@ -110,11 +108,6 @@ public abstract class StepTask extends AbstractTask implements IStepTask { return getCreationTime().plusMinutes(60).isBefore(OffsetDateTime.now()); } - @Override - public Button createButton() { - return null; - } - /** * Validates the user input against the expected step type. * diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/AbstractTask.java b/src/main/java/me/bobert/netneutrality/core/tasks/impl/AbstractTask.java similarity index 88% rename from src/main/java/me/bobert/netneutrality/core/tasks/AbstractTask.java rename to src/main/java/me/bobert/netneutrality/core/tasks/impl/AbstractTask.java index a50c620..c972192 100644 --- a/src/main/java/me/bobert/netneutrality/core/tasks/AbstractTask.java +++ b/src/main/java/me/bobert/netneutrality/core/tasks/impl/AbstractTask.java @@ -1,4 +1,4 @@ -package me.bobert.netneutrality.core.tasks; +package me.bobert.netneutrality.core.tasks.impl; /* * Copyright (c) anthorob * @@ -6,6 +6,8 @@ package me.bobert.netneutrality.core.tasks; */ import me.bobert.netneutrality.core.context.CommandContext; +import me.bobert.netneutrality.core.tasks.Task; +import me.bobert.netneutrality.core.tasks.TaskManager; import java.time.OffsetDateTime; import java.util.Objects; diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/impl/ButtonTask.java b/src/main/java/me/bobert/netneutrality/core/tasks/impl/ButtonTask.java index f18d76e..27dc14d 100644 --- a/src/main/java/me/bobert/netneutrality/core/tasks/impl/ButtonTask.java +++ b/src/main/java/me/bobert/netneutrality/core/tasks/impl/ButtonTask.java @@ -5,49 +5,40 @@ package me.bobert.netneutrality.core.tasks.impl; * https://discord.gg/qUa6zNFZsd */ -import me.bobert.netneutrality.core.tasks.GenericRandomIdTask; import me.bobert.netneutrality.core.tasks.Task; -import me.bobert.netneutrality.core.tasks.trait.WithChildren; -import net.dv8tion.jda.api.interactions.components.ActionRow; +import me.bobert.netneutrality.core.tasks.trait.WithButton; +import net.dv8tion.jda.api.entities.emoji.Emoji; import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; import java.time.OffsetDateTime; -import java.util.List; -public abstract class ButtonTask extends GenericRandomIdTask { +public abstract class ButtonTask extends GenericRandomIdTask implements WithButton { private final ButtonStyle buttonStyle; private final String buttonLabel; + private Emoji emoji; public ButtonTask(ButtonStyle buttonStyle, String buttonLabel) { this.buttonStyle = buttonStyle; this.buttonLabel = buttonLabel; } + public Task setEmoji(Emoji emoji) { + this.emoji = emoji; + return this; + } + @Override public Button createButton() { if (buttonStyle == null || buttonLabel == null) { return null; } - return Button.of(buttonStyle, getId(), buttonLabel); + return Button.of(buttonStyle, getId(), buttonLabel, emoji); } @Override public boolean isExpired() { return getCreationTime().plusMinutes(15).isBefore(OffsetDateTime.now()); } - - public ActionRow createActionRow(List tasks) { - ActionRow row = ActionRow.of(tasks.stream().map(Task::createButton).toList()); - if (this instanceof WithChildren parent) { - parent.addChild(tasks); - } - - return row; - } - - public ActionRow createActionRow(Task... tasks) { - return createActionRow(List.of(tasks)); - } } diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/impl/EmojiTask.java b/src/main/java/me/bobert/netneutrality/core/tasks/impl/EmojiTask.java index dae4604..cfdb734 100644 --- a/src/main/java/me/bobert/netneutrality/core/tasks/impl/EmojiTask.java +++ b/src/main/java/me/bobert/netneutrality/core/tasks/impl/EmojiTask.java @@ -6,8 +6,6 @@ package me.bobert.netneutrality.core.tasks.impl; */ import me.bobert.netneutrality.context.tasks.EmojiTaskContext; -import me.bobert.netneutrality.core.tasks.AbstractPersistableTask; -import net.dv8tion.jda.api.interactions.components.buttons.Button; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -54,9 +52,4 @@ public abstract class EmojiTask extends AbstractPersistableTask { public String getId() { return String.format(EmojiTaskContext.ID, getGuildId(), getMessageId()); } - - @Override - public Button createButton() { - return null; - } } diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/GenericCustomIdTask.java b/src/main/java/me/bobert/netneutrality/core/tasks/impl/GenericCustomIdTask.java similarity index 63% rename from src/main/java/me/bobert/netneutrality/core/tasks/GenericCustomIdTask.java rename to src/main/java/me/bobert/netneutrality/core/tasks/impl/GenericCustomIdTask.java index 8ab28a2..573905b 100644 --- a/src/main/java/me/bobert/netneutrality/core/tasks/GenericCustomIdTask.java +++ b/src/main/java/me/bobert/netneutrality/core/tasks/impl/GenericCustomIdTask.java @@ -1,4 +1,4 @@ -package me.bobert.netneutrality.core.tasks; +package me.bobert.netneutrality.core.tasks.impl; /* * Copyright (c) anthorob @@ -6,8 +6,6 @@ package me.bobert.netneutrality.core.tasks; * https://discord.gg/qUa6zNFZsd */ -import net.dv8tion.jda.api.interactions.components.buttons.Button; - public abstract class GenericCustomIdTask extends AbstractTask { private final String customId; @@ -19,9 +17,4 @@ public abstract class GenericCustomIdTask extends AbstractTask { 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/impl/GenericRandomIdTask.java similarity index 83% rename from src/main/java/me/bobert/netneutrality/core/tasks/GenericRandomIdTask.java rename to src/main/java/me/bobert/netneutrality/core/tasks/impl/GenericRandomIdTask.java index 23cde6e..e7a0e66 100644 --- a/src/main/java/me/bobert/netneutrality/core/tasks/GenericRandomIdTask.java +++ b/src/main/java/me/bobert/netneutrality/core/tasks/impl/GenericRandomIdTask.java @@ -1,4 +1,4 @@ -package me.bobert.netneutrality.core.tasks; +package me.bobert.netneutrality.core.tasks.impl; /* * Copyright (c) anthorob diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/impl/ModalTask.java b/src/main/java/me/bobert/netneutrality/core/tasks/impl/ModalTask.java index beb5a01..c16a680 100644 --- a/src/main/java/me/bobert/netneutrality/core/tasks/impl/ModalTask.java +++ b/src/main/java/me/bobert/netneutrality/core/tasks/impl/ModalTask.java @@ -6,7 +6,6 @@ package me.bobert.netneutrality.core.tasks.impl; */ import me.bobert.netneutrality.core.context.TaskContext; -import me.bobert.netneutrality.core.tasks.GenericRandomIdTask; import net.dv8tion.jda.api.interactions.modals.ModalMapping; import java.time.OffsetDateTime; diff --git a/src/main/java/me/bobert/netneutrality/core/tasks/trait/WithButton.java b/src/main/java/me/bobert/netneutrality/core/tasks/trait/WithButton.java new file mode 100644 index 0000000..2603df3 --- /dev/null +++ b/src/main/java/me/bobert/netneutrality/core/tasks/trait/WithButton.java @@ -0,0 +1,31 @@ +package me.bobert.netneutrality.core.tasks.trait; + +/* + * Copyright (c) anthorob + * + * https://discord.gg/qUa6zNFZsd + */ + +import me.bobert.netneutrality.core.tasks.Task; +import net.dv8tion.jda.api.interactions.components.ActionRow; +import net.dv8tion.jda.api.interactions.components.buttons.Button; + +import java.util.List; + +public interface WithButton { + + Button createButton(); + + default ActionRow createActionRow(List tasks) { + ActionRow row = ActionRow.of(tasks.stream().filter(task -> task instanceof WithButton).map(task -> (WithButton) task).map(WithButton::createButton).toList()); + if (this instanceof WithChildren parent) { + parent.addChild(tasks); + } + + return row; + } + + default ActionRow createActionRow(Task... tasks) { + return createActionRow(List.of(tasks)); + } +} diff --git a/src/main/java/me/bobert/netneutrality/core/thread/ScheduledTaskManager.java b/src/main/java/me/bobert/netneutrality/core/thread/ScheduledTaskManager.java new file mode 100644 index 0000000..bc33c35 --- /dev/null +++ b/src/main/java/me/bobert/netneutrality/core/thread/ScheduledTaskManager.java @@ -0,0 +1,64 @@ +package me.bobert.netneutrality.core.thread; + +/* + * Copyright (c) anthorob + * + * https://discord.gg/qUa6zNFZsd + */ + +import me.bobert.netneutrality.core.LogHandler; +import me.bobert.netneutrality.core.tasks.ScheduledTask; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; + +public class ScheduledTaskManager { + private static final Logger logger = LogManager.getLogger(ScheduledTaskManager.class); + private static final ScheduledExecutorService executorService = ThreadManager.getScheduledExecutor(); + private static final Map> scheduledTasks = new ConcurrentHashMap<>(); + + private ScheduledTaskManager() {} + + public static void schedule(ScheduledTask task) { + String taskId = task.getId(); + + if (scheduledTasks.containsKey(taskId)) { + logger.warn("Task {} is already scheduled.", taskId); + return; + } + + ScheduledTask.TimeFrame timeFrame = task.getTimeFrame(); + + Runnable runnable = () -> { + logger.info("Executing scheduled task: {}", taskId); + + try { + task.run(); + } catch (Exception e) { + logger.error("An exception was thrown while executing scheduled task {}", taskId); + LogHandler.log(e); + } + }; + + ScheduledFuture future = executorService.scheduleWithFixedDelay( + runnable, + 1, + timeFrame.getInterval(), + timeFrame.getUnit() + ); + + scheduledTasks.put(taskId, future); + logger.info("Successfully scheduled task: {} with interval {} {}", + taskId, timeFrame.getInterval(), timeFrame.getUnit()); + } + + public static void cancelAll() { + logger.info("Cancelling all {} scheduled tasks", scheduledTasks.size()); + scheduledTasks.forEach((id, future) -> future.cancel(false)); + scheduledTasks.clear(); + } +} diff --git a/src/main/java/me/bobert/netneutrality/music/MusicManager.java b/src/main/java/me/bobert/netneutrality/music/MusicManager.java index 1af9447..870c85f 100644 --- a/src/main/java/me/bobert/netneutrality/music/MusicManager.java +++ b/src/main/java/me/bobert/netneutrality/music/MusicManager.java @@ -15,12 +15,9 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import dev.lavalink.youtube.YoutubeAudioSourceManager; import me.bobert.netneutrality.core.command.CommandExecutionResult; import me.bobert.netneutrality.core.context.CommandContext; -import me.bobert.netneutrality.core.thread.ThreadManager; import me.bobert.netneutrality.db.GSettings; import me.bobert.netneutrality.db.service.GuildService; import me.bobert.netneutrality.music.source.UdioAudioSourceManager; -import me.bobert.netneutrality.thread.MusicManagerCleanupThread; -import me.bobert.netneutrality.thread.MusicPlayerAutoDisconnectThread; import me.bobert.netneutrality.utils.MusicUtils; import me.bobert.netneutrality.utils.Settings; import net.dv8tion.jda.api.entities.Guild; @@ -31,7 +28,6 @@ import org.apache.logging.log4j.Logger; import java.util.Collection; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; public class MusicManager { @@ -72,9 +68,6 @@ public class MusicManager { String po = Settings.getInstance().get("NETNEUTRALITY_PO_TOKEN"); String visitor = Settings.getInstance().get("NETNEUTRALITY_VISITOR_DATA"); dev.lavalink.youtube.clients.Web.setPoTokenAndVisitorData(po, visitor); - - ThreadManager.getScheduledExecutor().scheduleWithFixedDelay(new MusicPlayerAutoDisconnectThread(), 15, 15, TimeUnit.MINUTES); - ThreadManager.getScheduledExecutor().scheduleWithFixedDelay(new MusicManagerCleanupThread(), 1, 1, TimeUnit.HOURS); } public static void disconnectPlayers() { diff --git a/src/main/java/me/bobert/netneutrality/tasks/help/BotInfo.java b/src/main/java/me/bobert/netneutrality/tasks/help/BotInfo.java index 8c02b71..ccb717d 100644 --- a/src/main/java/me/bobert/netneutrality/tasks/help/BotInfo.java +++ b/src/main/java/me/bobert/netneutrality/tasks/help/BotInfo.java @@ -6,10 +6,12 @@ package me.bobert.netneutrality.tasks.help; */ import me.bobert.netneutrality.core.context.TaskContext; -import me.bobert.netneutrality.core.tasks.AbstractBuiltInTask; +import me.bobert.netneutrality.core.tasks.impl.AbstractBuiltInTask; +import me.bobert.netneutrality.core.tasks.trait.WithButton; +import me.bobert.netneutrality.utils.Settings; import net.dv8tion.jda.api.interactions.components.buttons.Button; -public class BotInfo extends AbstractBuiltInTask { +public class BotInfo extends AbstractBuiltInTask implements WithButton { @Override public String getId() { @@ -23,7 +25,7 @@ public class BotInfo extends AbstractBuiltInTask { @Override public void executeTask(TaskContext context) { - context.sendMessageInPrivate("For information about the bot and to follow the development, " + - "you can join the discord here: https://discord.gg/udVJwTgV"); + context.replyEphemeral("For information about the bot and to follow the development, " + + "you can join the discord here: " + Settings.getDiscordInvite()); } } diff --git a/src/main/java/me/bobert/netneutrality/tasks/help/CommandHelp.java b/src/main/java/me/bobert/netneutrality/tasks/help/CommandHelp.java index 37eeb5b..88089d3 100644 --- a/src/main/java/me/bobert/netneutrality/tasks/help/CommandHelp.java +++ b/src/main/java/me/bobert/netneutrality/tasks/help/CommandHelp.java @@ -6,12 +6,13 @@ package me.bobert.netneutrality.tasks.help; */ import me.bobert.netneutrality.core.context.TaskContext; -import me.bobert.netneutrality.core.tasks.AbstractBuiltInTask; +import me.bobert.netneutrality.core.tasks.impl.AbstractBuiltInTask; +import me.bobert.netneutrality.core.tasks.trait.WithButton; import me.bobert.netneutrality.utils.MessageFunction; import me.bobert.netneutrality.utils.Settings; import net.dv8tion.jda.api.interactions.components.buttons.Button; -public class CommandHelp extends AbstractBuiltInTask { +public class CommandHelp extends AbstractBuiltInTask implements WithButton { @Override public String getId() { diff --git a/src/main/java/me/bobert/netneutrality/tasks/help/ReportBug.java b/src/main/java/me/bobert/netneutrality/tasks/help/ReportBug.java index 70ec080..830b965 100644 --- a/src/main/java/me/bobert/netneutrality/tasks/help/ReportBug.java +++ b/src/main/java/me/bobert/netneutrality/tasks/help/ReportBug.java @@ -6,10 +6,12 @@ package me.bobert.netneutrality.tasks.help; */ import me.bobert.netneutrality.core.context.TaskContext; -import me.bobert.netneutrality.core.tasks.AbstractBuiltInTask; +import me.bobert.netneutrality.core.tasks.impl.AbstractBuiltInTask; +import me.bobert.netneutrality.core.tasks.trait.WithButton; +import me.bobert.netneutrality.utils.Settings; import net.dv8tion.jda.api.interactions.components.buttons.Button; -public class ReportBug extends AbstractBuiltInTask { +public class ReportBug extends AbstractBuiltInTask implements WithButton { @Override public String getId() { @@ -23,7 +25,7 @@ public class ReportBug extends AbstractBuiltInTask { @Override public void executeTask(TaskContext context) { - context.sendMessageInPrivate("To report a bug with the bot, you can either use the /report-bug command " + - "or join the discord here: https://discord.gg/udVJwTgV"); + context.replyEphemeral("To report a bug with the bot, you can either use the /report-bug command " + + "or join the discord here: " + Settings.getDiscordInvite()); } } diff --git a/src/main/java/me/bobert/netneutrality/tasks/music/LoadPlaylistTask.java b/src/main/java/me/bobert/netneutrality/tasks/music/LoadPlaylistTask.java index 18d4df3..089c90d 100644 --- a/src/main/java/me/bobert/netneutrality/tasks/music/LoadPlaylistTask.java +++ b/src/main/java/me/bobert/netneutrality/tasks/music/LoadPlaylistTask.java @@ -109,15 +109,12 @@ public class LoadPlaylistTask extends ButtonTask implements WithChildren, Deleta } return Lifecycle.KEEP; - }); + }).setEmoji(Emoji.fromFormatted("U+1F60E")); - Task cancel = CancelButton.create(this, cancelText, context -> Lifecycle.REMOVE_SELF_AND_CHILDREN); - addChild(accept, cancel); + Task cancel = CancelButton.create(this, cancelText, context -> Lifecycle.REMOVE_SELF_AND_CHILDREN) + .setEmoji(Emoji.fromFormatted("U+1F92E")); - return ActionRow.of( - accept.createButton().withEmoji(Emoji.fromFormatted("U+1F60E")), - cancel.createButton().withEmoji(Emoji.fromFormatted("U+1F92E")) - ); + return createActionRow(accept, cancel); } @Override diff --git a/src/main/java/me/bobert/netneutrality/tasks/reaction/EmojiRoleFirstStep.java b/src/main/java/me/bobert/netneutrality/tasks/reaction/EmojiRoleFirstStep.java index 83aeaa8..e03a5fe 100644 --- a/src/main/java/me/bobert/netneutrality/tasks/reaction/EmojiRoleFirstStep.java +++ b/src/main/java/me/bobert/netneutrality/tasks/reaction/EmojiRoleFirstStep.java @@ -6,11 +6,11 @@ package me.bobert.netneutrality.tasks.reaction; * https://discord.gg/qUa6zNFZsd */ -import me.bobert.netneutrality.core.tasks.impl.StepTask; +import me.bobert.netneutrality.core.tasks.impl.AbstractStepTask; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.Role; -public class EmojiRoleFirstStep extends StepTask { +public class EmojiRoleFirstStep extends AbstractStepTask { private final Message target; public EmojiRoleFirstStep(Message target) { diff --git a/src/main/java/me/bobert/netneutrality/tasks/reaction/EmojiRoleModify.java b/src/main/java/me/bobert/netneutrality/tasks/reaction/EmojiRoleModify.java index 40bf58e..ca442fd 100644 --- a/src/main/java/me/bobert/netneutrality/tasks/reaction/EmojiRoleModify.java +++ b/src/main/java/me/bobert/netneutrality/tasks/reaction/EmojiRoleModify.java @@ -74,7 +74,7 @@ public class EmojiRoleModify extends ButtonTask implements WithChildren { }); ActionRow row = createActionRow(addEmojiTask, removeEmojiTask, deleteMappingTask); - context.replyEphemeral("Select what you want to do with this message", List.of(row)); + context.replyEphemeral("Select what you want to do with this message", row); } @Override diff --git a/src/main/java/me/bobert/netneutrality/tasks/reaction/EmojiRoleRemoveStep.java b/src/main/java/me/bobert/netneutrality/tasks/reaction/EmojiRoleRemoveStep.java index 0d59a89..0de6bc9 100644 --- a/src/main/java/me/bobert/netneutrality/tasks/reaction/EmojiRoleRemoveStep.java +++ b/src/main/java/me/bobert/netneutrality/tasks/reaction/EmojiRoleRemoveStep.java @@ -6,14 +6,14 @@ package me.bobert.netneutrality.tasks.reaction; * https://discord.gg/qUa6zNFZsd */ -import me.bobert.netneutrality.core.tasks.impl.StepTask; +import me.bobert.netneutrality.core.tasks.impl.AbstractStepTask; import me.bobert.netneutrality.tasks.emoji.EmojiReactionRoleTask; import net.dv8tion.jda.api.entities.Message; import java.util.Set; import java.util.StringJoiner; -public class EmojiRoleRemoveStep extends StepTask { +public class EmojiRoleRemoveStep extends AbstractStepTask { private final Message target; private final EmojiReactionRoleTask task; @@ -22,6 +22,11 @@ public class EmojiRoleRemoveStep extends StepTask { this.task = task; } + @Override + public String getName() { + return "emoji-role-remove"; + } + @Override public StepType getStepType() { return StepType.EMOJI; @@ -54,9 +59,4 @@ public class EmojiRoleRemoveStep extends StepTask { task.removeEmoji(emoji); return StepResult.success("Removed emoji successfully!"); } - - @Override - public String getName() { - return "emoji-role-remove"; - } } diff --git a/src/main/java/me/bobert/netneutrality/tasks/reaction/EmojiRoleSecondStep.java b/src/main/java/me/bobert/netneutrality/tasks/reaction/EmojiRoleSecondStep.java index 92c3a60..f305909 100644 --- a/src/main/java/me/bobert/netneutrality/tasks/reaction/EmojiRoleSecondStep.java +++ b/src/main/java/me/bobert/netneutrality/tasks/reaction/EmojiRoleSecondStep.java @@ -8,14 +8,14 @@ package me.bobert.netneutrality.tasks.reaction; import me.bobert.netneutrality.core.tasks.Task; import me.bobert.netneutrality.core.tasks.TaskManager; -import me.bobert.netneutrality.core.tasks.impl.StepTask; +import me.bobert.netneutrality.core.tasks.impl.AbstractStepTask; import me.bobert.netneutrality.tasks.emoji.EmojiReactionRoleTask; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.Role; import java.util.Map; -public class EmojiRoleSecondStep extends StepTask { +public class EmojiRoleSecondStep extends AbstractStepTask { private final Message target; private final Role role; diff --git a/src/main/java/me/bobert/netneutrality/thread/MusicManagerCleanupThread.java b/src/main/java/me/bobert/netneutrality/tasks/scheduled/MusicManagerCleanup.java similarity index 74% rename from src/main/java/me/bobert/netneutrality/thread/MusicManagerCleanupThread.java rename to src/main/java/me/bobert/netneutrality/tasks/scheduled/MusicManagerCleanup.java index d52d064..140386d 100644 --- a/src/main/java/me/bobert/netneutrality/thread/MusicManagerCleanupThread.java +++ b/src/main/java/me/bobert/netneutrality/tasks/scheduled/MusicManagerCleanup.java @@ -1,27 +1,35 @@ -package me.bobert.netneutrality.thread; +package me.bobert.netneutrality.tasks.scheduled; /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.core.tasks.ScheduledTask; import me.bobert.netneutrality.music.MusicManager; import me.bobert.netneutrality.music.TrackScheduler; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -public class MusicManagerCleanupThread implements Runnable { - private static final Logger logger = LogManager.getLogger(MusicManagerCleanupThread.class); +public class MusicManagerCleanup implements ScheduledTask { + private static final Logger logger = LogManager.getLogger(MusicManagerCleanup.class); + + @Override + public String getId() { + return "MusicManagerCleanup"; + } + + @Override + public TimeFrame getTimeFrame() { + return TimeFrame.hourly(); + } @Override public void run() { - try { - for (MusicManager manager : MusicManager.getManagers()) { processManager(manager); } - } catch (InterruptedException e) { logger.error("Interrupted while running MusicManagerCleanupThread", e); } diff --git a/src/main/java/me/bobert/netneutrality/thread/MusicPlayerAutoDisconnectThread.java b/src/main/java/me/bobert/netneutrality/tasks/scheduled/MusicPlayerAutoDisconnect.java similarity index 84% rename from src/main/java/me/bobert/netneutrality/thread/MusicPlayerAutoDisconnectThread.java rename to src/main/java/me/bobert/netneutrality/tasks/scheduled/MusicPlayerAutoDisconnect.java index 2efb483..802c195 100644 --- a/src/main/java/me/bobert/netneutrality/thread/MusicPlayerAutoDisconnectThread.java +++ b/src/main/java/me/bobert/netneutrality/tasks/scheduled/MusicPlayerAutoDisconnect.java @@ -1,10 +1,12 @@ -package me.bobert.netneutrality.thread; +package me.bobert.netneutrality.tasks.scheduled; + /* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd */ +import me.bobert.netneutrality.core.tasks.ScheduledTask; import me.bobert.netneutrality.music.MusicManager; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.middleman.AudioChannel; @@ -13,17 +15,25 @@ import org.apache.logging.log4j.Logger; import java.util.List; -public class MusicPlayerAutoDisconnectThread implements Runnable { - private static final Logger logger = LogManager.getLogger(MusicPlayerAutoDisconnectThread.class); +public class MusicPlayerAutoDisconnect implements ScheduledTask { + private static final Logger logger = LogManager.getLogger(MusicPlayerAutoDisconnect.class); + + @Override + public String getId() { + return "MusicPlayerAutoDisconnect"; + } + + @Override + public TimeFrame getTimeFrame() { + return TimeFrame.minutely(15); + } @Override public void run() { try { - for (MusicManager manager : MusicManager.getManagers()) { processManager(manager); } - } catch (InterruptedException e) { logger.error("Interrupted while running MusicPlayerAutoDisconnectThread", e); } diff --git a/src/main/java/me/bobert/netneutrality/thread/CleanupTaskThread.java b/src/main/java/me/bobert/netneutrality/tasks/scheduled/TaskCleanup.java similarity index 69% rename from src/main/java/me/bobert/netneutrality/thread/CleanupTaskThread.java rename to src/main/java/me/bobert/netneutrality/tasks/scheduled/TaskCleanup.java index 6022b37..00260e2 100644 --- a/src/main/java/me/bobert/netneutrality/thread/CleanupTaskThread.java +++ b/src/main/java/me/bobert/netneutrality/tasks/scheduled/TaskCleanup.java @@ -1,4 +1,4 @@ -package me.bobert.netneutrality.thread;/* +package me.bobert.netneutrality.tasks.scheduled;/* * Copyright (c) anthorob * * https://discord.gg/qUa6zNFZsd @@ -6,6 +6,7 @@ package me.bobert.netneutrality.thread;/* import me.bobert.netneutrality.core.tasks.BuiltInTask; import me.bobert.netneutrality.core.tasks.PersistableTask; +import me.bobert.netneutrality.core.tasks.ScheduledTask; import me.bobert.netneutrality.core.tasks.Task; import me.bobert.netneutrality.core.tasks.TaskManager; import org.apache.logging.log4j.LogManager; @@ -13,8 +14,18 @@ import org.apache.logging.log4j.Logger; import java.util.List; -public class CleanupTaskThread implements Runnable { - private static final Logger logger = LogManager.getLogger(CleanupTaskThread.class); +public class TaskCleanup implements ScheduledTask { + private static final Logger logger = LogManager.getLogger(TaskCleanup.class); + + @Override + public String getId() { + return "TaskCleanup"; + } + + @Override + public TimeFrame getTimeFrame() { + return TimeFrame.minutely(5); + } @Override public void run() { diff --git a/src/main/java/me/bobert/netneutrality/thread/ShutdownThread.java b/src/main/java/me/bobert/netneutrality/thread/ShutdownThread.java deleted file mode 100644 index cb19a71..0000000 --- a/src/main/java/me/bobert/netneutrality/thread/ShutdownThread.java +++ /dev/null @@ -1,33 +0,0 @@ -package me.bobert.netneutrality.thread; - -/* - * Copyright (c) anthorob - * - * https://discord.gg/qUa6zNFZsd - */ - -import me.bobert.netneutrality.NetNeutrality; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.config.Configurator; - -public class ShutdownThread extends Thread { - private final NetNeutrality main; - - public ShutdownThread(NetNeutrality main) { - this.main = main; - } - - @Override - public void run() { - if (LogManager.getContext() instanceof LoggerContext) { - System.out.println("Shutting down log4j2"); - Configurator.shutdown((LoggerContext) LogManager.getContext()); - } - - if (main.getJDA() != null) { - main.shutdown(); - } - - } -} diff --git a/src/main/java/me/bobert/netneutrality/utils/ReflectionHelper.java b/src/main/java/me/bobert/netneutrality/utils/ReflectionHelper.java new file mode 100644 index 0000000..24e7d5f --- /dev/null +++ b/src/main/java/me/bobert/netneutrality/utils/ReflectionHelper.java @@ -0,0 +1,55 @@ +package me.bobert.netneutrality.utils; + +/* + * Copyright (c) anthorob + * + * https://discord.gg/qUa6zNFZsd + */ + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.reflections.Reflections; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +public class ReflectionHelper { + private static final Logger logger = LogManager.getLogger(ReflectionHelper.class); + private static final BiConsumer, Exception> DEFAULT_FAILURE = (aClass, e) -> logger.error("Failed to load class: {}", aClass.getName(), e); + + public static void loadClassesFromPackage(String packageName, Class clazz, Consumer onInstanciated, BiConsumer, Exception> onFailed) { + Set> classes = new Reflections(packageName).getSubTypesOf(clazz); + for (Class s : classes) { + try { + if (Modifier.isAbstract(s.getModifiers())) { + continue; + } + + E instance = s.getConstructor().newInstance(); + onInstanciated.accept(instance); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException | NoSuchMethodException | SecurityException e) { + onFailed.accept(s, e); + } + } + } + + public static void loadCommands(Class clazz, Consumer onInstanciated, BiConsumer, Exception> onFailed) { + loadClassesFromPackage("me.bobert.netneutrality.command", clazz, onInstanciated, onFailed); + } + + public static void loadCommands(Class clazz, Consumer onInstanciated) { + loadClassesFromPackage("me.bobert.netneutrality.command", clazz, onInstanciated, DEFAULT_FAILURE); + } + + public static void loadTasks(Class clazz, Consumer onInstanciated, BiConsumer, Exception> onFailed) { + loadClassesFromPackage("me.bobert.netneutrality.tasks", clazz, onInstanciated, onFailed); + } + + public static void loadTasks(Class clazz, Consumer onInstanciated) { + loadClassesFromPackage("me.bobert.netneutrality.tasks", clazz, onInstanciated, DEFAULT_FAILURE); + } +} diff --git a/src/main/java/me/bobert/netneutrality/utils/Settings.java b/src/main/java/me/bobert/netneutrality/utils/Settings.java index fce7c92..ec0c689 100644 --- a/src/main/java/me/bobert/netneutrality/utils/Settings.java +++ b/src/main/java/me/bobert/netneutrality/utils/Settings.java @@ -54,6 +54,10 @@ public class Settings { return INSTANCE; } + public static String getDiscordInvite() { + return Settings.getInstance().get("NETNEUTRALITY_BOT_INVITE", "https://discord.gg/PyCpd7JGMp"); + } + public static String getVersion() { return Settings.getInstance().getMavenVersion(); }