diff --git a/EssentialsDiscord/build.gradle b/EssentialsDiscord/build.gradle index bb41c2ae5..555fec855 100644 --- a/EssentialsDiscord/build.gradle +++ b/EssentialsDiscord/build.gradle @@ -22,12 +22,14 @@ shadowJar { include(dependency('com.neovisionaries:nv-websocket-client')) include(dependency('com.squareup.okhttp3:okhttp')) include(dependency('com.squareup.okio:okio')) + include(dependency('com.squareup.okio:okio-jvm')) include(dependency('org.apache.commons:commons-collections4')) include(dependency('net.sf.trove4j:trove4j')) include(dependency('com.fasterxml.jackson.core:jackson-databind')) include(dependency('com.fasterxml.jackson.core:jackson-core')) include(dependency('com.fasterxml.jackson.core:jackson-annotations')) include(dependency('org.slf4j:slf4j-api')) + include(dependency('org.jetbrains.kotlin:kotlin-stdlib')) // Emoji include(dependency('com.github.MinnDevelopment:emoji-java')) @@ -49,6 +51,7 @@ shadowJar { relocate 'com.fasterxml.jackson.core', 'net.essentialsx.dep.com.fasterxml.jackson.core' relocate 'com.fasterxml.jackson.annotation', 'net.essentialsx.dep.com.fasterxml.jackson.annotation' relocate 'gnu.trove', 'net.essentialsx.dep.gnu.trove' + relocate 'kotlin', 'net.essentialsx.dep.garbage.kotlin' // Emoji relocate 'com.vdurmont.emoji', 'net.essentialsx.dep.com.vdurmont.emoji' diff --git a/EssentialsDiscord/src/main/java/net/essentialsx/discord/JDADiscordService.java b/EssentialsDiscord/src/main/java/net/essentialsx/discord/JDADiscordService.java index 01dadcfe8..4883cb634 100644 --- a/EssentialsDiscord/src/main/java/net/essentialsx/discord/JDADiscordService.java +++ b/EssentialsDiscord/src/main/java/net/essentialsx/discord/JDADiscordService.java @@ -1,6 +1,5 @@ package net.essentialsx.discord; -import club.minnced.discord.webhook.WebhookClient; import club.minnced.discord.webhook.WebhookClientBuilder; import club.minnced.discord.webhook.send.WebhookMessage; import club.minnced.discord.webhook.send.WebhookMessageBuilder; @@ -17,7 +16,6 @@ import net.dv8tion.jda.api.entities.Webhook; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji; import net.dv8tion.jda.api.events.session.ShutdownEvent; -import net.dv8tion.jda.api.hooks.EventListener; import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.requests.GatewayIntent; import net.dv8tion.jda.api.utils.cache.CacheFlag; @@ -47,6 +45,7 @@ import net.essentialsx.discord.listeners.BukkitChatListener; import net.essentialsx.discord.util.ConsoleInjector; import net.essentialsx.discord.util.DiscordUtil; import net.essentialsx.discord.util.MessageUtil; +import net.essentialsx.discord.util.WrappedWebhookClient; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; @@ -80,11 +79,11 @@ public class JDADiscordService implements DiscordService, IEssentialsModule { private JDA jda; private Guild guild; private TextChannel primaryChannel; - private WebhookClient consoleWebhook; + private WrappedWebhookClient consoleWebhook; private String lastConsoleId; private final Map registeredTypes = new HashMap<>(); private final Map typeToChannelId = new HashMap<>(); - private final Map channelIdToWebhook = new HashMap<>(); + private final Map channelIdToWebhook = new HashMap<>(); private ConsoleInjector injector; private DiscordCommandDispatcher commandDispatcher; private InteractionControllerImpl interactionController; @@ -141,7 +140,7 @@ public class JDADiscordService implements DiscordService, IEssentialsModule { final String webhookChannelId = typeToChannelId.get(event.getType()); if (webhookChannelId != null) { - final WebhookClient client = channelIdToWebhook.get(webhookChannelId); + final WrappedWebhookClient client = channelIdToWebhook.get(webhookChannelId); if (client != null) { final String avatarUrl = event.getAvatarUrl() != null ? event.getAvatarUrl() : jda.getSelfUser().getAvatarUrl(); final String name = event.getName() != null ? event.getName() : guild.getSelfMember().getEffectiveName(); @@ -364,7 +363,7 @@ public class JDADiscordService implements DiscordService, IEssentialsModule { public void updateTypesRelay() { if (!getSettings().isShowAvatar() && !getSettings().isShowName() && !getSettings().isShowDisplayName()) { - for (WebhookClient webhook : channelIdToWebhook.values()) { + for (WrappedWebhookClient webhook : channelIdToWebhook.values()) { webhook.close(); } typeToChannelId.clear(); @@ -384,7 +383,7 @@ public class JDADiscordService implements DiscordService, IEssentialsModule { final Webhook webhook = DiscordUtil.getOrCreateWebhook(channel, DiscordUtil.ADVANCED_RELAY_NAME).join(); if (webhook == null) { - final WebhookClient current = channelIdToWebhook.get(channel.getId()); + final WrappedWebhookClient current = channelIdToWebhook.get(channel.getId()); if (current != null) { current.close(); } @@ -491,9 +490,7 @@ public class JDADiscordService implements DiscordService, IEssentialsModule { // Unregister leftover jda listeners for (Object obj : jda.getRegisteredListeners()) { - if (!(obj instanceof EventListener)) { // Yeah bro I wish I knew too :/ - jda.removeEventListener(obj); - } + jda.removeEventListener(obj); } // Unregister Bukkit Events @@ -514,7 +511,7 @@ public class JDADiscordService implements DiscordService, IEssentialsModule { // Wait for JDA to wrap it up future.get(5, TimeUnit.SECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { - logger.warning("JDA took longer than expected to shutdown, this may have caused some problems."); + logger.log(Level.WARNING, "JDA took longer than expected to shutdown, this may have caused some problems.", e); } finally { jda = null; } @@ -590,7 +587,7 @@ public class JDADiscordService implements DiscordService, IEssentialsModule { return plugin.getSettings(); } - public WebhookClient getConsoleWebhook() { + public WrappedWebhookClient getConsoleWebhook() { return consoleWebhook; } diff --git a/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/ConsoleInjector.java b/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/ConsoleInjector.java index dcce58d07..c6e52d10a 100644 --- a/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/ConsoleInjector.java +++ b/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/ConsoleInjector.java @@ -94,6 +94,9 @@ public class ConsoleInjector extends AbstractAppender { ((Logger) LogManager.getRootLogger()).removeAppender(this); Bukkit.getScheduler().cancelTask(taskId); messageQueue.clear(); + if (jda.getConsoleWebhook() != null && !jda.getConsoleWebhook().isShutdown()) { + jda.getConsoleWebhook().close(); + } removed = true; } diff --git a/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/DiscordUtil.java b/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/DiscordUtil.java index 76df5ce6e..d789d6d74 100644 --- a/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/DiscordUtil.java +++ b/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/DiscordUtil.java @@ -1,7 +1,6 @@ package net.essentialsx.discord.util; import club.minnced.discord.webhook.WebhookClient; -import club.minnced.discord.webhook.WebhookClientBuilder; import club.minnced.discord.webhook.send.AllowedMentions; import com.earth2me.essentials.utils.DownsampleUtil; import com.earth2me.essentials.utils.FormatUtil; @@ -54,13 +53,8 @@ public final class DiscordUtil { * @param client The http client of the webhook. * @return The {@link WebhookClient}. */ - public static WebhookClient getWebhookClient(long id, String token, OkHttpClient client) { - return new WebhookClientBuilder(id, token) - .setWait(false) - .setAllowedMentions(AllowedMentions.none()) - .setHttpClient(client) - .setDaemon(true) - .build(); + public static WrappedWebhookClient getWebhookClient(long id, String token, OkHttpClient client) { + return new WrappedWebhookClient(id, token, client); } /** diff --git a/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/WrappedWebhookClient.java b/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/WrappedWebhookClient.java new file mode 100644 index 000000000..6458f4bda --- /dev/null +++ b/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/WrappedWebhookClient.java @@ -0,0 +1,54 @@ +package net.essentialsx.discord.util; + +import club.minnced.discord.webhook.WebhookClient; +import club.minnced.discord.webhook.WebhookClientBuilder; +import club.minnced.discord.webhook.receive.ReadonlyMessage; +import club.minnced.discord.webhook.send.AllowedMentions; +import club.minnced.discord.webhook.send.WebhookMessage; +import club.minnced.discord.webhook.util.ThreadPools; +import net.essentialsx.discord.EssentialsDiscord; +import okhttp3.OkHttpClient; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class WrappedWebhookClient { + private final static Logger logger = EssentialsDiscord.getWrappedLogger(); + private final WebhookClient webhookClient; + private final ScheduledExecutorService executorService; + + public WrappedWebhookClient(final long id, final String token, final OkHttpClient client) { + webhookClient = new WebhookClientBuilder(id, token) + .setWait(false) + .setAllowedMentions(AllowedMentions.none()) + .setHttpClient(client) + .setExecutorService(executorService = ThreadPools.getDefaultPool(id, null, true)) + .build(); + } + + public CompletableFuture send(WebhookMessage message) { + return webhookClient.send(message); + } + + public boolean isShutdown() { + return webhookClient.isShutdown(); + } + + public void close() { + // This call should close the executor service as well + webhookClient.close(); + if (executorService.isTerminated()) { + return; + } + try { + if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) { + throw new InterruptedException("ExecutorService did not terminate in time."); + } + } catch (InterruptedException e) { + logger.log(Level.WARNING, "Webhook (ID: " + webhookClient.getId() + ") took longer than expected to shutdown, this may have caused some problems.", e); + } + } +}