Implement scheduled tasks

This commit is contained in:
anthorob committed 2025-10-22 20:11:03 +00:00
1 parent 78a149b546
commit 78002d9299
42 files changed
+403 -283

No files matched your search

+1
View File
@@ -4,6 +4,7 @@ NETNEUTRALITY_BOT_ENV=dev
NETNEUTRALITY_BOT_TOKEN= NETNEUTRALITY_BOT_TOKEN=
NETNEUTRALITY_BOT_PREFIX=$ NETNEUTRALITY_BOT_PREFIX=$
NETNEUTRALITY_BOT_OWNER= NETNEUTRALITY_BOT_OWNER=
NETNEUTRALITY_BOT_INVITE=
NETNEUTRALITY_API_PORT=9000 NETNEUTRALITY_API_PORT=9000
MYSQL_HOST=127.0.0.1 MYSQL_HOST=127.0.0.1
+1
View File
@@ -2,6 +2,7 @@ NETNEUTRALITY_BOT_ENV=dev
NETNEUTRALITY_BOT_TOKEN= NETNEUTRALITY_BOT_TOKEN=
NETNEUTRALITY_BOT_PREFIX= NETNEUTRALITY_BOT_PREFIX=
NETNEUTRALITY_BOT_OWNER= NETNEUTRALITY_BOT_OWNER=
NETNEUTRALITY_BOT_INVITE=
NETNEUTRALITY_API_PORT=9000 NETNEUTRALITY_API_PORT=9000
MYSQL_HOST=127.0.0.1 MYSQL_HOST=127.0.0.1
-64
View File
@@ -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:
+1 -1
View File
@@ -1,6 +1,6 @@
services: services:
netneutrality-db: netneutrality-db:
image: mariadb:lts@sha256:4b1e7958f820681b1b93b9cf9ea05a76e0785da12699a1fb1d05e0eb2137e56b image: mariadb:11
container_name: db container_name: db
restart: unless-stopped restart: unless-stopped
networks: networks:
-5
View File
@@ -259,11 +259,6 @@
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
<version>3.17.0</version> <version>3.17.0</version>
</dependency> </dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.18.0</version>
</dependency>
<dependency> <dependency>
<groupId>commons-io</groupId> <groupId>commons-io</groupId>
<artifactId>commons-io</artifactId> <artifactId>commons-io</artifactId>
+9 -1
View File
@@ -9,7 +9,15 @@
{ {
"groupName": "hibernate orm", "groupName": "hibernate orm",
"matchPackageNames": [ "matchPackageNames": [
"org.hibernate.orm:**" "org.hibernate.orm:**",
"com.mysql:**"
]
},
{
"groupName": "apache commons",
"matchPackageNames": [
"commons:**",
"org.apache.commons:**"
] ]
} }
] ]
@@ -12,11 +12,11 @@ import me.bobert.netneutrality.core.command.CommandManager;
import me.bobert.netneutrality.core.db.DatabaseMigration; import me.bobert.netneutrality.core.db.DatabaseMigration;
import me.bobert.netneutrality.core.db.SessionManager; import me.bobert.netneutrality.core.db.SessionManager;
import me.bobert.netneutrality.core.tasks.TaskManager; 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.core.thread.ThreadManager;
import me.bobert.netneutrality.hooks.EventsHandler; import me.bobert.netneutrality.hooks.EventsHandler;
import me.bobert.netneutrality.http.server.WebApi; import me.bobert.netneutrality.http.server.WebApi;
import me.bobert.netneutrality.music.MusicManager; import me.bobert.netneutrality.music.MusicManager;
import me.bobert.netneutrality.thread.ShutdownThread;
import me.bobert.netneutrality.utils.Settings; import me.bobert.netneutrality.utils.Settings;
import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.JDABuilder;
@@ -79,7 +79,7 @@ public class NetNeutrality {
new WebApi(Integer.parseInt(Settings.getInstance().get("NETNEUTRALITY_API_PORT", "9000"))); new WebApi(Integer.parseInt(Settings.getInstance().get("NETNEUTRALITY_API_PORT", "9000")));
jda.getPresence().setActivity(Activity.watching("you")); jda.getPresence().setActivity(Activity.watching("you"));
Runtime.getRuntime().addShutdownHook(new ShutdownThread(this)); Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown));
} }
public static NetNeutrality getInstance() { public static NetNeutrality getInstance() {
@@ -108,6 +108,7 @@ public class NetNeutrality {
public void shutdown() { public void shutdown() {
System.out.println("[Net Neutrality] Shutting down..."); System.out.println("[Net Neutrality] Shutting down...");
ScheduledTaskManager.cancelAll();
MusicManager.disconnectPlayers(); MusicManager.disconnectPlayers();
ThreadManager.shutdownExecutor(); ThreadManager.shutdownExecutor();
disconnect(); disconnect();
@@ -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.impl.AbstractCommand;
import me.bobert.netneutrality.core.command.options.CommandOption; import me.bobert.netneutrality.core.command.options.CommandOption;
import me.bobert.netneutrality.core.context.CommandContext; 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.BotInfo;
import me.bobert.netneutrality.tasks.help.CommandHelp; import me.bobert.netneutrality.tasks.help.CommandHelp;
import me.bobert.netneutrality.tasks.help.ReportBug; import me.bobert.netneutrality.tasks.help.ReportBug;
@@ -65,9 +65,9 @@ public class HelpCommand extends AbstractCommand {
public CommandExecutionResult execute(CommandContext context) { public CommandExecutionResult execute(CommandContext context) {
String command = context.getOption("command", null, CommandOption::getAsString); String command = context.getOption("command", null, CommandOption::getAsString);
if (command == null) { if (command == null) {
Button commands = BuiltInTask.createButton(CommandHelp.class); Button commands = Task.createButton(CommandHelp.class);
Button info = BuiltInTask.createButton(BotInfo.class); Button info = Task.createButton(BotInfo.class);
Button reportbug = BuiltInTask.createButton(ReportBug.class); Button reportbug = Task.createButton(ReportBug.class);
ActionRow row = ActionRow.of(commands, info, reportbug); 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)); context.replyEphemeral("Thanks for using the Net Neutrality Bot! What do you need help with?", List.of(row));
return CommandExecutionResult.none(); return CommandExecutionResult.none();
@@ -5,6 +5,7 @@ package me.bobert.netneutrality.core.command;
* https://discord.gg/qUa6zNFZsd * https://discord.gg/qUa6zNFZsd
*/ */
import me.bobert.netneutrality.utils.ReflectionHelper;
import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.interactions.InteractionContextType; import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.build.CommandData; 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 net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.reflections.Reflections;
import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -39,34 +38,27 @@ public class CommandManager {
} }
public static void initCommands() { public static void initCommands() {
Set<Class<? extends Command>> classes = new Reflections("me.bobert.netneutrality.command").getSubTypesOf(Command.class); ReflectionHelper.loadCommands(Command.class, command -> {
for (Class<? extends Command> s : classes) { if (!command.isEnabled()) {
try { logger.info("Skipping command {} as it is disabled", command.getClass().getName());
if (Modifier.isAbstract(s.getModifiers())) { return;
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());
} }
}
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) { public static void registerSlashCommands(JDA jda) {
@@ -65,7 +65,7 @@ public class CommandProcessor {
} }
try { 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()); logger.info("Executing command {} on guild {}", command.getCommandName(), context.getGuild() == null ? "PrivateMessage" : context.getGuild().getId());
configureSentry(command); configureSentry(command);
@@ -151,6 +151,10 @@ public interface Context {
replyEphemeralWithLimit(message); replyEphemeralWithLimit(message);
} }
default void replyEphemeral(String message, LayoutComponent component) {
replyEphemeral(message, List.of(component));
}
default void replyEphemeral(String message, List<LayoutComponent> components) { default void replyEphemeral(String message, List<LayoutComponent> components) {
replyEphemeral(MessageCreateData.fromContent(message), components); replyEphemeral(MessageCreateData.fromContent(message), components);
} }
@@ -5,7 +5,7 @@ package me.bobert.netneutrality.core.tasks;
* https://discord.gg/qUa6zNFZsd * 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. * 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 { public interface BuiltInTask extends Task {
static Button createButton(Class<? extends BuiltInTask> clazz) { void executeTask(TaskContext context);
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();
}
} }
@@ -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();
}
@@ -6,7 +6,7 @@ package me.bobert.netneutrality.core.tasks;
* https://discord.gg/qUa6zNFZsd * https://discord.gg/qUa6zNFZsd
*/ */
public interface IStepTask { public interface StepTask {
/** /**
* Defines the type of input expected for a step. * Defines the type of input expected for a step.
@@ -7,6 +7,7 @@ package me.bobert.netneutrality.core.tasks;
import me.bobert.netneutrality.core.context.CommandContext; import me.bobert.netneutrality.core.context.CommandContext;
import me.bobert.netneutrality.core.context.TaskContext; import me.bobert.netneutrality.core.context.TaskContext;
import me.bobert.netneutrality.core.tasks.trait.WithButton;
import me.bobert.netneutrality.core.tasks.trait.WithChildren; import me.bobert.netneutrality.core.tasks.trait.WithChildren;
import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.components.buttons.Button;
@@ -64,8 +65,6 @@ public interface Task {
OffsetDateTime getCreationTime(); OffsetDateTime getCreationTime();
Button createButton();
/** /**
* <p>This method is used to reply to the interaction that triggered this task.</p> * <p>This method is used to reply to the interaction that triggered this task.</p>
* <p>If the task is implementing {@link WithChildren}, the child tasks must be instanciated in this method.</p> * <p>If the task is implementing {@link WithChildren}, the child tasks must be instanciated in this method.</p>
@@ -80,4 +79,14 @@ public interface Task {
Lifecycle execute(TaskContext context); Lifecycle execute(TaskContext context);
void insert(CommandContext context); void insert(CommandContext context);
static Button createButton(Class<? extends WithButton> 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();
}
} }
@@ -11,28 +11,24 @@ import me.bobert.netneutrality.core.context.InteractionContext;
import me.bobert.netneutrality.core.context.TaskContext; import me.bobert.netneutrality.core.context.TaskContext;
import me.bobert.netneutrality.core.tasks.trait.Deletable; import me.bobert.netneutrality.core.tasks.trait.Deletable;
import me.bobert.netneutrality.core.tasks.trait.NotAcknowledgeable; 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.WithChildren;
import me.bobert.netneutrality.core.tasks.trait.WithParent; 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.db.service.TaskService;
import me.bobert.netneutrality.exceptions.GracefulContextError; import me.bobert.netneutrality.exceptions.GracefulContextError;
import me.bobert.netneutrality.exceptions.TaskExecutionException; 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 net.dv8tion.jda.api.interactions.InteractionHook;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; 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.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -63,12 +59,11 @@ public class TaskManager {
public void init() { public void init() {
loadBuiltInTasks(); loadBuiltInTasks();
loadScheduledTasks();
taskService.loadTasks(); taskService.loadTasks();
ThreadManager.getScheduledExecutor().scheduleWithFixedDelay(new CleanupTaskThread(), 1, 5, TimeUnit.MINUTES);
} }
protected TaskService getTaskService() { public TaskService getTaskService() {
return taskService; return taskService;
} }
@@ -101,7 +96,7 @@ public class TaskManager {
taskService.persistTask(persistableTask); taskService.persistTask(persistableTask);
} }
if (task instanceof IStepTask) { if (task instanceof StepTask) {
pendingTasks.add(task); pendingTasks.add(task);
} else { } else {
tasks.put(id, task); 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); Task.Lifecycle status = task.execute(context);
handleTaskLifecycle(task, status); handleTaskLifecycle(task, status);
@@ -205,7 +200,7 @@ public class TaskManager {
public <E extends Task> Optional<E> findTaskByPartialId(Class<E> clazz, String partialId) { public <E extends Task> Optional<E> findTaskByPartialId(Class<E> clazz, String partialId) {
List<E> tasks = findTasksByPartialId(clazz, partialId); List<E> tasks = findTasksByPartialId(clazz, partialId);
return Optional.ofNullable(tasks.isEmpty() ? null : tasks.get(0)); return Optional.ofNullable(tasks.isEmpty() ? null : tasks.getFirst());
} }
public <E extends Task> List<E> findTasksByPartialId(Class<E> clazz, String partialId) { public <E extends Task> List<E> findTasksByPartialId(Class<E> clazz, String partialId) {
@@ -216,10 +211,10 @@ public class TaskManager {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public BuiltInTask findBuiltInTaskByClass(Class<? extends BuiltInTask> clazz) { public WithButton findButtonTaskByClass(Class<? extends WithButton> clazz) {
return tasks.values().stream() return tasks.values().stream()
.filter(clazz::isInstance) .filter(clazz::isInstance)
.map(task -> (BuiltInTask) task) .map(task -> (WithButton) task)
.findFirst() .findFirst()
.orElse(null); .orElse(null);
} }
@@ -237,22 +232,27 @@ public class TaskManager {
private void loadBuiltInTasks() { private void loadBuiltInTasks() {
logger.info("Loading built-in tasks..."); logger.info("Loading built-in tasks...");
Set<Class<? extends BuiltInTask>> classes = new Reflections("me.bobert.netneutrality.tasks").getSubTypesOf(BuiltInTask.class); ReflectionHelper.loadTasks(BuiltInTask.class, builtInTask -> {
for (Class<? extends BuiltInTask> s : classes) { if (builtInTask.isInsertable()) {
try { logger.info("Loaded task: {}", builtInTask.getClass().getName());
if (Modifier.isAbstract(s.getModifiers())) { tasks.put(builtInTask.getId(), builtInTask);
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);
} }
} });
}
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) { private void deleteInteraction(Task task) {
@@ -1,4 +1,4 @@
package me.bobert.netneutrality.core.tasks; package me.bobert.netneutrality.core.tasks.impl;
/* /*
* Copyright (c) anthorob * 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.CommandContext;
import me.bobert.netneutrality.core.context.TaskContext; import me.bobert.netneutrality.core.context.TaskContext;
import me.bobert.netneutrality.core.tasks.BuiltInTask;
public abstract class AbstractBuiltInTask extends AbstractTask implements BuiltInTask { public abstract class AbstractBuiltInTask extends AbstractTask implements BuiltInTask {
@@ -35,6 +36,4 @@ public abstract class AbstractBuiltInTask extends AbstractTask implements BuiltI
executeTask(context); executeTask(context);
return Lifecycle.BUILTIN; return Lifecycle.BUILTIN;
} }
public abstract void executeTask(TaskContext context);
} }
@@ -1,4 +1,4 @@
package me.bobert.netneutrality.core.tasks; package me.bobert.netneutrality.core.tasks.impl;
/* /*
* Copyright (c) anthorob * 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.context.CommandContext;
import me.bobert.netneutrality.core.tasks.PersistableTask;
import me.bobert.netneutrality.core.tasks.TaskManager;
import org.json.JSONObject; import org.json.JSONObject;
public abstract class AbstractPersistableTask extends AbstractTask implements PersistableTask { public abstract class AbstractPersistableTask extends AbstractTask implements PersistableTask {
@@ -9,13 +9,11 @@ package me.bobert.netneutrality.core.tasks.impl;
import me.bobert.netneutrality.core.context.CommandContext; import me.bobert.netneutrality.core.context.CommandContext;
import me.bobert.netneutrality.core.context.MessageContext; import me.bobert.netneutrality.core.context.MessageContext;
import me.bobert.netneutrality.core.context.TaskContext; import me.bobert.netneutrality.core.context.TaskContext;
import me.bobert.netneutrality.core.tasks.AbstractTask; import me.bobert.netneutrality.core.tasks.StepTask;
import me.bobert.netneutrality.core.tasks.IStepTask;
import me.bobert.netneutrality.core.tasks.TaskManager; import me.bobert.netneutrality.core.tasks.TaskManager;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.Role; 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.Emoji;
import net.fellbaum.jemoji.EmojiManager; 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) * 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. * 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 final Object stepLock = new Object();
private CommandContext commandContext; private CommandContext commandContext;
private Guild guild; private Guild guild;
@@ -110,11 +108,6 @@ public abstract class StepTask extends AbstractTask implements IStepTask {
return getCreationTime().plusMinutes(60).isBefore(OffsetDateTime.now()); return getCreationTime().plusMinutes(60).isBefore(OffsetDateTime.now());
} }
@Override
public Button createButton() {
return null;
}
/** /**
* Validates the user input against the expected step type. * Validates the user input against the expected step type.
* *
@@ -1,4 +1,4 @@
package me.bobert.netneutrality.core.tasks; package me.bobert.netneutrality.core.tasks.impl;
/* /*
* Copyright (c) anthorob * 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.context.CommandContext;
import me.bobert.netneutrality.core.tasks.Task;
import me.bobert.netneutrality.core.tasks.TaskManager;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.Objects; import java.util.Objects;
@@ -5,49 +5,40 @@ package me.bobert.netneutrality.core.tasks.impl;
* https://discord.gg/qUa6zNFZsd * https://discord.gg/qUa6zNFZsd
*/ */
import me.bobert.netneutrality.core.tasks.GenericRandomIdTask;
import me.bobert.netneutrality.core.tasks.Task; import me.bobert.netneutrality.core.tasks.Task;
import me.bobert.netneutrality.core.tasks.trait.WithChildren; import me.bobert.netneutrality.core.tasks.trait.WithButton;
import net.dv8tion.jda.api.interactions.components.ActionRow; 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.Button;
import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
import java.time.OffsetDateTime; 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 ButtonStyle buttonStyle;
private final String buttonLabel; private final String buttonLabel;
private Emoji emoji;
public ButtonTask(ButtonStyle buttonStyle, String buttonLabel) { public ButtonTask(ButtonStyle buttonStyle, String buttonLabel) {
this.buttonStyle = buttonStyle; this.buttonStyle = buttonStyle;
this.buttonLabel = buttonLabel; this.buttonLabel = buttonLabel;
} }
public Task setEmoji(Emoji emoji) {
this.emoji = emoji;
return this;
}
@Override @Override
public Button createButton() { public Button createButton() {
if (buttonStyle == null || buttonLabel == null) { if (buttonStyle == null || buttonLabel == null) {
return null; return null;
} }
return Button.of(buttonStyle, getId(), buttonLabel); return Button.of(buttonStyle, getId(), buttonLabel, emoji);
} }
@Override @Override
public boolean isExpired() { public boolean isExpired() {
return getCreationTime().plusMinutes(15).isBefore(OffsetDateTime.now()); return getCreationTime().plusMinutes(15).isBefore(OffsetDateTime.now());
} }
public ActionRow createActionRow(List<Task> 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));
}
} }
@@ -6,8 +6,6 @@ package me.bobert.netneutrality.core.tasks.impl;
*/ */
import me.bobert.netneutrality.context.tasks.EmojiTaskContext; 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.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@@ -54,9 +52,4 @@ public abstract class EmojiTask extends AbstractPersistableTask {
public String getId() { public String getId() {
return String.format(EmojiTaskContext.ID, getGuildId(), getMessageId()); return String.format(EmojiTaskContext.ID, getGuildId(), getMessageId());
} }
@Override
public Button createButton() {
return null;
}
} }
@@ -1,4 +1,4 @@
package me.bobert.netneutrality.core.tasks; package me.bobert.netneutrality.core.tasks.impl;
/* /*
* Copyright (c) anthorob * Copyright (c) anthorob
@@ -6,8 +6,6 @@ package me.bobert.netneutrality.core.tasks;
* https://discord.gg/qUa6zNFZsd * https://discord.gg/qUa6zNFZsd
*/ */
import net.dv8tion.jda.api.interactions.components.buttons.Button;
public abstract class GenericCustomIdTask extends AbstractTask { public abstract class GenericCustomIdTask extends AbstractTask {
private final String customId; private final String customId;
@@ -19,9 +17,4 @@ public abstract class GenericCustomIdTask extends AbstractTask {
public String getId() { public String getId() {
return customId; return customId;
} }
@Override
public Button createButton() {
return null;
}
} }
@@ -1,4 +1,4 @@
package me.bobert.netneutrality.core.tasks; package me.bobert.netneutrality.core.tasks.impl;
/* /*
* Copyright (c) anthorob * Copyright (c) anthorob
@@ -6,7 +6,6 @@ package me.bobert.netneutrality.core.tasks.impl;
*/ */
import me.bobert.netneutrality.core.context.TaskContext; import me.bobert.netneutrality.core.context.TaskContext;
import me.bobert.netneutrality.core.tasks.GenericRandomIdTask;
import net.dv8tion.jda.api.interactions.modals.ModalMapping; import net.dv8tion.jda.api.interactions.modals.ModalMapping;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
@@ -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<Task> 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));
}
}
@@ -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<String, ScheduledFuture<?>> 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();
}
}
@@ -15,12 +15,9 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import dev.lavalink.youtube.YoutubeAudioSourceManager; import dev.lavalink.youtube.YoutubeAudioSourceManager;
import me.bobert.netneutrality.core.command.CommandExecutionResult; import me.bobert.netneutrality.core.command.CommandExecutionResult;
import me.bobert.netneutrality.core.context.CommandContext; 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.GSettings;
import me.bobert.netneutrality.db.service.GuildService; import me.bobert.netneutrality.db.service.GuildService;
import me.bobert.netneutrality.music.source.UdioAudioSourceManager; 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.MusicUtils;
import me.bobert.netneutrality.utils.Settings; import me.bobert.netneutrality.utils.Settings;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
@@ -31,7 +28,6 @@ import org.apache.logging.log4j.Logger;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
public class MusicManager { public class MusicManager {
@@ -72,9 +68,6 @@ public class MusicManager {
String po = Settings.getInstance().get("NETNEUTRALITY_PO_TOKEN"); String po = Settings.getInstance().get("NETNEUTRALITY_PO_TOKEN");
String visitor = Settings.getInstance().get("NETNEUTRALITY_VISITOR_DATA"); String visitor = Settings.getInstance().get("NETNEUTRALITY_VISITOR_DATA");
dev.lavalink.youtube.clients.Web.setPoTokenAndVisitorData(po, visitor); 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() { public static void disconnectPlayers() {
@@ -6,10 +6,12 @@ package me.bobert.netneutrality.tasks.help;
*/ */
import me.bobert.netneutrality.core.context.TaskContext; 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; import net.dv8tion.jda.api.interactions.components.buttons.Button;
public class BotInfo extends AbstractBuiltInTask { public class BotInfo extends AbstractBuiltInTask implements WithButton {
@Override @Override
public String getId() { public String getId() {
@@ -23,7 +25,7 @@ public class BotInfo extends AbstractBuiltInTask {
@Override @Override
public void executeTask(TaskContext context) { public void executeTask(TaskContext context) {
context.sendMessageInPrivate("For information about the bot and to follow the development, " + context.replyEphemeral("For information about the bot and to follow the development, " +
"you can join the discord here: https://discord.gg/udVJwTgV"); "you can join the discord here: " + Settings.getDiscordInvite());
} }
} }
@@ -6,12 +6,13 @@ package me.bobert.netneutrality.tasks.help;
*/ */
import me.bobert.netneutrality.core.context.TaskContext; 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.MessageFunction;
import me.bobert.netneutrality.utils.Settings; import me.bobert.netneutrality.utils.Settings;
import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.components.buttons.Button;
public class CommandHelp extends AbstractBuiltInTask { public class CommandHelp extends AbstractBuiltInTask implements WithButton {
@Override @Override
public String getId() { public String getId() {
@@ -6,10 +6,12 @@ package me.bobert.netneutrality.tasks.help;
*/ */
import me.bobert.netneutrality.core.context.TaskContext; 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; import net.dv8tion.jda.api.interactions.components.buttons.Button;
public class ReportBug extends AbstractBuiltInTask { public class ReportBug extends AbstractBuiltInTask implements WithButton {
@Override @Override
public String getId() { public String getId() {
@@ -23,7 +25,7 @@ public class ReportBug extends AbstractBuiltInTask {
@Override @Override
public void executeTask(TaskContext context) { public void executeTask(TaskContext context) {
context.sendMessageInPrivate("To report a bug with the bot, you can either use the /report-bug command " + context.replyEphemeral("To report a bug with the bot, you can either use the /report-bug command " +
"or join the discord here: https://discord.gg/udVJwTgV"); "or join the discord here: " + Settings.getDiscordInvite());
} }
} }
@@ -109,15 +109,12 @@ public class LoadPlaylistTask extends ButtonTask implements WithChildren, Deleta
} }
return Lifecycle.KEEP; return Lifecycle.KEEP;
}); }).setEmoji(Emoji.fromFormatted("U+1F60E"));
Task cancel = CancelButton.create(this, cancelText, context -> Lifecycle.REMOVE_SELF_AND_CHILDREN); Task cancel = CancelButton.create(this, cancelText, context -> Lifecycle.REMOVE_SELF_AND_CHILDREN)
addChild(accept, cancel); .setEmoji(Emoji.fromFormatted("U+1F92E"));
return ActionRow.of( return createActionRow(accept, cancel);
accept.createButton().withEmoji(Emoji.fromFormatted("U+1F60E")),
cancel.createButton().withEmoji(Emoji.fromFormatted("U+1F92E"))
);
} }
@Override @Override
@@ -6,11 +6,11 @@ package me.bobert.netneutrality.tasks.reaction;
* https://discord.gg/qUa6zNFZsd * 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.Message;
import net.dv8tion.jda.api.entities.Role; import net.dv8tion.jda.api.entities.Role;
public class EmojiRoleFirstStep extends StepTask { public class EmojiRoleFirstStep extends AbstractStepTask {
private final Message target; private final Message target;
public EmojiRoleFirstStep(Message target) { public EmojiRoleFirstStep(Message target) {
@@ -74,7 +74,7 @@ public class EmojiRoleModify extends ButtonTask implements WithChildren {
}); });
ActionRow row = createActionRow(addEmojiTask, removeEmojiTask, deleteMappingTask); 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 @Override
@@ -6,14 +6,14 @@ package me.bobert.netneutrality.tasks.reaction;
* https://discord.gg/qUa6zNFZsd * 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 me.bobert.netneutrality.tasks.emoji.EmojiReactionRoleTask;
import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.Message;
import java.util.Set; import java.util.Set;
import java.util.StringJoiner; import java.util.StringJoiner;
public class EmojiRoleRemoveStep extends StepTask { public class EmojiRoleRemoveStep extends AbstractStepTask {
private final Message target; private final Message target;
private final EmojiReactionRoleTask task; private final EmojiReactionRoleTask task;
@@ -22,6 +22,11 @@ public class EmojiRoleRemoveStep extends StepTask {
this.task = task; this.task = task;
} }
@Override
public String getName() {
return "emoji-role-remove";
}
@Override @Override
public StepType getStepType() { public StepType getStepType() {
return StepType.EMOJI; return StepType.EMOJI;
@@ -54,9 +59,4 @@ public class EmojiRoleRemoveStep extends StepTask {
task.removeEmoji(emoji); task.removeEmoji(emoji);
return StepResult.success("Removed emoji successfully!"); return StepResult.success("Removed emoji successfully!");
} }
@Override
public String getName() {
return "emoji-role-remove";
}
} }
@@ -8,14 +8,14 @@ package me.bobert.netneutrality.tasks.reaction;
import me.bobert.netneutrality.core.tasks.Task; import me.bobert.netneutrality.core.tasks.Task;
import me.bobert.netneutrality.core.tasks.TaskManager; 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 me.bobert.netneutrality.tasks.emoji.EmojiReactionRoleTask;
import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.Role; import net.dv8tion.jda.api.entities.Role;
import java.util.Map; import java.util.Map;
public class EmojiRoleSecondStep extends StepTask { public class EmojiRoleSecondStep extends AbstractStepTask {
private final Message target; private final Message target;
private final Role role; private final Role role;
@@ -1,27 +1,35 @@
package me.bobert.netneutrality.thread; package me.bobert.netneutrality.tasks.scheduled;
/* /*
* Copyright (c) anthorob * Copyright (c) anthorob
* *
* https://discord.gg/qUa6zNFZsd * https://discord.gg/qUa6zNFZsd
*/ */
import me.bobert.netneutrality.core.tasks.ScheduledTask;
import me.bobert.netneutrality.music.MusicManager; import me.bobert.netneutrality.music.MusicManager;
import me.bobert.netneutrality.music.TrackScheduler; import me.bobert.netneutrality.music.TrackScheduler;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
public class MusicManagerCleanupThread implements Runnable { public class MusicManagerCleanup implements ScheduledTask {
private static final Logger logger = LogManager.getLogger(MusicManagerCleanupThread.class); private static final Logger logger = LogManager.getLogger(MusicManagerCleanup.class);
@Override
public String getId() {
return "MusicManagerCleanup";
}
@Override
public TimeFrame getTimeFrame() {
return TimeFrame.hourly();
}
@Override @Override
public void run() { public void run() {
try { try {
for (MusicManager manager : MusicManager.getManagers()) { for (MusicManager manager : MusicManager.getManagers()) {
processManager(manager); processManager(manager);
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
logger.error("Interrupted while running MusicManagerCleanupThread", e); logger.error("Interrupted while running MusicManagerCleanupThread", e);
} }
@@ -1,10 +1,12 @@
package me.bobert.netneutrality.thread; package me.bobert.netneutrality.tasks.scheduled;
/* /*
* Copyright (c) anthorob * Copyright (c) anthorob
* *
* https://discord.gg/qUa6zNFZsd * https://discord.gg/qUa6zNFZsd
*/ */
import me.bobert.netneutrality.core.tasks.ScheduledTask;
import me.bobert.netneutrality.music.MusicManager; import me.bobert.netneutrality.music.MusicManager;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.channel.middleman.AudioChannel; import net.dv8tion.jda.api.entities.channel.middleman.AudioChannel;
@@ -13,17 +15,25 @@ import org.apache.logging.log4j.Logger;
import java.util.List; import java.util.List;
public class MusicPlayerAutoDisconnectThread implements Runnable { public class MusicPlayerAutoDisconnect implements ScheduledTask {
private static final Logger logger = LogManager.getLogger(MusicPlayerAutoDisconnectThread.class); private static final Logger logger = LogManager.getLogger(MusicPlayerAutoDisconnect.class);
@Override
public String getId() {
return "MusicPlayerAutoDisconnect";
}
@Override
public TimeFrame getTimeFrame() {
return TimeFrame.minutely(15);
}
@Override @Override
public void run() { public void run() {
try { try {
for (MusicManager manager : MusicManager.getManagers()) { for (MusicManager manager : MusicManager.getManagers()) {
processManager(manager); processManager(manager);
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
logger.error("Interrupted while running MusicPlayerAutoDisconnectThread", e); logger.error("Interrupted while running MusicPlayerAutoDisconnectThread", e);
} }
@@ -1,4 +1,4 @@
package me.bobert.netneutrality.thread;/* package me.bobert.netneutrality.tasks.scheduled;/*
* Copyright (c) anthorob * Copyright (c) anthorob
* *
* https://discord.gg/qUa6zNFZsd * 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.BuiltInTask;
import me.bobert.netneutrality.core.tasks.PersistableTask; 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.Task;
import me.bobert.netneutrality.core.tasks.TaskManager; import me.bobert.netneutrality.core.tasks.TaskManager;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@@ -13,8 +14,18 @@ import org.apache.logging.log4j.Logger;
import java.util.List; import java.util.List;
public class CleanupTaskThread implements Runnable { public class TaskCleanup implements ScheduledTask {
private static final Logger logger = LogManager.getLogger(CleanupTaskThread.class); private static final Logger logger = LogManager.getLogger(TaskCleanup.class);
@Override
public String getId() {
return "TaskCleanup";
}
@Override
public TimeFrame getTimeFrame() {
return TimeFrame.minutely(5);
}
@Override @Override
public void run() { public void run() {
@@ -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();
}
}
}
@@ -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<Class<?>, Exception> DEFAULT_FAILURE = (aClass, e) -> logger.error("Failed to load class: {}", aClass.getName(), e);
public static <E> void loadClassesFromPackage(String packageName, Class<E> clazz, Consumer<E> onInstanciated, BiConsumer<Class<?>, Exception> onFailed) {
Set<Class<? extends E>> classes = new Reflections(packageName).getSubTypesOf(clazz);
for (Class<? extends E> 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 <E> void loadCommands(Class<E> clazz, Consumer<E> onInstanciated, BiConsumer<Class<?>, Exception> onFailed) {
loadClassesFromPackage("me.bobert.netneutrality.command", clazz, onInstanciated, onFailed);
}
public static <E> void loadCommands(Class<E> clazz, Consumer<E> onInstanciated) {
loadClassesFromPackage("me.bobert.netneutrality.command", clazz, onInstanciated, DEFAULT_FAILURE);
}
public static <E> void loadTasks(Class<E> clazz, Consumer<E> onInstanciated, BiConsumer<Class<?>, Exception> onFailed) {
loadClassesFromPackage("me.bobert.netneutrality.tasks", clazz, onInstanciated, onFailed);
}
public static <E> void loadTasks(Class<E> clazz, Consumer<E> onInstanciated) {
loadClassesFromPackage("me.bobert.netneutrality.tasks", clazz, onInstanciated, DEFAULT_FAILURE);
}
}
@@ -54,6 +54,10 @@ public class Settings {
return INSTANCE; return INSTANCE;
} }
public static String getDiscordInvite() {
return Settings.getInstance().get("NETNEUTRALITY_BOT_INVITE", "https://discord.gg/PyCpd7JGMp");
}
public static String getVersion() { public static String getVersion() {
return Settings.getInstance().getMavenVersion(); return Settings.getInstance().getMavenVersion();
} }