From fdb1c0b093b591e376664b2f8cfb430f7c2b046c Mon Sep 17 00:00:00 2001 From: Logan Fick Date: Tue, 25 Jun 2019 10:20:55 -0400 Subject: [PATCH] Moved many operations to single main thread. --- src/main/java/dev/logal/logalbot/Main.java | 8 ++- .../java/dev/logal/logalbot/MainThread.java | 61 +++++++++++++++++++ .../dev/logal/logalbot/MainThreadFactory.java | 30 +++++++++ .../logalbot/audio/TrackLoadHandler.java | 24 +++++--- .../logal/logalbot/audio/TrackScheduler.java | 36 +++++++---- .../logalbot/commands/CommandResponse.java | 6 +- .../logal/logalbot/commands/audio/Queue.java | 9 ++- .../logal/logalbot/commands/audio/Remove.java | 6 +- .../events/GuildMessageReactionAdd.java | 7 ++- .../logalbot/events/GuildMessageReceived.java | 7 ++- .../logalbot/events/GuildVoiceLeave.java | 7 +-- .../logal/logalbot/events/GuildVoiceMove.java | 7 +-- ...ask.java => CloseAudioConnectionTask.java} | 4 +- .../logalbot/tasks/CommandExecutionTask.java | 41 +++++++++++++ .../logalbot/tasks/MessageDeleteTask.java | 1 - .../tasks/OpenAudioConnectionTask.java | 34 +++++++++++ .../logalbot/tasks/PlayNextTrackTask.java | 34 +++++++++++ .../tasks/ReactionCallbackExecutionTask.java | 45 ++++++++++++++ .../logalbot/tasks/ResetAudioPlayerTask.java | 35 +++++++++++ .../logalbot/tasks/TrackAdditionTask.java | 54 ++++++++++++++++ .../dev/logal/logalbot/utils/AudioUtil.java | 9 +++ .../dev/logal/logalbot/utils/Scheduler.java | 48 --------------- 22 files changed, 417 insertions(+), 96 deletions(-) create mode 100644 src/main/java/dev/logal/logalbot/MainThread.java create mode 100644 src/main/java/dev/logal/logalbot/MainThreadFactory.java rename src/main/java/dev/logal/logalbot/tasks/{IdleDisconnectTask.java => CloseAudioConnectionTask.java} (88%) create mode 100644 src/main/java/dev/logal/logalbot/tasks/CommandExecutionTask.java create mode 100644 src/main/java/dev/logal/logalbot/tasks/OpenAudioConnectionTask.java create mode 100644 src/main/java/dev/logal/logalbot/tasks/PlayNextTrackTask.java create mode 100644 src/main/java/dev/logal/logalbot/tasks/ReactionCallbackExecutionTask.java create mode 100644 src/main/java/dev/logal/logalbot/tasks/ResetAudioPlayerTask.java create mode 100644 src/main/java/dev/logal/logalbot/tasks/TrackAdditionTask.java delete mode 100644 src/main/java/dev/logal/logalbot/utils/Scheduler.java diff --git a/src/main/java/dev/logal/logalbot/Main.java b/src/main/java/dev/logal/logalbot/Main.java index e12197a..8b18b37 100644 --- a/src/main/java/dev/logal/logalbot/Main.java +++ b/src/main/java/dev/logal/logalbot/Main.java @@ -31,7 +31,7 @@ import net.dv8tion.jda.core.AccountType; import net.dv8tion.jda.core.JDA; import net.dv8tion.jda.core.JDABuilder; -public final class Main { +public final class Main implements Runnable { private static final Logger logger = LoggerFactory.getLogger(Main.class); private static final String token = System.getenv("TOKEN"); @@ -42,6 +42,11 @@ public final class Main { } public static final void main(final String[] arguments) { + MainThread.scheduleImmediately(new Main()); + } + + @Override + public final void run() { logger.info("Beginning setup of LogalBot..."); logger.info("Verifying connection to Redis..."); @@ -93,6 +98,7 @@ public final class Main { CommandManager.registerCommandAlias("die", "dice"); CommandManager.registerCommandAlias("random", "dice"); CommandManager.registerCommandAlias("rng", "dice"); + CommandManager.registerCommandAlias("roll", "dice"); CommandManager.registerCommand("8ball", new EightBall(), false); // Audio Commands diff --git a/src/main/java/dev/logal/logalbot/MainThread.java b/src/main/java/dev/logal/logalbot/MainThread.java new file mode 100644 index 0000000..702afcf --- /dev/null +++ b/src/main/java/dev/logal/logalbot/MainThread.java @@ -0,0 +1,61 @@ +package dev.logal.logalbot; + +// Copyright 2019 Logan Fick + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import net.dv8tion.jda.core.utils.Checks; + +public final class MainThread { + private static final ScheduledExecutorService mainThread = Executors + .newSingleThreadScheduledExecutor(new MainThreadFactory()); + + public static final void scheduleImmediately(final Runnable task) { + Checks.notNull(task, "Task"); + + mainThread.schedule(task, 0, TimeUnit.MICROSECONDS); + } + + public static final ScheduledFuture scheduleLater(final Runnable task, final long delay, final TimeUnit unit) { + Checks.notNull(task, "Task"); + Checks.notNegative(delay, "Delay"); + Checks.notNull(unit, "Unit"); + + return mainThread.schedule(task, delay, unit); + } + + public static final ScheduledFuture scheduleRepeatedlyAtFixedRate(final Runnable task, final long initialDelay, + final long period, final TimeUnit unit) { + Checks.notNull(task, "Task"); + Checks.notNegative(initialDelay, "Initial Delay"); + Checks.notNegative(period, "Period"); + Checks.notNull(unit, "Unit"); + + return mainThread.scheduleAtFixedRate(task, initialDelay, period, unit); + } + + public static final ScheduledFuture scheduleRepeatedlyWithFixedDelay(final Runnable task, + final long initialDelay, final long period, final TimeUnit unit) { + Checks.notNull(task, "Task"); + Checks.notNegative(initialDelay, "Initial Delay"); + Checks.notNegative(period, "Period"); + Checks.notNull(unit, "Unit"); + + return mainThread.scheduleWithFixedDelay(task, initialDelay, period, unit); + } +} \ No newline at end of file diff --git a/src/main/java/dev/logal/logalbot/MainThreadFactory.java b/src/main/java/dev/logal/logalbot/MainThreadFactory.java new file mode 100644 index 0000000..8097655 --- /dev/null +++ b/src/main/java/dev/logal/logalbot/MainThreadFactory.java @@ -0,0 +1,30 @@ +package dev.logal.logalbot; + +// Copyright 2019 Logan Fick + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import java.util.concurrent.ThreadFactory; + +import net.dv8tion.jda.core.utils.Checks; + +public final class MainThreadFactory implements ThreadFactory { + @Override + public final Thread newThread(final Runnable runnable) { + Checks.notNull(runnable, "Runnable"); + + final Thread newThread = new Thread(runnable); + newThread.setName("Main Thread"); + return newThread; + } +} \ No newline at end of file diff --git a/src/main/java/dev/logal/logalbot/audio/TrackLoadHandler.java b/src/main/java/dev/logal/logalbot/audio/TrackLoadHandler.java index 1642e79..c326d34 100644 --- a/src/main/java/dev/logal/logalbot/audio/TrackLoadHandler.java +++ b/src/main/java/dev/logal/logalbot/audio/TrackLoadHandler.java @@ -26,7 +26,9 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import dev.logal.logalbot.MainThread; import dev.logal.logalbot.commands.CommandResponse; +import dev.logal.logalbot.tasks.TrackAdditionTask; import dev.logal.logalbot.utils.AudioUtil; import dev.logal.logalbot.utils.PermissionManager; import dev.logal.logalbot.utils.TrackUtil; @@ -54,7 +56,8 @@ public final class TrackLoadHandler implements AudioLoadResultHandler { Checks.notNull(track, "Track"); final CommandResponse response; - final TrackScheduler scheduler = AudioUtil.getTrackScheduler(this.channel.getGuild()); + final Guild guild = this.channel.getGuild(); + final TrackScheduler scheduler = AudioUtil.getTrackScheduler(guild); final AudioTrackInfo info = track.getInfo(); if (info.isStream) { @@ -83,7 +86,7 @@ public final class TrackLoadHandler implements AudioLoadResultHandler { } final RequestedTrack requestedTrack = new RequestedTrack(track, requester); - scheduler.addToQueue(requestedTrack); + MainThread.scheduleImmediately(new TrackAdditionTask(guild, requestedTrack)); response = new CommandResponse("notes", this.requester.getAsMention() + " added the following track to the queue:"); response.attachEmbed(TrackUtil.trackInfoEmbed(requestedTrack)); @@ -95,7 +98,8 @@ public final class TrackLoadHandler implements AudioLoadResultHandler { Checks.notNull(playlist, "Playlist"); CommandResponse response; - final TrackScheduler scheduler = AudioUtil.getTrackScheduler(this.channel.getGuild()); + final Guild guild = this.channel.getGuild(); + final TrackScheduler scheduler = AudioUtil.getTrackScheduler(guild); final AudioTrack selectedTrack = playlist.getSelectedTrack(); final AudioTrack track; @@ -141,20 +145,19 @@ public final class TrackLoadHandler implements AudioLoadResultHandler { } } else { if (PermissionManager.isWhitelisted(this.requester)) { - final LinkedList addedTracks = new LinkedList<>(); + final LinkedList tracksToAdd = new LinkedList<>(); + int count = 0; for (final AudioTrack playlistTrack : playlist.getTracks()) { - if (!scheduler.isQueueFull()) { + if (count++ != 250) { if (!scheduler.isQueued(playlistTrack) && !playlistTrack.getInfo().isStream) { - final RequestedTrack requestedTrack = new RequestedTrack(playlistTrack, requester); - scheduler.addToQueue(requestedTrack); - addedTracks.add(requestedTrack); + tracksToAdd.add(new RequestedTrack(playlistTrack, requester)); } } else { break; } } - if (addedTracks.size() == 0) { + if (tracksToAdd.size() == 0) { response = new CommandResponse("x", "Sorry " + this.requester.getAsMention() + ", but none of the tracks in that playlist could be added to the queue.") @@ -162,9 +165,10 @@ public final class TrackLoadHandler implements AudioLoadResultHandler { response.sendResponse(this.channel); } + MainThread.scheduleImmediately(new TrackAdditionTask(guild, tracksToAdd)); response = new CommandResponse("notes", this.requester.getAsMention() + " added the following tracks from a playlist to the queue:"); - response.attachEmbed(TrackUtil.trackListInfoEmbed(addedTracks, false)); + response.attachEmbed(TrackUtil.trackListInfoEmbed(tracksToAdd, false)); response.sendResponse(this.channel); } else { response = new CommandResponse("x", diff --git a/src/main/java/dev/logal/logalbot/audio/TrackScheduler.java b/src/main/java/dev/logal/logalbot/audio/TrackScheduler.java index 8531f67..470a291 100644 --- a/src/main/java/dev/logal/logalbot/audio/TrackScheduler.java +++ b/src/main/java/dev/logal/logalbot/audio/TrackScheduler.java @@ -27,11 +27,13 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import dev.logal.logalbot.tasks.IdleDisconnectTask; +import dev.logal.logalbot.MainThread; +import dev.logal.logalbot.tasks.CloseAudioConnectionTask; +import dev.logal.logalbot.tasks.OpenAudioConnectionTask; +import dev.logal.logalbot.tasks.PlayNextTrackTask; import dev.logal.logalbot.utils.AudioUtil; import dev.logal.logalbot.utils.DataManager; import dev.logal.logalbot.utils.PermissionManager; -import dev.logal.logalbot.utils.Scheduler; import dev.logal.logalbot.utils.SkipTracker; import dev.logal.logalbot.utils.VoiceChannelUtil; import net.dv8tion.jda.core.entities.Guild; @@ -46,7 +48,7 @@ public final class TrackScheduler extends AudioEventAdapter { private final Guild guild; private final LinkedList queue = new LinkedList<>(); private boolean queueLocked = false; - private ScheduledFuture idleLogoutTask; + private ScheduledFuture closeAudioConnectionTask; public TrackScheduler(final Guild guild) { Checks.notNull(guild, "Guild"); @@ -71,12 +73,17 @@ public final class TrackScheduler extends AudioEventAdapter { logger.info(user.getName() + " (" + user.getId() + ") added '" + track.getInfo().title + "' to the queue in " + this.guild.getName() + " (" + this.guild.getId() + ")."); - if (!AudioUtil.isTrackLoaded(this.guild)) { - AudioUtil.openAudioConnection(VoiceChannelUtil.getVoiceChannelMemberIsConnectedTo(requester)); - AudioUtil.playTrack(this.guild, requestedTrack); - } else { - this.queue.add(requestedTrack); + final VoiceChannel targetChannel = VoiceChannelUtil.getVoiceChannelMemberIsConnectedTo(requester); + if (!AudioUtil.isAudioConnectionOpen(this.guild) + || targetChannel != AudioUtil.getVoiceChannelConnectedTo(this.guild)) { + MainThread.scheduleImmediately( + new OpenAudioConnectionTask(VoiceChannelUtil.getVoiceChannelMemberIsConnectedTo(requester))); } + + if (!AudioUtil.isTrackLoaded(this.guild) && this.queue.size() == 0) { + MainThread.scheduleImmediately(new PlayNextTrackTask(this.guild)); + } + this.queue.add(requestedTrack); } public final void removeFromQueue(final int index) { @@ -121,6 +128,10 @@ public final class TrackScheduler extends AudioEventAdapter { Collections.shuffle(this.queue); } + public final RequestedTrack popFromQueue() { + return this.queue.remove(0); + } + public final int occupiedSlotCount(Member member) { Checks.notNull(member, "Member"); @@ -152,10 +163,10 @@ public final class TrackScheduler extends AudioEventAdapter { logger.info("Track '" + track.getInfo().title + "' in " + this.guild.getName() + " (" + this.guild.getId() + ") has started."); - if (this.idleLogoutTask != null && !this.idleLogoutTask.isDone()) { + if (this.closeAudioConnectionTask != null && !this.closeAudioConnectionTask.isDone()) { logger.info("A track has started in " + this.guild.getName() + " (" + this.guild.getId() + "). Cancelling scheduled disconnect."); - this.idleLogoutTask.cancel(true); + this.closeAudioConnectionTask.cancel(true); } SkipTracker.resetVotes(this.guild); } @@ -170,7 +181,7 @@ public final class TrackScheduler extends AudioEventAdapter { logger.info("Track '" + track.getInfo().title + "' in " + this.guild.getName() + " (" + this.guild.getId() + ") has stopped."); if ((endReason.mayStartNext || endReason == AudioTrackEndReason.STOPPED) && this.queue.size() >= 1) { - AudioUtil.playTrack(this.guild, this.queue.remove(0)); + MainThread.scheduleImmediately(new PlayNextTrackTask(this.guild)); } else { try { AudioUtil.setVolume(this.guild, Integer.parseInt(DataManager.getGuildValue(guild, "defaultVolume"))); @@ -182,7 +193,8 @@ public final class TrackScheduler extends AudioEventAdapter { final VoiceChannel currentChannel = AudioUtil.getVoiceChannelConnectedTo(this.guild); logger.info("Disconnecting from " + currentChannel.getName() + " (" + currentChannel.getId() + ") in " + this.guild.getName() + " (" + this.guild.getId() + ") in 1 minute..."); - this.idleLogoutTask = Scheduler.schedule(new IdleDisconnectTask(this.guild), 1, TimeUnit.MINUTES); + this.closeAudioConnectionTask = MainThread.scheduleLater(new CloseAudioConnectionTask(this.guild), 1, + TimeUnit.MINUTES); } SkipTracker.resetVotes(this.guild); } diff --git a/src/main/java/dev/logal/logalbot/commands/CommandResponse.java b/src/main/java/dev/logal/logalbot/commands/CommandResponse.java index 4495167..bec49c9 100644 --- a/src/main/java/dev/logal/logalbot/commands/CommandResponse.java +++ b/src/main/java/dev/logal/logalbot/commands/CommandResponse.java @@ -21,10 +21,10 @@ import java.util.concurrent.TimeUnit; import com.vdurmont.emoji.Emoji; import com.vdurmont.emoji.EmojiManager; +import dev.logal.logalbot.MainThread; import dev.logal.logalbot.tasks.MessageDeleteTask; import dev.logal.logalbot.tasks.ReactionCallbackExpireTask; import dev.logal.logalbot.utils.ReactionCallbackManager; -import dev.logal.logalbot.utils.Scheduler; import net.dv8tion.jda.core.MessageBuilder; import net.dv8tion.jda.core.entities.Member; import net.dv8tion.jda.core.entities.Message; @@ -106,9 +106,9 @@ public final class CommandResponse { private final void handleResponseCreation(final Message message) { if ((this.deletionDelay != 0) && (this.deletionDelayUnit != null)) { - Scheduler.schedule(new MessageDeleteTask(message), this.deletionDelay, this.deletionDelayUnit); + MainThread.scheduleLater(new MessageDeleteTask(message), this.deletionDelay, this.deletionDelayUnit); } else if ((this.expireDelay != 0) && (this.expireDelayUnit != null)) { - Scheduler.schedule(new ReactionCallbackExpireTask(message), this.expireDelay, this.expireDelayUnit); + MainThread.scheduleLater(new ReactionCallbackExpireTask(message), this.expireDelay, this.expireDelayUnit); } for (final Map.Entry callback : callbacks.entrySet()) { diff --git a/src/main/java/dev/logal/logalbot/commands/audio/Queue.java b/src/main/java/dev/logal/logalbot/commands/audio/Queue.java index 94bf40d..10d5409 100644 --- a/src/main/java/dev/logal/logalbot/commands/audio/Queue.java +++ b/src/main/java/dev/logal/logalbot/commands/audio/Queue.java @@ -17,11 +17,12 @@ package dev.logal.logalbot.commands.audio; import java.util.List; import java.util.concurrent.TimeUnit; +import dev.logal.logalbot.MainThread; import dev.logal.logalbot.audio.RequestedTrack; import dev.logal.logalbot.commands.Command; import dev.logal.logalbot.commands.CommandResponse; +import dev.logal.logalbot.tasks.CommandExecutionTask; import dev.logal.logalbot.utils.AudioUtil; -import dev.logal.logalbot.utils.CommandManager; import dev.logal.logalbot.utils.ReactionCallbackManager; import dev.logal.logalbot.utils.TrackUtil; import net.dv8tion.jda.core.entities.Guild; @@ -56,14 +57,16 @@ public final class Queue implements Command { if (page != 1) { response.addReactionCallback("arrow_left", (reactor, message) -> { ReactionCallbackManager.unregisterMessage(message, true); - CommandManager.executeCommand(("queue " + (page - 1)).split(" "), reactor, channel); + MainThread.scheduleImmediately( + new CommandExecutionTask(("queue " + (page - 1)).split(" "), reactor, channel)); }); } if (TrackUtil.doesGreaterPageExist(queue, page)) { response.addReactionCallback("arrow_right", (reactor, message) -> { ReactionCallbackManager.unregisterMessage(message, true); - CommandManager.executeCommand(("queue " + (page + 1)).split(" "), reactor, channel); + MainThread.scheduleImmediately( + new CommandExecutionTask(("queue " + (page + 1)).split(" "), reactor, channel)); }); } diff --git a/src/main/java/dev/logal/logalbot/commands/audio/Remove.java b/src/main/java/dev/logal/logalbot/commands/audio/Remove.java index 8334e18..7787e86 100644 --- a/src/main/java/dev/logal/logalbot/commands/audio/Remove.java +++ b/src/main/java/dev/logal/logalbot/commands/audio/Remove.java @@ -16,12 +16,13 @@ package dev.logal.logalbot.commands.audio; import java.util.concurrent.TimeUnit; +import dev.logal.logalbot.MainThread; import dev.logal.logalbot.audio.RequestedTrack; import dev.logal.logalbot.audio.TrackScheduler; import dev.logal.logalbot.commands.Command; import dev.logal.logalbot.commands.CommandResponse; +import dev.logal.logalbot.tasks.CommandExecutionTask; import dev.logal.logalbot.utils.AudioUtil; -import dev.logal.logalbot.utils.CommandManager; import dev.logal.logalbot.utils.ReactionCallbackManager; import dev.logal.logalbot.utils.StringUtil; import dev.logal.logalbot.utils.TrackUtil; @@ -69,7 +70,8 @@ public final class Remove implements Command { response.addReactionCallback(StringUtil.intToKeycapEmoji(trackNumber).getAliases().get(0), (reactor, message) -> { ReactionCallbackManager.unregisterMessage(message, true); - CommandManager.executeCommand(("remove " + trackNumber).split(" "), reactor, channel); + MainThread.scheduleImmediately( + new CommandExecutionTask(("remove " + trackNumber).split(" "), reactor, channel)); }); } diff --git a/src/main/java/dev/logal/logalbot/events/GuildMessageReactionAdd.java b/src/main/java/dev/logal/logalbot/events/GuildMessageReactionAdd.java index 6e133be..804a86e 100644 --- a/src/main/java/dev/logal/logalbot/events/GuildMessageReactionAdd.java +++ b/src/main/java/dev/logal/logalbot/events/GuildMessageReactionAdd.java @@ -14,7 +14,8 @@ package dev.logal.logalbot.events; // See the License for the specific language governing permissions and // limitations under the License. -import dev.logal.logalbot.utils.ReactionCallbackManager; +import dev.logal.logalbot.MainThread; +import dev.logal.logalbot.tasks.ReactionCallbackExecutionTask; import net.dv8tion.jda.core.events.message.guild.react.GuildMessageReactionAddEvent; import net.dv8tion.jda.core.hooks.ListenerAdapter; import net.dv8tion.jda.core.utils.Checks; @@ -25,8 +26,8 @@ public final class GuildMessageReactionAdd extends ListenerAdapter { Checks.notNull(event, "Event"); if (!event.getUser().equals(event.getJDA().getSelfUser())) { - ReactionCallbackManager.executeCallback(event.getMessageIdLong(), event.getChannel(), event.getMember(), - event.getReactionEmote().getName()); + MainThread.scheduleImmediately(new ReactionCallbackExecutionTask(event.getMessageIdLong(), + event.getChannel(), event.getMember(), event.getReactionEmote().getName())); } } } \ No newline at end of file diff --git a/src/main/java/dev/logal/logalbot/events/GuildMessageReceived.java b/src/main/java/dev/logal/logalbot/events/GuildMessageReceived.java index 88b03c0..1ec429a 100644 --- a/src/main/java/dev/logal/logalbot/events/GuildMessageReceived.java +++ b/src/main/java/dev/logal/logalbot/events/GuildMessageReceived.java @@ -17,7 +17,8 @@ package dev.logal.logalbot.events; import java.util.Arrays; import java.util.List; -import dev.logal.logalbot.utils.CommandManager; +import dev.logal.logalbot.MainThread; +import dev.logal.logalbot.tasks.CommandExecutionTask; import dev.logal.logalbot.utils.DataManager; import net.dv8tion.jda.core.Permission; import net.dv8tion.jda.core.entities.Guild; @@ -55,7 +56,7 @@ public final class GuildMessageReceived extends ListenerAdapter { if (self.hasPermission(channel, Permission.MESSAGE_MANAGE)) { message.delete().reason("LogalBot Command Execution").queue(); } - CommandManager.executeCommand(command, author, channel); + MainThread.scheduleImmediately(new CommandExecutionTask(command, author, channel)); } } else { final String commandCharacter = DataManager.getGuildValue(guild, "commandCharacter"); @@ -70,7 +71,7 @@ public final class GuildMessageReceived extends ListenerAdapter { if (self.hasPermission(channel, Permission.MESSAGE_MANAGE)) { message.delete().reason("LogalBot Command Execution").queue(); } - CommandManager.executeCommand(command, author, channel); + MainThread.scheduleImmediately(new CommandExecutionTask(command, author, channel)); } } } diff --git a/src/main/java/dev/logal/logalbot/events/GuildVoiceLeave.java b/src/main/java/dev/logal/logalbot/events/GuildVoiceLeave.java index bcb1a31..7cecec6 100644 --- a/src/main/java/dev/logal/logalbot/events/GuildVoiceLeave.java +++ b/src/main/java/dev/logal/logalbot/events/GuildVoiceLeave.java @@ -19,6 +19,8 @@ import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import dev.logal.logalbot.MainThread; +import dev.logal.logalbot.tasks.ResetAudioPlayerTask; import dev.logal.logalbot.utils.AudioUtil; import net.dv8tion.jda.core.entities.Guild; import net.dv8tion.jda.core.entities.Member; @@ -55,10 +57,7 @@ public final class GuildVoiceLeave extends ListenerAdapter { if (members.size() == 1 && members.get(0).getUser().equals(event.getJDA().getSelfUser())) { logger.info("All listeners left " + leftChannel.getName() + " (" + leftChannel.getId() + ") in " + guild.getName() + " (" + guild.getId() + ")."); - AudioUtil.getTrackScheduler(guild).clearQueue(); - if (AudioUtil.isTrackLoaded(guild)) { - AudioUtil.stopTrack(guild); - } + MainThread.scheduleImmediately(new ResetAudioPlayerTask(guild)); } } } diff --git a/src/main/java/dev/logal/logalbot/events/GuildVoiceMove.java b/src/main/java/dev/logal/logalbot/events/GuildVoiceMove.java index a8db4c5..5462f99 100644 --- a/src/main/java/dev/logal/logalbot/events/GuildVoiceMove.java +++ b/src/main/java/dev/logal/logalbot/events/GuildVoiceMove.java @@ -19,6 +19,8 @@ import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import dev.logal.logalbot.MainThread; +import dev.logal.logalbot.tasks.ResetAudioPlayerTask; import dev.logal.logalbot.utils.AudioUtil; import net.dv8tion.jda.core.entities.Guild; import net.dv8tion.jda.core.entities.Member; @@ -55,10 +57,7 @@ public final class GuildVoiceMove extends ListenerAdapter { if (members.size() == 1 && members.get(0).getUser().equals(event.getJDA().getSelfUser())) { logger.info("All listeners left " + leftChannel.getName() + " (" + leftChannel.getId() + ") in " + guild.getName() + " (" + guild.getId() + ")."); - AudioUtil.getTrackScheduler(guild).clearQueue(); - if (AudioUtil.isTrackLoaded(guild)) { - AudioUtil.stopTrack(guild); - } + MainThread.scheduleImmediately(new ResetAudioPlayerTask(guild)); } } } diff --git a/src/main/java/dev/logal/logalbot/tasks/IdleDisconnectTask.java b/src/main/java/dev/logal/logalbot/tasks/CloseAudioConnectionTask.java similarity index 88% rename from src/main/java/dev/logal/logalbot/tasks/IdleDisconnectTask.java rename to src/main/java/dev/logal/logalbot/tasks/CloseAudioConnectionTask.java index b645b34..e3ee3bb 100644 --- a/src/main/java/dev/logal/logalbot/tasks/IdleDisconnectTask.java +++ b/src/main/java/dev/logal/logalbot/tasks/CloseAudioConnectionTask.java @@ -18,10 +18,10 @@ import dev.logal.logalbot.utils.AudioUtil; import net.dv8tion.jda.core.entities.Guild; import net.dv8tion.jda.core.utils.Checks; -public final class IdleDisconnectTask implements Runnable { +public final class CloseAudioConnectionTask implements Runnable { private final Guild guild; - public IdleDisconnectTask(final Guild guild) { + public CloseAudioConnectionTask(final Guild guild) { Checks.notNull(guild, "Guild"); this.guild = guild; diff --git a/src/main/java/dev/logal/logalbot/tasks/CommandExecutionTask.java b/src/main/java/dev/logal/logalbot/tasks/CommandExecutionTask.java new file mode 100644 index 0000000..b16d9cf --- /dev/null +++ b/src/main/java/dev/logal/logalbot/tasks/CommandExecutionTask.java @@ -0,0 +1,41 @@ +package dev.logal.logalbot.tasks; + +// Copyright 2019 Logan Fick + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import dev.logal.logalbot.utils.CommandManager; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.utils.Checks; + +public final class CommandExecutionTask implements Runnable { + private final String[] command; + private final Member executor; + private final TextChannel channel; + + public CommandExecutionTask(final String[] command, final Member executor, final TextChannel channel) { + Checks.noneNull(command, "Command"); + Checks.notNull(executor, "Executor"); + Checks.notNull(channel, "Channel"); + + this.command = command; + this.executor = executor; + this.channel = channel; + } + + @Override + public final void run() { + CommandManager.executeCommand(this.command, this.executor, this.channel); + } +} \ No newline at end of file diff --git a/src/main/java/dev/logal/logalbot/tasks/MessageDeleteTask.java b/src/main/java/dev/logal/logalbot/tasks/MessageDeleteTask.java index 79485ed..23c78f3 100644 --- a/src/main/java/dev/logal/logalbot/tasks/MessageDeleteTask.java +++ b/src/main/java/dev/logal/logalbot/tasks/MessageDeleteTask.java @@ -30,6 +30,5 @@ public final class MessageDeleteTask implements Runnable { @Override public final void run() { ReactionCallbackManager.unregisterMessage(messageToDelete, true); - messageToDelete.delete().queue(); } } \ No newline at end of file diff --git a/src/main/java/dev/logal/logalbot/tasks/OpenAudioConnectionTask.java b/src/main/java/dev/logal/logalbot/tasks/OpenAudioConnectionTask.java new file mode 100644 index 0000000..a41dc32 --- /dev/null +++ b/src/main/java/dev/logal/logalbot/tasks/OpenAudioConnectionTask.java @@ -0,0 +1,34 @@ +package dev.logal.logalbot.tasks; + +// Copyright 2019 Logan Fick + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import dev.logal.logalbot.utils.AudioUtil; +import net.dv8tion.jda.core.entities.VoiceChannel; +import net.dv8tion.jda.core.utils.Checks; + +public final class OpenAudioConnectionTask implements Runnable { + private final VoiceChannel channel; + + public OpenAudioConnectionTask(final VoiceChannel channel) { + Checks.notNull(channel, "Channel"); + + this.channel = channel; + } + + @Override + public void run() { + AudioUtil.openAudioConnection(channel); + } +} \ No newline at end of file diff --git a/src/main/java/dev/logal/logalbot/tasks/PlayNextTrackTask.java b/src/main/java/dev/logal/logalbot/tasks/PlayNextTrackTask.java new file mode 100644 index 0000000..f8dd47f --- /dev/null +++ b/src/main/java/dev/logal/logalbot/tasks/PlayNextTrackTask.java @@ -0,0 +1,34 @@ +package dev.logal.logalbot.tasks; + +// Copyright 2019 Logan Fick + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import dev.logal.logalbot.utils.AudioUtil; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.utils.Checks; + +public final class PlayNextTrackTask implements Runnable { + private final Guild guild; + + public PlayNextTrackTask(final Guild guild) { + Checks.notNull(guild, "Guild"); + + this.guild = guild; + } + + @Override + public void run() { + AudioUtil.playNextTrack(this.guild); + } +} \ No newline at end of file diff --git a/src/main/java/dev/logal/logalbot/tasks/ReactionCallbackExecutionTask.java b/src/main/java/dev/logal/logalbot/tasks/ReactionCallbackExecutionTask.java new file mode 100644 index 0000000..bd06805 --- /dev/null +++ b/src/main/java/dev/logal/logalbot/tasks/ReactionCallbackExecutionTask.java @@ -0,0 +1,45 @@ +package dev.logal.logalbot.tasks; + +// Copyright 2019 Logan Fick + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import dev.logal.logalbot.utils.ReactionCallbackManager; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.utils.Checks; + +public final class ReactionCallbackExecutionTask implements Runnable { + private final long messageID; + private final TextChannel channel; + private final Member executor; + private final String emoji; + + public ReactionCallbackExecutionTask(final long messageID, final TextChannel channel, final Member executor, + final String emoji) { + Checks.notNegative(messageID, "Message ID"); + Checks.notNull(channel, "Channel"); + Checks.notNull(executor, "Executor"); + Checks.notEmpty(emoji, "Emoji"); + + this.messageID = messageID; + this.channel = channel; + this.executor = executor; + this.emoji = emoji; + } + + @Override + public void run() { + ReactionCallbackManager.executeCallback(this.messageID, this.channel, this.executor, this.emoji); + } +} \ No newline at end of file diff --git a/src/main/java/dev/logal/logalbot/tasks/ResetAudioPlayerTask.java b/src/main/java/dev/logal/logalbot/tasks/ResetAudioPlayerTask.java new file mode 100644 index 0000000..52db92f --- /dev/null +++ b/src/main/java/dev/logal/logalbot/tasks/ResetAudioPlayerTask.java @@ -0,0 +1,35 @@ +package dev.logal.logalbot.tasks; + +// Copyright 2019 Logan Fick + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import dev.logal.logalbot.utils.AudioUtil; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.utils.Checks; + +public final class ResetAudioPlayerTask implements Runnable { + private final Guild guild; + + public ResetAudioPlayerTask(final Guild guild) { + Checks.notNull(guild, "Guild"); + + this.guild = guild; + } + + @Override + public void run() { + AudioUtil.getTrackScheduler(guild).clearQueue(); + AudioUtil.stopTrack(guild); + } +} \ No newline at end of file diff --git a/src/main/java/dev/logal/logalbot/tasks/TrackAdditionTask.java b/src/main/java/dev/logal/logalbot/tasks/TrackAdditionTask.java new file mode 100644 index 0000000..8d88765 --- /dev/null +++ b/src/main/java/dev/logal/logalbot/tasks/TrackAdditionTask.java @@ -0,0 +1,54 @@ +package dev.logal.logalbot.tasks; + +// Copyright 2019 Logan Fick + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import java.util.LinkedList; +import java.util.List; + +import dev.logal.logalbot.audio.RequestedTrack; +import dev.logal.logalbot.audio.TrackScheduler; +import dev.logal.logalbot.utils.AudioUtil; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.utils.Checks; + +public final class TrackAdditionTask implements Runnable { + private final Guild guild; + private final LinkedList tracks; + + public TrackAdditionTask(final Guild guild, final RequestedTrack track) { + Checks.notNull(guild, "Guild"); + Checks.notNull(track, "Track"); + + this.guild = guild; + tracks = new LinkedList(); + tracks.add(track); + } + + public TrackAdditionTask(final Guild guild, final List tracks) { + Checks.notNull(guild, "Guild"); + Checks.noneNull(tracks, "Tracks"); + + this.guild = guild; + this.tracks = (LinkedList) tracks; + } + + @Override + public final void run() { + final TrackScheduler scheduler = AudioUtil.getTrackScheduler(this.guild); + for (final RequestedTrack track : this.tracks) { + scheduler.addToQueue(track); + } + } +} \ No newline at end of file diff --git a/src/main/java/dev/logal/logalbot/utils/AudioUtil.java b/src/main/java/dev/logal/logalbot/utils/AudioUtil.java index 7cc1cc7..62c710c 100644 --- a/src/main/java/dev/logal/logalbot/utils/AudioUtil.java +++ b/src/main/java/dev/logal/logalbot/utils/AudioUtil.java @@ -106,6 +106,15 @@ public final class AudioUtil { loadedTracks.put(guild.getIdLong(), track); } + public static final void playNextTrack(final Guild guild) { + Checks.notNull(guild, "Guild"); + + final RequestedTrack track = schedulers.get(guild.getIdLong()).popFromQueue(); + if (track != null) { + playTrack(guild, track); + } + } + public static final void stopTrack(final Guild guild) { Checks.notNull(guild, "Guild"); diff --git a/src/main/java/dev/logal/logalbot/utils/Scheduler.java b/src/main/java/dev/logal/logalbot/utils/Scheduler.java deleted file mode 100644 index 2bb94de..0000000 --- a/src/main/java/dev/logal/logalbot/utils/Scheduler.java +++ /dev/null @@ -1,48 +0,0 @@ -package dev.logal.logalbot.utils; - -// Copyright 2019 Logan Fick - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// https://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -import net.dv8tion.jda.core.utils.Checks; - -public final class Scheduler { - private static final ScheduledExecutorService pool = Executors.newScheduledThreadPool(1); - - private Scheduler() { - // Static access only. - } - - public static final ScheduledFuture schedule(final Runnable runnable, final long delay, final TimeUnit unit) { - Checks.notNull(runnable, "Runnable"); - Checks.notNegative(delay, "Delay"); - Checks.notNull(unit, "Unit"); - - return pool.schedule(runnable, delay, unit); - } - - public static final ScheduledFuture scheduleRepeating(final Runnable runnable, final long initialDelay, - final long period, final TimeUnit unit) { - Checks.notNull(runnable, "Runnable"); - Checks.notNegative(initialDelay, "Initial delay"); - Checks.notNegative(period, "Period"); - Checks.notNull(unit, "Unit"); - - return pool.scheduleAtFixedRate(runnable, initialDelay, period, unit); - } -} \ No newline at end of file