From f7dcd69b77c7f47c58167ebff037fcddc72b6954 Mon Sep 17 00:00:00 2001 From: Vankka Date: Fri, 14 Feb 2025 22:19:44 +0200 Subject: [PATCH] Complete conversion to Task from CompletableFuture --- .../entity/channel/DiscordForumChannel.java | 5 +- .../entity/channel/DiscordGuildChannel.java | 5 +- .../entity/channel/DiscordMediaChannel.java | 5 +- .../entity/channel/DiscordMessageChannel.java | 9 +- .../channel/DiscordThreadContainer.java | 12 +- .../discord/entity/guild/DiscordGuild.java | 2 +- .../entity/guild/DiscordGuildMember.java | 6 +- .../interaction/DiscordInteractionHook.java | 9 +- .../message/ReceivedDiscordMessage.java | 12 +- .../ReceivedDiscordMessageCluster.java | 10 +- .../AbstractCommandInteractionEvent.java | 9 +- .../java/com/discordsrv/api/task/Task.java | 219 ++++++++++++++++++ .../discordsrv/bukkit/ban/PaperBanModule.java | 14 +- .../game/PaperGameCommandExecutionHelper.java | 4 +- .../bukkit/ban/BukkitBanModule.java | 8 +- .../BukkitGameCommandExecutionHelper.java | 10 +- .../bukkit/player/BukkitPlayer.java | 4 +- .../bukkit/scheduler/BukkitScheduler.java | 13 +- .../bukkit/player/BukkitPlayerImpl.java | 4 +- .../bungee/player/BungeePlayer.java | 6 +- .../discordsrv/common/AbstractDiscordSRV.java | 6 +- .../com/discordsrv/common/DiscordSRV.java | 8 +- .../bootstrap/LifecycleManager.java | 4 +- .../common/abstraction/player/IPlayer.java | 4 +- .../abstraction/sync/AbstractSyncModule.java | 3 +- .../combined/commands/LinkOtherCommand.java | 6 +- .../combined/commands/ResyncCommand.java | 5 +- .../GameCommandExecutionHelper.java | 5 +- .../commands/subcommand/BroadcastCommand.java | 4 +- .../core/dependency/DependencyLoader.java | 8 +- .../context/GamePermissionContext.java | 4 +- .../core/scheduler/ServerScheduler.java | 12 +- .../common/discord/api/DiscordAPIImpl.java | 60 ++--- .../discord/api/entity/DiscordUserImpl.java | 8 +- .../channel/AbstractDiscordForumChannel.java | 41 ++-- .../AbstractDiscordGuildMessageChannel.java | 38 +-- ...actDiscordThreadedGuildMessageChannel.java | 37 ++- .../entity/channel/DiscordDMChannelImpl.java | 21 +- .../channel/DiscordForumChannelImpl.java | 5 +- .../channel/DiscordMediaChannelImpl.java | 5 +- .../channel/DiscordThreadChannelImpl.java | 5 +- .../component/DiscordInteractionHookImpl.java | 11 +- .../api/entity/guild/DiscordGuildImpl.java | 6 +- .../entity/guild/DiscordGuildMemberImpl.java | 15 +- .../ReceivedDiscordMessageClusterImpl.java | 15 +- .../message/ReceivedDiscordMessageImpl.java | 14 +- .../connection/jda/JDAConnectionManager.java | 13 +- .../DiscordChatInputInteractionEventImpl.java | 19 +- ...ordMessageContextInteractionEventImpl.java | 19 +- ...iscordUserContextInteractionEventImpl.java | 19 +- .../common/feature/bansync/BanSyncModule.java | 5 +- .../feature/console/SingleConsoleHandler.java | 85 +++---- .../feature/groupsync/GroupSyncModule.java | 12 +- .../requirelinking/RequiredLinkingModule.java | 30 +-- .../ServerRequireLinkingModule.java | 4 +- .../requirement/RequirementType.java | 5 +- .../parser/ParsedRequirements.java | 8 +- .../requirement/parser/RequirementParser.java | 7 +- .../type/DiscordBoostingRequirementType.java | 7 +- .../type/DiscordRoleRequirementType.java | 7 +- .../type/DiscordServerRequirementType.java | 6 +- .../type/MinecraftAuthRequirementType.java | 4 +- .../feature/mention/MentionCachingModule.java | 12 +- .../DiscordMessageMirroringModule.java | 40 +--- .../game/AbstractGameMessageModule.java | 42 ++-- .../game/JoinMessageModule.java | 13 +- .../game/LeaveMessageModule.java | 8 +- .../game/MinecraftToDiscordChatModule.java | 14 +- .../game/StartMessageModule.java | 4 +- .../game/StopMessageModule.java | 4 +- .../helper/DestinationLookupHelper.java | 65 +++--- .../integration/LuckPermsIntegration.java | 7 +- .../discordsrv/common/util/CommandUtil.java | 32 +-- ...mpletableFutureUtil.java => TaskUtil.java} | 52 +---- .../command/game/GameCommandFilterTest.java | 4 +- .../parser/RequirementTypeParserTest.java | 8 +- .../MinecraftToDiscordChatMessageTest.java | 3 +- .../FabricGameCommandExecutionHelper.java | 16 +- .../fabric/module/ban/FabricBanModule.java | 22 +- .../fabric/player/FabricPlayer.java | 6 +- .../velocity/player/VelocityPlayer.java | 6 +- 81 files changed, 696 insertions(+), 628 deletions(-) create mode 100644 api/src/main/java/com/discordsrv/api/task/Task.java rename common/src/main/java/com/discordsrv/common/util/{CompletableFutureUtil.java => TaskUtil.java} (53%) diff --git a/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordForumChannel.java b/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordForumChannel.java index 74fa7d02..c7d71da9 100644 --- a/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordForumChannel.java +++ b/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordForumChannel.java @@ -25,11 +25,10 @@ package com.discordsrv.api.discord.entity.channel; import com.discordsrv.api.discord.entity.JDAEntity; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.api.task.Task; import net.dv8tion.jda.api.entities.channel.concrete.ForumChannel; -import java.util.concurrent.CompletableFuture; - public interface DiscordForumChannel extends DiscordChannel, DiscordThreadContainer, JDAEntity { - CompletableFuture createPost(String name, SendableDiscordMessage message); + Task createPost(String name, SendableDiscordMessage message); } diff --git a/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordGuildChannel.java b/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordGuildChannel.java index 1568cffc..1eb3c9b4 100644 --- a/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordGuildChannel.java +++ b/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordGuildChannel.java @@ -27,10 +27,9 @@ import com.discordsrv.api.discord.entity.Snowflake; import com.discordsrv.api.discord.entity.guild.DiscordGuild; import com.discordsrv.api.placeholder.annotation.Placeholder; import com.discordsrv.api.placeholder.annotation.PlaceholderPrefix; +import com.discordsrv.api.task.Task; import org.jetbrains.annotations.NotNull; -import java.util.concurrent.CompletableFuture; - @PlaceholderPrefix("channel_") public interface DiscordGuildChannel extends DiscordChannel, Snowflake { @@ -62,5 +61,5 @@ public interface DiscordGuildChannel extends DiscordChannel, Snowflake { * Deletes the channel. * @return a future completing upon deletion */ - CompletableFuture delete(); + Task delete(); } diff --git a/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordMediaChannel.java b/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordMediaChannel.java index fd317a58..0b54263c 100644 --- a/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordMediaChannel.java +++ b/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordMediaChannel.java @@ -25,10 +25,9 @@ package com.discordsrv.api.discord.entity.channel; import com.discordsrv.api.discord.entity.JDAEntity; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.api.task.Task; import net.dv8tion.jda.api.entities.channel.concrete.MediaChannel; -import java.util.concurrent.CompletableFuture; - public interface DiscordMediaChannel extends DiscordChannel, DiscordThreadContainer, JDAEntity { - CompletableFuture createPost(String name, SendableDiscordMessage message); + Task createPost(String name, SendableDiscordMessage message); } diff --git a/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordMessageChannel.java b/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordMessageChannel.java index 1482ed18..e918b8e6 100644 --- a/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordMessageChannel.java +++ b/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordMessageChannel.java @@ -26,11 +26,10 @@ package com.discordsrv.api.discord.entity.channel; import com.discordsrv.api.DiscordSRVApi; import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessage; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.api.task.Task; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import org.jetbrains.annotations.NotNull; -import java.util.concurrent.CompletableFuture; - /** * A Discord channel that can send/receive messages. */ @@ -43,7 +42,7 @@ public interface DiscordMessageChannel extends DiscordChannel { * @return a future returning the message after being sent */ @NotNull - CompletableFuture sendMessage(@NotNull SendableDiscordMessage message); + Task sendMessage(@NotNull SendableDiscordMessage message); /** * Deletes the message identified by the id. @@ -52,7 +51,7 @@ public interface DiscordMessageChannel extends DiscordChannel { * @param webhookMessage if the message is a webhook message or not * @return a future that will fail if the request fails */ - CompletableFuture deleteMessageById(long id, boolean webhookMessage); + Task deleteMessageById(long id, boolean webhookMessage); /** * Edits the message identified by the id. @@ -62,7 +61,7 @@ public interface DiscordMessageChannel extends DiscordChannel { * @return a future returning the message after being edited */ @NotNull - CompletableFuture editMessageById(long id, @NotNull SendableDiscordMessage message); + Task editMessageById(long id, @NotNull SendableDiscordMessage message); /** * Returns the JDA representation of this object. This should not be used if it can be avoided. diff --git a/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordThreadContainer.java b/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordThreadContainer.java index 85359bb4..c30ddc93 100644 --- a/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordThreadContainer.java +++ b/api/src/main/java/com/discordsrv/api/discord/entity/channel/DiscordThreadContainer.java @@ -24,11 +24,11 @@ package com.discordsrv.api.discord.entity.channel; import com.discordsrv.api.DiscordSRVApi; +import com.discordsrv.api.task.Task; import net.dv8tion.jda.api.entities.channel.attribute.IThreadContainer; import org.jetbrains.annotations.NotNull; import java.util.List; -import java.util.concurrent.CompletableFuture; /** * A Discord channel that contains threads. @@ -38,12 +38,12 @@ public interface DiscordThreadContainer extends DiscordGuildChannel { @NotNull List getActiveThreads(); - CompletableFuture> retrieveArchivedPrivateThreads(); - CompletableFuture> retrieveArchivedJoinedPrivateThreads(); - CompletableFuture> retrieveArchivedPublicThreads(); + Task> retrieveArchivedPrivateThreads(); + Task> retrieveArchivedJoinedPrivateThreads(); + Task> retrieveArchivedPublicThreads(); - CompletableFuture createThread(String name, boolean privateThread); - CompletableFuture createThread(String name, long messageId); + Task createThread(String name, boolean privateThread); + Task createThread(String name, long messageId); /** * Returns the JDA representation of this object. This should not be used if it can be avoided. diff --git a/api/src/main/java/com/discordsrv/api/discord/entity/guild/DiscordGuild.java b/api/src/main/java/com/discordsrv/api/discord/entity/guild/DiscordGuild.java index e06f36ae..f38ee33d 100644 --- a/api/src/main/java/com/discordsrv/api/discord/entity/guild/DiscordGuild.java +++ b/api/src/main/java/com/discordsrv/api/discord/entity/guild/DiscordGuild.java @@ -27,13 +27,13 @@ import com.discordsrv.api.discord.entity.JDAEntity; import com.discordsrv.api.discord.entity.Snowflake; import com.discordsrv.api.placeholder.annotation.Placeholder; import com.discordsrv.api.placeholder.annotation.PlaceholderPrefix; +import com.discordsrv.api.task.Task; import net.dv8tion.jda.api.entities.Guild; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Set; -import java.util.concurrent.CompletableFuture; /** * A Discord server. diff --git a/api/src/main/java/com/discordsrv/api/discord/entity/guild/DiscordGuildMember.java b/api/src/main/java/com/discordsrv/api/discord/entity/guild/DiscordGuildMember.java index 33698b50..8d91f715 100644 --- a/api/src/main/java/com/discordsrv/api/discord/entity/guild/DiscordGuildMember.java +++ b/api/src/main/java/com/discordsrv/api/discord/entity/guild/DiscordGuildMember.java @@ -29,13 +29,13 @@ import com.discordsrv.api.discord.entity.JDAEntity; import com.discordsrv.api.discord.entity.Mentionable; import com.discordsrv.api.placeholder.annotation.Placeholder; import com.discordsrv.api.placeholder.annotation.PlaceholderPrefix; +import com.discordsrv.api.task.Task; import net.dv8tion.jda.api.entities.Member; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.time.OffsetDateTime; import java.util.List; -import java.util.concurrent.CompletableFuture; /** * A Discord server member. @@ -97,14 +97,14 @@ public interface DiscordGuildMember extends JDAEntity, Mentionable { * @param role the role to give * @return a future */ - CompletableFuture addRole(@NotNull DiscordRole role); + Task addRole(@NotNull DiscordRole role); /** * Takes the given role from this member. * @param role the role to take * @return a future */ - CompletableFuture removeRole(@NotNull DiscordRole role); + Task removeRole(@NotNull DiscordRole role); /** * Gets the effective name of this Discord server member. diff --git a/api/src/main/java/com/discordsrv/api/discord/entity/interaction/DiscordInteractionHook.java b/api/src/main/java/com/discordsrv/api/discord/entity/interaction/DiscordInteractionHook.java index ce5792be..e6f895e6 100644 --- a/api/src/main/java/com/discordsrv/api/discord/entity/interaction/DiscordInteractionHook.java +++ b/api/src/main/java/com/discordsrv/api/discord/entity/interaction/DiscordInteractionHook.java @@ -26,18 +26,17 @@ package com.discordsrv.api.discord.entity.interaction; import com.discordsrv.api.discord.entity.JDAEntity; import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessage; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.api.task.Task; import net.dv8tion.jda.api.interactions.InteractionHook; -import java.util.concurrent.CompletableFuture; - public interface DiscordInteractionHook extends JDAEntity { long getExpiryTime(); boolean isExpired(); - CompletableFuture editOriginal(SendableDiscordMessage message); - CompletableFuture sendMessage(SendableDiscordMessage message, boolean ephemeral); - default CompletableFuture sendMessage(SendableDiscordMessage message) { + Task editOriginal(SendableDiscordMessage message); + Task sendMessage(SendableDiscordMessage message, boolean ephemeral); + default Task sendMessage(SendableDiscordMessage message) { return sendMessage(message, false); } } diff --git a/api/src/main/java/com/discordsrv/api/discord/entity/message/ReceivedDiscordMessage.java b/api/src/main/java/com/discordsrv/api/discord/entity/message/ReceivedDiscordMessage.java index a71b28a9..cd996010 100644 --- a/api/src/main/java/com/discordsrv/api/discord/entity/message/ReceivedDiscordMessage.java +++ b/api/src/main/java/com/discordsrv/api/discord/entity/message/ReceivedDiscordMessage.java @@ -32,13 +32,13 @@ import com.discordsrv.api.discord.entity.guild.DiscordGuild; import com.discordsrv.api.discord.entity.guild.DiscordGuildMember; import com.discordsrv.api.placeholder.annotation.Placeholder; import com.discordsrv.api.placeholder.annotation.PlaceholderPrefix; +import com.discordsrv.api.task.Task; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Unmodifiable; import java.util.List; import java.util.Set; -import java.util.concurrent.CompletableFuture; /** * A message received from Discord. @@ -162,26 +162,28 @@ public interface ReceivedDiscordMessage extends Snowflake { * @return a future that will fail if the request fails */ @NotNull - CompletableFuture delete(); + Task delete(); /** * Edits this message to the provided message. * * @param message the new message * @return a future that will fail if the request fails, otherwise the new message provided by the request response + * * @throws IllegalArgumentException if the message is not a webhook message, - * but the provided {@link SendableDiscordMessage} specifies a webhook username. + * but the provided {@link SendableDiscordMessage} specifies a webhook username. */ - CompletableFuture edit(@NotNull SendableDiscordMessage message); + Task edit(@NotNull SendableDiscordMessage message); /** * Send the provided message in the channel this message was sent in, replying to this message. * * @param message the message * @return a future that will fail if the request fails, otherwise the new message provided by the request response + * * @throws IllegalArgumentException if the provided message is a webhook message */ - CompletableFuture reply(@NotNull SendableDiscordMessage message); + Task reply(@NotNull SendableDiscordMessage message); class Attachment { diff --git a/api/src/main/java/com/discordsrv/api/discord/entity/message/ReceivedDiscordMessageCluster.java b/api/src/main/java/com/discordsrv/api/discord/entity/message/ReceivedDiscordMessageCluster.java index 7fde8312..f31506de 100644 --- a/api/src/main/java/com/discordsrv/api/discord/entity/message/ReceivedDiscordMessageCluster.java +++ b/api/src/main/java/com/discordsrv/api/discord/entity/message/ReceivedDiscordMessageCluster.java @@ -23,10 +23,10 @@ package com.discordsrv.api.discord.entity.message; +import com.discordsrv.api.task.Task; import org.jetbrains.annotations.NotNull; import java.util.Set; -import java.util.concurrent.CompletableFuture; /** * A cluster of Discord messages, or just a single message. @@ -42,17 +42,17 @@ public interface ReceivedDiscordMessageCluster { /** * Deletes all the messages from this cluster, one request per message. + * * @return a future that fails if any of the requests fail. */ - @NotNull - CompletableFuture deleteAll(); + @NotNull Task deleteAll(); /** * Edits all the messages in this cluster, one request per edit. + * * @param newMessage the new content of the messages * @return a future that fails if any of the requests fail. */ - @NotNull - CompletableFuture editAll(SendableDiscordMessage newMessage); + @NotNull Task editAll(SendableDiscordMessage newMessage); } diff --git a/api/src/main/java/com/discordsrv/api/events/discord/interaction/command/AbstractCommandInteractionEvent.java b/api/src/main/java/com/discordsrv/api/events/discord/interaction/command/AbstractCommandInteractionEvent.java index e1117531..790f1157 100644 --- a/api/src/main/java/com/discordsrv/api/events/discord/interaction/command/AbstractCommandInteractionEvent.java +++ b/api/src/main/java/com/discordsrv/api/events/discord/interaction/command/AbstractCommandInteractionEvent.java @@ -33,12 +33,11 @@ import com.discordsrv.api.discord.entity.interaction.DiscordInteractionHook; import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; import com.discordsrv.api.events.discord.interaction.AbstractInteractionWithHookEvent; +import com.discordsrv.api.task.Task; import net.dv8tion.jda.api.events.interaction.command.GenericCommandInteractionEvent; import net.dv8tion.jda.api.interactions.commands.OptionMapping; import org.jetbrains.annotations.Nullable; -import java.util.concurrent.CompletableFuture; - public abstract class AbstractCommandInteractionEvent extends AbstractInteractionWithHookEvent { @@ -57,13 +56,13 @@ public abstract class AbstractCommandInteractionEvent reply(SendableDiscordMessage message, boolean ephemeral); + public abstract Task reply(SendableDiscordMessage message, boolean ephemeral); - public CompletableFuture reply(SendableDiscordMessage message) { + public Task reply(SendableDiscordMessage message) { return reply(message, false); } - public abstract CompletableFuture deferReply(boolean ephemeral); + public abstract Task deferReply(boolean ephemeral); @Nullable public String getOptionAsString(String name) { diff --git a/api/src/main/java/com/discordsrv/api/task/Task.java b/api/src/main/java/com/discordsrv/api/task/Task.java new file mode 100644 index 00000000..131d4fcd --- /dev/null +++ b/api/src/main/java/com/discordsrv/api/task/Task.java @@ -0,0 +1,219 @@ +/* + * This file is part of the DiscordSRV API, licensed under the MIT License + * Copyright (c) 2016-2025 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.discordsrv.api.task; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.*; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; + +public class Task implements Future { + + public static Task of(@NotNull CompletableFuture future) { + return new Task<>(future); + } + + public static Task failed(@NotNull Throwable throwable) { + return of(failedFuture(throwable)); + } + + public static Task completed(@Nullable T result) { + return of(CompletableFuture.completedFuture(result)); + } + + @SuppressWarnings("unchecked") + public static Task anyOf(@NotNull Collection> tasks) { + return anyOf(tasks.toArray(new Task[0])); + } + + @SuppressWarnings("unchecked") + @NotNull + public static Task anyOfGeneric(@NotNull Collection<@NotNull Task> futures) { + return anyOf(futures.toArray(new Task[0])); + } + + @SuppressWarnings("unchecked") + public static Task anyOf(@NotNull Task... tasks) { + CompletableFuture[] futures = new CompletableFuture[tasks.length]; + for (int i = 0; i < tasks.length; i++) { + futures[i] = tasks[i].getFuture(); + } + return of(CompletableFuture.anyOf(futures).thenApply(obj -> (T) obj)); + } + + @SuppressWarnings("unchecked") + public static Task> allOf(@NotNull Collection> tasks) { + return allOf(tasks.toArray(new Task[0])); + } + + @SuppressWarnings("unchecked") + @NotNull + public static Task> allOfGeneric(@NotNull Collection<@NotNull Task> futures) { + return allOf(futures.toArray(new Task[0])); + } + + @SuppressWarnings("unchecked") + @SafeVarargs + public static Task> allOf(@NotNull Task... tasks) { + CompletableFuture[] futures = new CompletableFuture[tasks.length]; + for (int i = 0; i < tasks.length; i++) { + futures[i] = tasks[i].getFuture(); + } + return of(CompletableFuture.allOf(futures).thenApply(v -> { + List results = new ArrayList<>(futures.length); + for (CompletableFuture aFuture : futures) { + results.add(aFuture.join()); + } + return results; + })); + } + + private static CompletableFuture failedFuture(@NotNull Throwable throwable) { + CompletableFuture future = new CompletableFuture<>(); + future.completeExceptionally(throwable); + return future; + } + + private final CompletableFuture future; + + private Task(@NotNull CompletableFuture future) { + this.future = future; + } + + public CompletableFuture getFuture() { + return future; + } + + public boolean isFailed() { + return future.isCompletedExceptionally(); + } + + public T join() { + return future.join(); + } + + @Override + public boolean isDone() { + return future.isDone(); + } + + @Override + public boolean isCancelled() { + return future.isCancelled(); + } + + @Override + public boolean cancel(boolean interruptIfRunning) { + return future.cancel(interruptIfRunning); + } + + @Override + public T get() throws InterruptedException, ExecutionException { + return future.get(); + } + + @Override + public T get(long timeout, @NotNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return future.get(timeout, unit); + } + + public Task whenSuccessful(@NotNull Consumer successConsumer) { + return of(future.whenComplete((result, throwable) -> { + if (throwable == null) { + successConsumer.accept(result); + } + })); + } + + public Task whenFailed(@NotNull Consumer failureConsumer) { + return of(future.whenComplete((result, throwable) -> { + if (throwable != null) { + failureConsumer.accept(throwable); + } + })); + } + + public Task whenComplete(@NotNull BiConsumer consumer) { + return of(future.whenComplete(consumer)); + } + + public Task thenApply(@NotNull Function mappingFunction) { + return of(future.thenCompose(result -> map(mappingFunction, result))); + } + + public Task then(@NotNull Function> mappingFunction) { + return of(future.thenCompose(result -> { + try { + return mappingFunction.apply(result).future; + } catch (Throwable throwable) { + return failedFuture(throwable); + } + })); + } + + public Task thenCompose(@NotNull Function> mappingFunction) { + return of(future.thenCompose(result -> { + try { + return mappingFunction.apply(result); + } catch (Throwable throwable) { + return failedFuture(throwable); + } + })); + } + + public Task mapException(@NotNull Function mappingFunction) { + return mapException(Throwable.class, mappingFunction); + } + + @SuppressWarnings("unchecked") + public Task mapException(@NotNull Class type, @NotNull Function mappingFunction) { + Throwable[] error = new Throwable[1]; + return of(future.exceptionally(throwable -> { + error[0] = throwable; + return null; + }).thenCompose(result -> { + E throwable = (E) error[0]; + if (throwable != null && type.isAssignableFrom(throwable.getClass())) { + return map(mappingFunction, throwable); + } + + return CompletableFuture.completedFuture(result); + })); + } + + private CompletableFuture map(Function function, I result) { + try { + O mappedResult = function.apply(result); + return CompletableFuture.completedFuture(mappedResult); + } catch (Throwable throwable) { + return failedFuture(throwable); + } + } +} diff --git a/bukkit/compat/paper/src/main/java/com/discordsrv/bukkit/ban/PaperBanModule.java b/bukkit/compat/paper/src/main/java/com/discordsrv/bukkit/ban/PaperBanModule.java index 812989a3..bbced992 100644 --- a/bukkit/compat/paper/src/main/java/com/discordsrv/bukkit/ban/PaperBanModule.java +++ b/bukkit/compat/paper/src/main/java/com/discordsrv/bukkit/ban/PaperBanModule.java @@ -22,6 +22,7 @@ import com.destroystokyo.paper.profile.PlayerProfile; import com.discordsrv.api.component.MinecraftComponent; import com.discordsrv.api.module.type.PunishmentModule; import com.discordsrv.api.punishment.Punishment; +import com.discordsrv.api.task.Task; import com.discordsrv.bukkit.BukkitDiscordSRV; import com.discordsrv.common.core.module.type.AbstractModule; import com.discordsrv.common.feature.bansync.BanSyncModule; @@ -42,7 +43,6 @@ import org.jetbrains.annotations.Nullable; import java.time.Instant; import java.util.Date; import java.util.UUID; -import java.util.concurrent.CompletableFuture; @ApiStatus.AvailableSince("Paper 1.21.1") public class PaperBanModule extends AbstractModule implements Listener, PunishmentModule.Bans { @@ -69,7 +69,7 @@ public class PaperBanModule extends AbstractModule implements } @Override - public CompletableFuture<@Nullable Punishment> getBan(@NotNull UUID playerUUID) { + public Task<@Nullable Punishment> getBan(@NotNull UUID playerUUID) { ProfileBanList banList = discordSRV.server().getBanList(BanListType.PROFILE); PlayerProfile profile = discordSRV.server().createProfile(playerUUID); @@ -80,7 +80,7 @@ public class PaperBanModule extends AbstractModule implements Date expiration = ban.getExpiration(); String reason = ban.getReason(); - return CompletableFuture.completedFuture(new Punishment( + return Task.completed(new Punishment( expiration != null ? expiration.toInstant() : null, reason != null ? ComponentUtil.toAPI(BukkitComponentSerializer.legacy().deserialize(reason)) : null, ComponentUtil.toAPI(BukkitComponentSerializer.legacy().deserialize(ban.getSource())) @@ -88,7 +88,7 @@ public class PaperBanModule extends AbstractModule implements } @Override - public CompletableFuture addBan( + public Task addBan( @NotNull UUID playerUUID, @Nullable Instant until, @Nullable MinecraftComponent reason, @@ -100,14 +100,14 @@ public class PaperBanModule extends AbstractModule implements String reasonLegacy = reason != null ? BukkitComponentSerializer.legacy().serialize(ComponentUtil.fromAPI(reason)) : null; String punisherLegacy = BukkitComponentSerializer.legacy().serialize(ComponentUtil.fromAPI(punisher)); banList.addBan(profile, reasonLegacy, until != null ? Date.from(until) : null, punisherLegacy); - return CompletableFuture.completedFuture(null); + return Task.completed(null); } @Override - public CompletableFuture removeBan(@NotNull UUID playerUUID) { + public Task removeBan(@NotNull UUID playerUUID) { ProfileBanList banList = discordSRV.server().getBanList(BanListType.PROFILE); PlayerProfile profile = discordSRV.server().createProfile(playerUUID); banList.pardon(profile); - return CompletableFuture.completedFuture(null); + return Task.completed(null); } } diff --git a/bukkit/compat/paper/src/main/java/com/discordsrv/bukkit/command/game/PaperGameCommandExecutionHelper.java b/bukkit/compat/paper/src/main/java/com/discordsrv/bukkit/command/game/PaperGameCommandExecutionHelper.java index c63406a6..310ee92e 100644 --- a/bukkit/compat/paper/src/main/java/com/discordsrv/bukkit/command/game/PaperGameCommandExecutionHelper.java +++ b/bukkit/compat/paper/src/main/java/com/discordsrv/bukkit/command/game/PaperGameCommandExecutionHelper.java @@ -18,13 +18,13 @@ package com.discordsrv.bukkit.command.game; +import com.discordsrv.api.task.Task; import com.discordsrv.bukkit.BukkitDiscordSRV; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.ApiStatus; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CompletableFuture; @ApiStatus.AvailableSince("Paper 1.12") public class PaperGameCommandExecutionHelper extends BukkitGameCommandExecutionHelper { @@ -34,7 +34,7 @@ public class PaperGameCommandExecutionHelper extends BukkitGameCommandExecutionH } @Override - public CompletableFuture> getRootCommands(CommandSender commandSender) { + public Task> getRootCommands(CommandSender commandSender) { return discordSRV.scheduler().supplyOnMainThread( commandSender, () -> new ArrayList<>(discordSRV.server().getCommandMap().getKnownCommands().keySet()) diff --git a/bukkit/shared/src/main/java/com/discordsrv/bukkit/ban/BukkitBanModule.java b/bukkit/shared/src/main/java/com/discordsrv/bukkit/ban/BukkitBanModule.java index 1c9e5a90..9f764710 100644 --- a/bukkit/shared/src/main/java/com/discordsrv/bukkit/ban/BukkitBanModule.java +++ b/bukkit/shared/src/main/java/com/discordsrv/bukkit/ban/BukkitBanModule.java @@ -21,6 +21,7 @@ package com.discordsrv.bukkit.ban; import com.discordsrv.api.component.MinecraftComponent; import com.discordsrv.api.module.type.PunishmentModule; import com.discordsrv.api.punishment.Punishment; +import com.discordsrv.api.task.Task; import com.discordsrv.bukkit.BukkitDiscordSRV; import com.discordsrv.common.core.module.type.AbstractModule; import com.discordsrv.common.feature.bansync.BanSyncModule; @@ -39,7 +40,6 @@ import org.jetbrains.annotations.Nullable; import java.time.Instant; import java.util.Date; import java.util.UUID; -import java.util.concurrent.CompletableFuture; public class BukkitBanModule extends AbstractModule implements Listener, PunishmentModule.Bans { @@ -72,7 +72,7 @@ public class BukkitBanModule extends AbstractModule implements } @Override - public CompletableFuture<@Nullable Punishment> getBan(@NotNull UUID playerUUID) { + public Task<@Nullable Punishment> getBan(@NotNull UUID playerUUID) { BanList banList = discordSRV.server().getBanList(BanList.Type.NAME); return discordSRV.playerProvider().lookupOfflinePlayer(playerUUID) .thenApply(offlinePlayer -> banList.getBanEntry(offlinePlayer.username())) @@ -90,7 +90,7 @@ public class BukkitBanModule extends AbstractModule implements } @Override - public CompletableFuture addBan( + public Task addBan( @NotNull UUID playerUUID, @Nullable Instant until, @Nullable MinecraftComponent reason, @@ -107,7 +107,7 @@ public class BukkitBanModule extends AbstractModule implements } @Override - public CompletableFuture removeBan(@NotNull UUID playerUUID) { + public Task removeBan(@NotNull UUID playerUUID) { BanList banList = discordSRV.server().getBanList(BanList.Type.NAME); return discordSRV.playerProvider().lookupOfflinePlayer(playerUUID).thenApply(offlinePlayer -> { banList.pardon(offlinePlayer.username()); diff --git a/bukkit/shared/src/main/java/com/discordsrv/bukkit/command/game/BukkitGameCommandExecutionHelper.java b/bukkit/shared/src/main/java/com/discordsrv/bukkit/command/game/BukkitGameCommandExecutionHelper.java index 145bfcd8..232d4ba6 100644 --- a/bukkit/shared/src/main/java/com/discordsrv/bukkit/command/game/BukkitGameCommandExecutionHelper.java +++ b/bukkit/shared/src/main/java/com/discordsrv/bukkit/command/game/BukkitGameCommandExecutionHelper.java @@ -18,6 +18,7 @@ package com.discordsrv.bukkit.command.game; +import com.discordsrv.api.task.Task; import com.discordsrv.bukkit.BukkitDiscordSRV; import com.discordsrv.common.command.game.abstraction.GameCommandExecutionHelper; import org.bukkit.command.Command; @@ -28,7 +29,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; -import java.util.concurrent.CompletableFuture; public class BukkitGameCommandExecutionHelper implements GameCommandExecutionHelper { @@ -38,12 +38,12 @@ public class BukkitGameCommandExecutionHelper implements GameCommandExecutionHel this.discordSRV = discordSRV; } - public CompletableFuture> getRootCommands(CommandSender commandSender) { - return CompletableFuture.completedFuture(Collections.emptyList()); + public Task> getRootCommands(CommandSender commandSender) { + return Task.completed(Collections.emptyList()); } @Override - public CompletableFuture> suggestCommands(List parts) { + public Task> suggestCommands(List parts) { CommandSender commandSender = discordSRV.server().getConsoleSender(); String commandName = !parts.isEmpty() ? parts.remove(0) : null; @@ -51,7 +51,7 @@ public class BukkitGameCommandExecutionHelper implements GameCommandExecutionHel if (command == null) { if (parts.size() > 1) { // Command is not known but there are arguments, nothing to auto complete... - return CompletableFuture.completedFuture(Collections.emptyList()); + return Task.completed(Collections.emptyList()); } else { return getRootCommands(commandSender).thenApply(commands -> { List suggestions = new ArrayList<>(commands.size()); diff --git a/bukkit/shared/src/main/java/com/discordsrv/bukkit/player/BukkitPlayer.java b/bukkit/shared/src/main/java/com/discordsrv/bukkit/player/BukkitPlayer.java index d565325d..093ce52c 100644 --- a/bukkit/shared/src/main/java/com/discordsrv/bukkit/player/BukkitPlayer.java +++ b/bukkit/shared/src/main/java/com/discordsrv/bukkit/player/BukkitPlayer.java @@ -18,6 +18,7 @@ package com.discordsrv.bukkit.player; +import com.discordsrv.api.task.Task; import com.discordsrv.bukkit.BukkitDiscordSRV; import com.discordsrv.bukkit.command.game.sender.BukkitCommandSender; import com.discordsrv.common.abstraction.player.IPlayer; @@ -31,7 +32,6 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Locale; -import java.util.concurrent.CompletableFuture; public abstract class BukkitPlayer extends BukkitCommandSender implements IPlayer { @@ -55,7 +55,7 @@ public abstract class BukkitPlayer extends BukkitCommandSender implements IPlaye } @Override - public CompletableFuture kick(Component component) { + public Task kick(Component component) { String legacy = BukkitComponentSerializer.legacy().serialize(component); return discordSRV.scheduler().executeOnMainThread(player, () -> player.kickPlayer(legacy)); } diff --git a/bukkit/shared/src/main/java/com/discordsrv/bukkit/scheduler/BukkitScheduler.java b/bukkit/shared/src/main/java/com/discordsrv/bukkit/scheduler/BukkitScheduler.java index 297a99c0..bf65f246 100644 --- a/bukkit/shared/src/main/java/com/discordsrv/bukkit/scheduler/BukkitScheduler.java +++ b/bukkit/shared/src/main/java/com/discordsrv/bukkit/scheduler/BukkitScheduler.java @@ -18,11 +18,13 @@ package com.discordsrv.bukkit.scheduler; +import com.discordsrv.api.task.Task; import com.discordsrv.bukkit.BukkitDiscordSRV; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.core.scheduler.ServerScheduler; import com.discordsrv.common.core.scheduler.StandardScheduler; -import com.discordsrv.common.util.CompletableFutureUtil; +import com.discordsrv.common.util.TaskUtil; +import com.discordsrv.common.util.function.CheckedRunnable; import com.discordsrv.common.util.function.CheckedSupplier; import org.bukkit.Server; import org.bukkit.command.CommandSender; @@ -30,7 +32,6 @@ import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.CheckReturnValue; import org.jetbrains.annotations.NotNull; -import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; public class BukkitScheduler extends StandardScheduler implements ServerScheduler { @@ -72,12 +73,12 @@ public class BukkitScheduler extends StandardScheduler implements ServerSchedule } @CheckReturnValue - public CompletableFuture executeOnMainThread(CommandSender sender, Runnable runnable) { - return CompletableFuture.runAsync(runnable, task -> runOnMainThread(sender, task)); + public Task executeOnMainThread(CommandSender sender, CheckedRunnable runnable) { + return TaskUtil.runAsync(runnable, task -> runOnMainThread(sender, task)); } @CheckReturnValue - public CompletableFuture supplyOnMainThread(CommandSender sender, CheckedSupplier supplier) { - return CompletableFutureUtil.supplyAsync(supplier, task -> runOnMainThread(sender, task)); + public Task supplyOnMainThread(CommandSender sender, CheckedSupplier supplier) { + return TaskUtil.supplyAsync(supplier, task -> runOnMainThread(sender, task)); } } diff --git a/bukkit/src/main/java/com/discordsrv/bukkit/player/BukkitPlayerImpl.java b/bukkit/src/main/java/com/discordsrv/bukkit/player/BukkitPlayerImpl.java index e9f3de75..6aa77f2c 100644 --- a/bukkit/src/main/java/com/discordsrv/bukkit/player/BukkitPlayerImpl.java +++ b/bukkit/src/main/java/com/discordsrv/bukkit/player/BukkitPlayerImpl.java @@ -19,6 +19,7 @@ package com.discordsrv.bukkit.player; import com.discordsrv.api.component.MinecraftComponent; +import com.discordsrv.api.task.Task; import com.discordsrv.bukkit.BukkitDiscordSRV; import com.discordsrv.bukkit.component.PaperComponentHandle; import com.discordsrv.common.abstraction.player.provider.model.SkinInfo; @@ -30,7 +31,6 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Locale; -import java.util.concurrent.CompletableFuture; public class BukkitPlayerImpl extends BukkitPlayer { @@ -39,7 +39,7 @@ public class BukkitPlayerImpl extends BukkitPlayer { } @Override - public CompletableFuture kick(Component component) { + public Task kick(Component component) { if (PaperComponentHandle.IS_AVAILABLE) { return discordSRV.scheduler().executeOnMainThread(player, () -> PaperPlayerUtil.kick(player, ComponentUtil.toAPI(component))); } diff --git a/bungee/src/main/java/com/discordsrv/bungee/player/BungeePlayer.java b/bungee/src/main/java/com/discordsrv/bungee/player/BungeePlayer.java index ac973687..16b022d5 100644 --- a/bungee/src/main/java/com/discordsrv/bungee/player/BungeePlayer.java +++ b/bungee/src/main/java/com/discordsrv/bungee/player/BungeePlayer.java @@ -18,6 +18,7 @@ package com.discordsrv.bungee.player; +import com.discordsrv.api.task.Task; import com.discordsrv.bungee.BungeeDiscordSRV; import com.discordsrv.bungee.command.game.sender.BungeeCommandSender; import com.discordsrv.bungee.component.util.BungeeComponentUtil; @@ -33,7 +34,6 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Locale; -import java.util.concurrent.CompletableFuture; public class BungeePlayer extends BungeeCommandSender implements IPlayer { @@ -57,9 +57,9 @@ public class BungeePlayer extends BungeeCommandSender implements IPlayer { } @Override - public CompletableFuture kick(Component component) { + public Task kick(Component component) { player.disconnect(BungeeComponentSerializer.get().serialize(component)); - return CompletableFuture.completedFuture(null); + return Task.completed(null); } @Override diff --git a/common/src/main/java/com/discordsrv/common/AbstractDiscordSRV.java b/common/src/main/java/com/discordsrv/common/AbstractDiscordSRV.java index 5129979b..5ebf2186 100644 --- a/common/src/main/java/com/discordsrv/common/AbstractDiscordSRV.java +++ b/common/src/main/java/com/discordsrv/common/AbstractDiscordSRV.java @@ -25,6 +25,7 @@ import com.discordsrv.api.events.lifecycle.DiscordSRVShuttingDownEvent; import com.discordsrv.api.module.Module; import com.discordsrv.api.reload.ReloadFlag; import com.discordsrv.api.reload.ReloadResult; +import com.discordsrv.api.task.Task; import com.discordsrv.common.abstraction.bootstrap.IBootstrap; import com.discordsrv.common.command.discord.DiscordCommandModule; import com.discordsrv.common.command.game.GameCommandModule; @@ -111,7 +112,6 @@ import java.time.LocalDateTime; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.*; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -614,7 +614,7 @@ public abstract class AbstractDiscordSRV< * Must be manually triggered for {@link DiscordSRV.ServerType#SERVER}, automatically triggered in {@link #enable()} for {@link DiscordSRV.ServerType#PROXY}. * @return a future running on the {@link #scheduler()} */ - public final CompletableFuture runServerStarted() { + public final Task runServerStarted() { return scheduler().execute(() -> { if (status().isShutdown()) { // Already shutdown/shutting down, don't bother @@ -653,7 +653,7 @@ public abstract class AbstractDiscordSRV< } @Override - public final CompletableFuture runDisable() { + public final Task runDisable() { return scheduler().execute(this::disable); } diff --git a/common/src/main/java/com/discordsrv/common/DiscordSRV.java b/common/src/main/java/com/discordsrv/common/DiscordSRV.java index df43f610..23b2412a 100644 --- a/common/src/main/java/com/discordsrv/common/DiscordSRV.java +++ b/common/src/main/java/com/discordsrv/common/DiscordSRV.java @@ -20,8 +20,10 @@ package com.discordsrv.common; import com.discordsrv.api.DiscordSRVApi; import com.discordsrv.api.module.Module; -import com.discordsrv.api.reload.ReloadFlag; import com.discordsrv.api.placeholder.format.PlainPlaceholderFormat; +import com.discordsrv.api.reload.ReloadFlag; +import com.discordsrv.api.reload.ReloadResult; +import com.discordsrv.api.task.Task; import com.discordsrv.common.abstraction.bootstrap.IBootstrap; import com.discordsrv.common.abstraction.player.IPlayer; import com.discordsrv.common.abstraction.player.provider.AbstractPlayerProvider; @@ -29,7 +31,6 @@ import com.discordsrv.common.abstraction.plugin.PluginManager; import com.discordsrv.common.command.game.abstraction.GameCommandExecutionHelper; import com.discordsrv.common.command.game.abstraction.handler.ICommandHandler; import com.discordsrv.common.command.game.abstraction.sender.ICommandSender; -import com.discordsrv.api.reload.ReloadResult; import com.discordsrv.common.config.configurate.manager.ConnectionConfigManager; import com.discordsrv.common.config.configurate.manager.MainConfigManager; import com.discordsrv.common.config.configurate.manager.MessagesConfigManager; @@ -68,7 +69,6 @@ import java.time.ZonedDateTime; import java.util.List; import java.util.Locale; import java.util.Set; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; public interface DiscordSRV extends DiscordSRVApi { @@ -177,7 +177,7 @@ public interface DiscordSRV extends DiscordSRVApi { // Lifecycle void runEnable(); List runReload(Set flags); - CompletableFuture runDisable(); + Task runDisable(); boolean isServerStarted(); ZonedDateTime getInitializeTime(); diff --git a/common/src/main/java/com/discordsrv/common/abstraction/bootstrap/LifecycleManager.java b/common/src/main/java/com/discordsrv/common/abstraction/bootstrap/LifecycleManager.java index 6de22338..1b4a013a 100644 --- a/common/src/main/java/com/discordsrv/common/abstraction/bootstrap/LifecycleManager.java +++ b/common/src/main/java/com/discordsrv/common/abstraction/bootstrap/LifecycleManager.java @@ -19,6 +19,7 @@ package com.discordsrv.common.abstraction.bootstrap; import com.discordsrv.api.reload.ReloadFlag; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.core.dependency.DependencyLoader; import com.discordsrv.common.core.logging.Logger; @@ -28,7 +29,6 @@ import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -42,7 +42,7 @@ public class LifecycleManager { private final Logger logger; private final ExecutorService taskPool; private final DependencyLoader dependencyLoader; - private CompletableFuture dependencyLoadFuture; + private Task dependencyLoadFuture; public LifecycleManager( Logger logger, diff --git a/common/src/main/java/com/discordsrv/common/abstraction/player/IPlayer.java b/common/src/main/java/com/discordsrv/common/abstraction/player/IPlayer.java index 8698303b..672b8e82 100644 --- a/common/src/main/java/com/discordsrv/common/abstraction/player/IPlayer.java +++ b/common/src/main/java/com/discordsrv/common/abstraction/player/IPlayer.java @@ -22,6 +22,7 @@ import com.discordsrv.api.component.MinecraftComponent; import com.discordsrv.api.placeholder.annotation.Placeholder; import com.discordsrv.api.placeholder.annotation.PlaceholderPrefix; import com.discordsrv.api.player.DiscordSRVPlayer; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.command.game.abstraction.sender.ICommandSender; import com.discordsrv.common.feature.profile.Profile; @@ -32,7 +33,6 @@ import org.jetbrains.annotations.NotNull; import java.util.Collection; import java.util.UUID; -import java.util.concurrent.CompletableFuture; @PlaceholderPrefix("player_") public interface IPlayer extends DiscordSRVPlayer, IOfflinePlayer, ICommandSender { @@ -63,7 +63,7 @@ public interface IPlayer extends DiscordSRVPlayer, IOfflinePlayer, ICommandSende return identity().uuid(); } - CompletableFuture kick(Component component); + Task kick(Component component); void addChatSuggestions(Collection suggestions); void removeChatSuggestions(Collection suggestions); diff --git a/common/src/main/java/com/discordsrv/common/abstraction/sync/AbstractSyncModule.java b/common/src/main/java/com/discordsrv/common/abstraction/sync/AbstractSyncModule.java index 7886236c..d8109463 100644 --- a/common/src/main/java/com/discordsrv/common/abstraction/sync/AbstractSyncModule.java +++ b/common/src/main/java/com/discordsrv/common/abstraction/sync/AbstractSyncModule.java @@ -39,7 +39,6 @@ import org.jetbrains.annotations.Nullable; import java.time.Duration; import java.util.*; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; @@ -348,7 +347,7 @@ public abstract class AbstractSyncModule< }); } - protected CompletableFuture> resync(ISyncCause cause, C config, Someone someone) { + protected Task> resync(ISyncCause cause, C config, Someone someone) { return someone.withLinkedAccounts(discordSRV).thenApply(resolved -> { if (resolved == null) { return new SyncSummary<>(this, cause, someone).fail(GenericSyncResults.NOT_LINKED); diff --git a/common/src/main/java/com/discordsrv/common/command/combined/commands/LinkOtherCommand.java b/common/src/main/java/com/discordsrv/common/command/combined/commands/LinkOtherCommand.java index bee3aef9..86311cc8 100644 --- a/common/src/main/java/com/discordsrv/common/command/combined/commands/LinkOtherCommand.java +++ b/common/src/main/java/com/discordsrv/common/command/combined/commands/LinkOtherCommand.java @@ -21,6 +21,7 @@ package com.discordsrv.common.command.combined.commands; import com.discordsrv.api.discord.entity.interaction.command.CommandOption; import com.discordsrv.api.discord.entity.interaction.command.DiscordCommand; import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.command.combined.abstraction.CombinedCommand; import com.discordsrv.common.command.combined.abstraction.CommandExecution; @@ -39,7 +40,6 @@ import com.discordsrv.common.util.CommandUtil; import net.kyori.adventure.text.format.NamedTextColor; import java.util.UUID; -import java.util.concurrent.CompletableFuture; public class LinkOtherCommand extends CombinedCommand { @@ -123,8 +123,8 @@ public class LinkOtherCommand extends CombinedCommand { } } - CompletableFuture playerUUIDFuture = CommandUtil.lookupPlayer(discordSRV, logger, execution, false, playerArgument, null); - CompletableFuture userIdFuture = CommandUtil.lookupUser(discordSRV, logger, execution, false, userArgument, null); + Task playerUUIDFuture = CommandUtil.lookupPlayer(discordSRV, logger, execution, false, playerArgument, null); + Task userIdFuture = CommandUtil.lookupUser(discordSRV, logger, execution, false, userArgument, null); playerUUIDFuture.whenComplete((playerUUID, __) -> userIdFuture.whenComplete((userId, ___) -> { if (playerUUID == null) { diff --git a/common/src/main/java/com/discordsrv/common/command/combined/commands/ResyncCommand.java b/common/src/main/java/com/discordsrv/common/command/combined/commands/ResyncCommand.java index 6ea151db..cb880fd6 100644 --- a/common/src/main/java/com/discordsrv/common/command/combined/commands/ResyncCommand.java +++ b/common/src/main/java/com/discordsrv/common/command/combined/commands/ResyncCommand.java @@ -41,7 +41,6 @@ import net.kyori.adventure.text.format.NamedTextColor; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -142,7 +141,7 @@ public class ResyncCommand extends CombinedCommand { long startTime = System.currentTimeMillis(); List>> futures = resyncOnlinePlayers(module); - Task.allOfGeneric(futures).thenCompose(result -> { + Task.allOfGeneric(futures).then(result -> { List> results = new ArrayList<>(); for (SyncSummary summary : result) { results.add(summary.resultFuture()); @@ -153,7 +152,7 @@ public class ResyncCommand extends CombinedCommand { int total = 0; List results = new ArrayList<>(); - for (CompletableFuture> future : futures) { + for (Task> future : futures) { SyncSummary summary = future.join(); ISyncResult allFailResult = summary.allFailReason(); if (allFailResult != null) { diff --git a/common/src/main/java/com/discordsrv/common/command/game/abstraction/GameCommandExecutionHelper.java b/common/src/main/java/com/discordsrv/common/command/game/abstraction/GameCommandExecutionHelper.java index a31f384e..4ff1d712 100644 --- a/common/src/main/java/com/discordsrv/common/command/game/abstraction/GameCommandExecutionHelper.java +++ b/common/src/main/java/com/discordsrv/common/command/game/abstraction/GameCommandExecutionHelper.java @@ -18,12 +18,13 @@ package com.discordsrv.common.command.game.abstraction; +import com.discordsrv.api.task.Task; + import java.util.List; -import java.util.concurrent.CompletableFuture; public interface GameCommandExecutionHelper { - CompletableFuture> suggestCommands(List parts); + Task> suggestCommands(List parts); List getAliases(String command); boolean isSameCommand(String command1, String command2); diff --git a/common/src/main/java/com/discordsrv/common/command/game/commands/subcommand/BroadcastCommand.java b/common/src/main/java/com/discordsrv/common/command/game/commands/subcommand/BroadcastCommand.java index 4b97d2ff..96b4ba51 100644 --- a/common/src/main/java/com/discordsrv/common/command/game/commands/subcommand/BroadcastCommand.java +++ b/common/src/main/java/com/discordsrv/common/command/game/commands/subcommand/BroadcastCommand.java @@ -22,6 +22,7 @@ import com.discordsrv.api.component.MinecraftComponent; import com.discordsrv.api.discord.entity.channel.DiscordGuildMessageChannel; import com.discordsrv.api.discord.entity.channel.DiscordMessageChannel; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.command.game.abstraction.command.GameCommand; import com.discordsrv.common.command.game.abstraction.command.GameCommandArguments; @@ -37,7 +38,6 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import java.util.*; -import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -103,7 +103,7 @@ public abstract class BroadcastCommand implements GameCommandExecutor, GameComma String content = arguments.getString("content"); Set channels = new HashSet<>(); - CompletableFuture> future = null; + Task> future = null; try { long id = Long.parseUnsignedLong(channel); diff --git a/common/src/main/java/com/discordsrv/common/core/dependency/DependencyLoader.java b/common/src/main/java/com/discordsrv/common/core/dependency/DependencyLoader.java index 9eb981bd..16a19eb7 100644 --- a/common/src/main/java/com/discordsrv/common/core/dependency/DependencyLoader.java +++ b/common/src/main/java/com/discordsrv/common/core/dependency/DependencyLoader.java @@ -18,6 +18,7 @@ package com.discordsrv.common.core.dependency; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.core.logging.Logger; import dev.vankka.dependencydownload.DependencyManager; @@ -33,7 +34,6 @@ import java.net.URL; import java.nio.file.Path; import java.util.Arrays; import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; public class DependencyLoader { @@ -100,12 +100,12 @@ public class DependencyLoader { return classLoader; } - public CompletableFuture downloadRelocateAndLoad() { + public Task downloadRelocateAndLoad() { return downloadRelocateAndLoad(classpathAppender); } - private CompletableFuture downloadRelocateAndLoad(ClasspathAppender appender) { - return dependencyManager.downloadAll(executor, REPOSITORIES) + private Task downloadRelocateAndLoad(ClasspathAppender appender) { + return Task.of(dependencyManager.downloadAll(executor, REPOSITORIES)) .thenCompose(v -> dependencyManager.relocateAll(executor)) .thenCompose(v -> dependencyManager.loadAll(executor, appender)); } diff --git a/common/src/main/java/com/discordsrv/common/core/placeholder/context/GamePermissionContext.java b/common/src/main/java/com/discordsrv/common/core/placeholder/context/GamePermissionContext.java index d6c6a2b3..8bba8067 100644 --- a/common/src/main/java/com/discordsrv/common/core/placeholder/context/GamePermissionContext.java +++ b/common/src/main/java/com/discordsrv/common/core/placeholder/context/GamePermissionContext.java @@ -21,12 +21,12 @@ package com.discordsrv.common.core.placeholder.context; import com.discordsrv.api.module.type.PermissionModule; import com.discordsrv.api.placeholder.annotation.Placeholder; import com.discordsrv.api.placeholder.format.FormattedText; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.abstraction.player.IOfflinePlayer; import net.kyori.adventure.text.Component; import java.util.UUID; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.function.Function; @@ -75,7 +75,7 @@ public class GamePermissionContext { private Component getPermissionMeta( String what, - Function> function + Function> function ) { PermissionModule.PrefixAndSuffix permission = discordSRV.getModule(PermissionModule.PrefixAndSuffix.class); if (permission == null) { diff --git a/common/src/main/java/com/discordsrv/common/core/scheduler/ServerScheduler.java b/common/src/main/java/com/discordsrv/common/core/scheduler/ServerScheduler.java index df3ada91..aabd7f9a 100644 --- a/common/src/main/java/com/discordsrv/common/core/scheduler/ServerScheduler.java +++ b/common/src/main/java/com/discordsrv/common/core/scheduler/ServerScheduler.java @@ -19,13 +19,11 @@ package com.discordsrv.common.core.scheduler; import com.discordsrv.api.task.Task; -import com.discordsrv.common.util.CompletableFutureUtil; import com.discordsrv.common.util.TaskUtil; import com.discordsrv.common.util.function.CheckedRunnable; import com.discordsrv.common.util.function.CheckedSupplier; import org.jetbrains.annotations.NotNull; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @SuppressWarnings("unused") // API @@ -71,14 +69,12 @@ public interface ServerScheduler extends Scheduler { */ void runOnMainThreadLaterInTicks(@NotNull Runnable task, int ticks); - @NotNull - default CompletableFuture executeOnMainThreadLaterInTicks(@NotNull CheckedRunnable task, int ticks) { - return CompletableFutureUtil.runAsync(task, t -> runOnMainThreadLaterInTicks(t, ticks)); + default @NotNull Task executeOnMainThreadLaterInTicks(@NotNull CheckedRunnable task, int ticks) { + return TaskUtil.runAsync(task, t -> runOnMainThreadLaterInTicks(t, ticks)); } - @NotNull - default CompletableFuture supplyOnMainThreadLaterInTicks(@NotNull CheckedSupplier task, int ticks) { - return CompletableFutureUtil.supplyAsync(task, t -> runOnMainThreadLaterInTicks(t, ticks)); + default @NotNull Task supplyOnMainThreadLaterInTicks(@NotNull CheckedSupplier task, int ticks) { + return TaskUtil.supplyAsync(task, t -> runOnMainThreadLaterInTicks(t, ticks)); } /** diff --git a/common/src/main/java/com/discordsrv/common/discord/api/DiscordAPIImpl.java b/common/src/main/java/com/discordsrv/common/discord/api/DiscordAPIImpl.java index 449565d2..495aba64 100644 --- a/common/src/main/java/com/discordsrv/common/discord/api/DiscordAPIImpl.java +++ b/common/src/main/java/com/discordsrv/common/discord/api/DiscordAPIImpl.java @@ -41,8 +41,6 @@ import com.discordsrv.common.discord.api.entity.guild.DiscordCustomEmojiImpl; import com.discordsrv.common.discord.api.entity.guild.DiscordGuildImpl; import com.discordsrv.common.discord.api.entity.guild.DiscordGuildMemberImpl; import com.discordsrv.common.discord.api.entity.guild.DiscordRoleImpl; -import com.discordsrv.common.util.CompletableFutureUtil; -import com.discordsrv.common.util.function.CheckedSupplier; import com.github.benmanes.caffeine.cache.AsyncCacheLoader; import com.github.benmanes.caffeine.cache.AsyncLoadingCache; import com.github.benmanes.caffeine.cache.Expiry; @@ -56,6 +54,7 @@ import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.entities.emoji.CustomEmoji; import net.dv8tion.jda.api.exceptions.ErrorResponseException; import net.dv8tion.jda.api.requests.ErrorResponse; +import net.dv8tion.jda.api.requests.RestAction; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -65,6 +64,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.function.Function; +import java.util.function.Supplier; public class DiscordAPIImpl implements DiscordAPI { @@ -80,50 +80,29 @@ public class DiscordAPIImpl implements DiscordAPI { .buildAsync(new WebhookCacheLoader()); } - public CompletableFuture> queryWebhookClient(long channelId) { - return cachedClients.get(channelId); + public Task> queryWebhookClient(long channelId) { + return Task.of(cachedClients.get(channelId)); } public AsyncLoadingCache> getCachedClients() { return cachedClients; } - public CompletableFuture mapExceptions(CheckedSupplier> futureSupplier) { + public Task toTask(Supplier> jdaRestActionSupplier) { try { - return mapExceptions(futureSupplier.get()); - } catch (Throwable t) { - return CompletableFutureUtil.failed(t); - } - } - - public CompletableFuture mapExceptions(CompletableFuture future) { - return future.handle((response, t) -> { - if (t instanceof ErrorResponseException) { - ErrorResponseException exception = (ErrorResponseException) t; - int code = exception.getErrorCode(); - ErrorResponse errorResponse = exception.getErrorResponse(); - throw new RestErrorResponseException(code, errorResponse.getMeaning(), t); - } else if (t != null) { - throw (RuntimeException) t; - } - return response; - }); - } - - public Task mapExceptions(CheckedSupplier> futureSupplier) { - try { - return mapExceptions(futureSupplier.get()); + RestAction restAction = jdaRestActionSupplier.get(); + return toTask(restAction); } catch (Throwable t) { return Task.failed(t); } } - public Task mapExceptions(Task future) { - return future - .mapException(ErrorResponseException.class, t -> { - int code = t.getErrorCode(); - ErrorResponse errorResponse = t.getErrorResponse(); - throw new RestErrorResponseException(code, errorResponse.getMeaning(), t); + public Task toTask(RestAction jdaRestAction) { + return Task.of(jdaRestAction.submit()) + .mapException(ErrorResponseException.class, exception -> { + int code = exception.getErrorCode(); + ErrorResponse errorResponse = exception.getErrorResponse(); + throw new RestErrorResponseException(code, errorResponse.getMeaning(), exception); }); } @@ -320,10 +299,7 @@ public class DiscordAPIImpl implements DiscordAPI { return notReady(); } - return mapExceptions( - Task.of(jda.retrieveUserById(id).submit()) - .thenApply(this::getUser) - ); + return toTask(() -> jda.retrieveUserById(id)).thenApply(this::getUser); } @Override @@ -374,13 +350,17 @@ public class DiscordAPIImpl implements DiscordAPI { public @NotNull CompletableFuture> asyncLoad(@NotNull Long channelId, @NotNull Executor executor) { JDA jda = discordSRV.jda(); if (jda == null) { - return CompletableFutureUtil.failed(new NotReadyException()); + CompletableFuture> future = new CompletableFuture<>(); + future.completeExceptionally(new NotReadyException()); + return future; } GuildChannel channel = jda.getGuildChannelById(channelId); IWebhookContainer webhookContainer = channel instanceof IWebhookContainer ? (IWebhookContainer) channel : null; if (webhookContainer == null) { - return CompletableFutureUtil.failed(new IllegalArgumentException("Channel could not be found")); + CompletableFuture> future = new CompletableFuture<>(); + future.completeExceptionally(new IllegalArgumentException("Channel could not be found")); + return future; } return webhookContainer.retrieveWebhooks().submit().thenApply(webhooks -> { diff --git a/common/src/main/java/com/discordsrv/common/discord/api/entity/DiscordUserImpl.java b/common/src/main/java/com/discordsrv/common/discord/api/entity/DiscordUserImpl.java index 20e72839..87f2b248 100644 --- a/common/src/main/java/com/discordsrv/common/discord/api/entity/DiscordUserImpl.java +++ b/common/src/main/java/com/discordsrv/common/discord/api/entity/DiscordUserImpl.java @@ -87,11 +87,9 @@ public class DiscordUserImpl implements DiscordUser { return discordSRV.discordAPI().notReady(); } - return discordSRV.discordAPI().mapExceptions( - Task.of(jda.retrieveUserById(getId()).submit()) - .thenCompose(user -> user.openPrivateChannel().submit()) - .thenApply(privateChannel -> new DiscordDMChannelImpl(discordSRV, privateChannel)) - ); + return discordSRV.discordAPI().toTask(() -> jda.retrieveUserById(getId())) + .then(user -> discordSRV.discordAPI().toTask(() -> user.openPrivateChannel())) + .thenApply(privateChannel -> new DiscordDMChannelImpl(discordSRV, privateChannel)); } @Override diff --git a/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/AbstractDiscordForumChannel.java b/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/AbstractDiscordForumChannel.java index 35720617..03c38f71 100644 --- a/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/AbstractDiscordForumChannel.java +++ b/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/AbstractDiscordForumChannel.java @@ -22,6 +22,7 @@ import com.discordsrv.api.discord.entity.channel.DiscordChannel; import com.discordsrv.api.discord.entity.channel.DiscordThreadChannel; import com.discordsrv.api.discord.entity.channel.DiscordThreadContainer; import com.discordsrv.api.discord.entity.guild.DiscordGuild; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import net.dv8tion.jda.api.entities.channel.attribute.IPostContainer; import net.dv8tion.jda.api.entities.channel.attribute.IThreadContainer; @@ -32,7 +33,6 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.function.Function; import java.util.stream.Collectors; @@ -69,8 +69,8 @@ public abstract class AbstractDiscordForumChannel imp } @Override - public CompletableFuture delete() { - return discordSRV.discordAPI().mapExceptions(() -> channel.delete().submit()); + public Task delete() { + return discordSRV.discordAPI().toTask(channel::delete); } @Override @@ -84,40 +84,35 @@ public abstract class AbstractDiscordForumChannel imp } @Override - public CompletableFuture> retrieveArchivedPrivateThreads() { + public Task> retrieveArchivedPrivateThreads() { return threads(IThreadContainer::retrieveArchivedPrivateThreadChannels); } @Override - public CompletableFuture> retrieveArchivedJoinedPrivateThreads() { + public Task> retrieveArchivedJoinedPrivateThreads() { return threads(IThreadContainer::retrieveArchivedPrivateJoinedThreadChannels); } @Override - public CompletableFuture> retrieveArchivedPublicThreads() { + public Task> retrieveArchivedPublicThreads() { return threads(IThreadContainer::retrieveArchivedPublicThreadChannels); } - @SuppressWarnings("CodeBlock2Expr") - private CompletableFuture> threads( - Function action) { - return discordSRV.discordAPI().mapExceptions(() -> { - return action.apply(channel) - .submit() - .thenApply(channels -> channels.stream() - .map(channel -> discordSRV.discordAPI().getThreadChannel(channel)) - .collect(Collectors.toList()) - ); - }); + private Task> threads(Function action) { + return discordSRV.discordAPI().toTask(() -> action.apply(channel)) + .thenApply(channels -> channels.stream() + .map(channel -> discordSRV.discordAPI().getThreadChannel(channel)) + .collect(Collectors.toList()) + ); } @Override - public CompletableFuture createThread(String name, boolean privateThread) { + public Task createThread(String name, boolean privateThread) { throw new IllegalStateException("Cannot create Threads in Forums without a message"); } @Override - public CompletableFuture createThread(String name, long messageId) { + public Task createThread(String name, long messageId) { return thread(channel -> channel.createThreadChannel(name, messageId), result -> result); } @@ -126,16 +121,12 @@ public abstract class AbstractDiscordForumChannel imp return channel; } - @SuppressWarnings("CodeBlock2Expr") - protected CompletableFuture thread( + protected Task thread( Function> action, Function resultMapper ) { - return discordSRV.discordAPI().mapExceptions(() -> { - return action.apply(channel) - .submit() + return discordSRV.discordAPI().toTask(() -> action.apply(channel)) .thenApply(result -> discordSRV.discordAPI().getThreadChannel(resultMapper.apply(result))); - }); } } diff --git a/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/AbstractDiscordGuildMessageChannel.java b/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/AbstractDiscordGuildMessageChannel.java index a2491c0a..35c51fe0 100644 --- a/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/AbstractDiscordGuildMessageChannel.java +++ b/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/AbstractDiscordGuildMessageChannel.java @@ -22,6 +22,7 @@ import com.discordsrv.api.discord.entity.channel.DiscordGuildMessageChannel; import com.discordsrv.api.discord.entity.guild.DiscordGuild; import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessage; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.discord.api.entity.message.ReceivedDiscordMessageImpl; import com.discordsrv.common.discord.api.entity.message.util.SendableDiscordMessageUtil; @@ -39,8 +40,6 @@ import net.dv8tion.jda.api.utils.messages.MessageEditData; import net.dv8tion.jda.api.utils.messages.MessageEditRequest; import org.jetbrains.annotations.NotNull; -import java.util.concurrent.CompletableFuture; - public abstract class AbstractDiscordGuildMessageChannel extends AbstractDiscordMessageChannel implements DiscordGuildMessageChannel { @@ -52,7 +51,7 @@ public abstract class AbstractDiscordGuildMessageChannel> queryWebhookClient() { + public Task> queryWebhookClient() { return discordSRV.discordAPI().queryWebhookClient(getId()); } @@ -77,7 +76,7 @@ public abstract class AbstractDiscordGuildMessageChannel sendMessage(@NotNull SendableDiscordMessage message) { + public @NotNull Task sendMessage(@NotNull SendableDiscordMessage message) { return sendInternal(message); } @@ -86,10 +85,10 @@ public abstract class AbstractDiscordGuildMessageChannel> & RestAction> CompletableFuture sendInternal(SendableDiscordMessage message) { + private > & RestAction> Task sendInternal(SendableDiscordMessage message) { MessageCreateData createData = SendableDiscordMessageUtil.toJDASend(message); - CompletableFuture createRequest; + Task createRequest; if (message.isWebhookMessage()) { createRequest = queryWebhookClient() .thenApply(client -> (R) mapAction(client.sendMessage(createData)) @@ -103,7 +102,7 @@ public abstract class AbstractDiscordGuildMessageChannel editMessageById( + public @NotNull Task editMessageById( long id, @NotNull SendableDiscordMessage message ) { @@ -124,21 +123,21 @@ public abstract class AbstractDiscordGuildMessageChannel> & RestAction> CompletableFuture editInternal( + private > & RestAction> Task editInternal( long id, SendableDiscordMessage message ) { MessageEditData editData = SendableDiscordMessageUtil.toJDAEdit(message); - CompletableFuture editRequest; + Task editRequest; if (message.isWebhookMessage()) { editRequest = queryWebhookClient().thenApply(client -> (R) mapAction(client.editMessageById(id, editData))); } else { - editRequest = CompletableFuture.completedFuture(((R) channel.editMessageById(id, editData))); + editRequest = Task.completed(((R) channel.editMessageById(id, editData))); } return editRequest - .thenCompose(RestAction::submit) + .then(restAction -> discordSRV.discordAPI().toTask(restAction)) .thenApply(msg -> ReceivedDiscordMessageImpl.fromJDA(discordSRV, msg)); } @@ -147,18 +146,19 @@ public abstract class AbstractDiscordGuildMessageChannel deleteMessageById(long id, boolean webhookMessage) { - CompletableFuture future; + public Task deleteMessageById(long id, boolean webhookMessage) { + Task future; if (webhookMessage) { - future = queryWebhookClient().thenCompose(client -> mapAction(client.deleteMessageById(id)).submit()); + future = queryWebhookClient() + .then(client -> discordSRV.discordAPI().toTask(() -> mapAction(client.deleteMessageById(id)))); } else { - future = channel.deleteMessageById(id).submit(); + future = discordSRV.discordAPI().toTask(() -> channel.deleteMessageById(id)); } - return discordSRV.discordAPI().mapExceptions(future); + return future; } @Override - public CompletableFuture delete() { - return discordSRV.discordAPI().mapExceptions(() -> channel.delete().submit()); + public Task delete() { + return discordSRV.discordAPI().toTask(channel::delete); } } diff --git a/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/AbstractDiscordThreadedGuildMessageChannel.java b/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/AbstractDiscordThreadedGuildMessageChannel.java index 5eae9f10..bfbb5837 100644 --- a/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/AbstractDiscordThreadedGuildMessageChannel.java +++ b/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/AbstractDiscordThreadedGuildMessageChannel.java @@ -21,6 +21,7 @@ package com.discordsrv.common.discord.api.entity.channel; import com.discordsrv.api.discord.entity.channel.DiscordGuildMessageChannel; import com.discordsrv.api.discord.entity.channel.DiscordThreadChannel; import com.discordsrv.api.discord.entity.channel.DiscordThreadContainer; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import net.dv8tion.jda.api.entities.channel.attribute.IThreadContainer; import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel; @@ -31,7 +32,6 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.function.Function; import java.util.stream.Collectors; @@ -54,50 +54,41 @@ public abstract class AbstractDiscordThreadedGuildMessageChannel> retrieveArchivedPrivateThreads() { + public Task> retrieveArchivedPrivateThreads() { return threads(IThreadContainer::retrieveArchivedPrivateThreadChannels); } @Override - public CompletableFuture> retrieveArchivedJoinedPrivateThreads() { + public Task> retrieveArchivedJoinedPrivateThreads() { return threads(IThreadContainer::retrieveArchivedPrivateJoinedThreadChannels); } @Override - public CompletableFuture> retrieveArchivedPublicThreads() { + public Task> retrieveArchivedPublicThreads() { return threads(IThreadContainer::retrieveArchivedPublicThreadChannels); } - @SuppressWarnings("CodeBlock2Expr") - private CompletableFuture> threads( - Function action) { - return discordSRV.discordAPI().mapExceptions(() -> { - return action.apply(channel) - .submit() - .thenApply(channels -> channels.stream() - .map(channel -> discordSRV.discordAPI().getThreadChannel(channel)) - .collect(Collectors.toList()) - ); - }); + private Task> threads(Function action) { + return discordSRV.discordAPI().toTask(() -> action.apply(channel)) + .thenApply(channels -> channels.stream() + .map(channel -> discordSRV.discordAPI().getThreadChannel(channel)) + .collect(Collectors.toList()) + ); } @Override - public CompletableFuture createThread(String name, boolean privateThread) { + public Task createThread(String name, boolean privateThread) { return thread(channel -> channel.createThreadChannel(name, privateThread)); } @Override - public CompletableFuture createThread(String name, long messageId) { + public Task createThread(String name, long messageId) { return thread(channel -> channel.createThreadChannel(name, messageId)); } - @SuppressWarnings("CodeBlock2Expr") - private CompletableFuture thread(Function action) { - return discordSRV.discordAPI().mapExceptions(() -> { - return action.apply(channel) - .submit() + private Task thread(Function action) { + return discordSRV.discordAPI().toTask(() -> action.apply(channel)) .thenApply(channel -> discordSRV.discordAPI().getThreadChannel(channel)); - }); } @Override diff --git a/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/DiscordDMChannelImpl.java b/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/DiscordDMChannelImpl.java index d64dafac..ba34b8dd 100644 --- a/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/DiscordDMChannelImpl.java +++ b/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/DiscordDMChannelImpl.java @@ -22,6 +22,7 @@ import com.discordsrv.api.discord.entity.DiscordUser; import com.discordsrv.api.discord.entity.channel.DiscordDMChannel; import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessage; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.discord.api.entity.message.ReceivedDiscordMessageImpl; import com.discordsrv.common.discord.api.entity.message.util.SendableDiscordMessageUtil; @@ -31,7 +32,6 @@ import net.dv8tion.jda.api.requests.restaction.MessageCreateAction; import org.jetbrains.annotations.NotNull; import java.util.Objects; -import java.util.concurrent.CompletableFuture; public class DiscordDMChannelImpl extends AbstractDiscordMessageChannel implements DiscordDMChannel { @@ -49,7 +49,7 @@ public class DiscordDMChannelImpl extends AbstractDiscordMessageChannel sendMessage(@NotNull SendableDiscordMessage message) { + public @NotNull Task sendMessage(@NotNull SendableDiscordMessage message) { if (message.isWebhookMessage()) { throw new IllegalArgumentException("Cannot send webhook messages to DMChannels"); } @@ -61,21 +61,21 @@ public class DiscordDMChannelImpl extends AbstractDiscordMessageChannel future = action.submit() + return discordSRV.discordAPI().toTask(action) .thenApply(msg -> ReceivedDiscordMessageImpl.fromJDA(discordSRV, msg)); - return discordSRV.discordAPI().mapExceptions(future); } @Override - public CompletableFuture deleteMessageById(long id, boolean webhookMessage) { + public Task deleteMessageById(long id, boolean webhookMessage) { if (webhookMessage) { throw new IllegalArgumentException("DMChannels do not contain webhook messages"); } - return discordSRV.discordAPI().mapExceptions(channel.deleteMessageById(id).submit()); + + return discordSRV.discordAPI().toTask(() -> channel.deleteMessageById(id)); } @Override - public @NotNull CompletableFuture editMessageById( + public @NotNull Task editMessageById( long id, @NotNull SendableDiscordMessage message ) { @@ -83,12 +83,9 @@ public class DiscordDMChannelImpl extends AbstractDiscordMessageChannel future = channel - .editMessageById(id, SendableDiscordMessageUtil.toJDAEdit(message)) - .submit() + return discordSRV.discordAPI() + .toTask(channel.editMessageById(id, SendableDiscordMessageUtil.toJDAEdit(message))) .thenApply(msg -> ReceivedDiscordMessageImpl.fromJDA(discordSRV, msg)); - - return discordSRV.discordAPI().mapExceptions(future); } @Override diff --git a/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/DiscordForumChannelImpl.java b/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/DiscordForumChannelImpl.java index 5d1515e9..dc6b975f 100644 --- a/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/DiscordForumChannelImpl.java +++ b/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/DiscordForumChannelImpl.java @@ -22,13 +22,12 @@ import com.discordsrv.api.discord.entity.channel.DiscordChannelType; import com.discordsrv.api.discord.entity.channel.DiscordForumChannel; import com.discordsrv.api.discord.entity.channel.DiscordThreadChannel; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.discord.api.entity.message.util.SendableDiscordMessageUtil; import net.dv8tion.jda.api.entities.channel.concrete.ForumChannel; import net.dv8tion.jda.api.entities.channel.forums.ForumPost; -import java.util.concurrent.CompletableFuture; - public class DiscordForumChannelImpl extends AbstractDiscordForumChannel implements DiscordForumChannel { public DiscordForumChannelImpl(DiscordSRV discordSRV, ForumChannel channel) { @@ -46,7 +45,7 @@ public class DiscordForumChannelImpl extends AbstractDiscordForumChannel createPost(String name, SendableDiscordMessage message) { + public Task createPost(String name, SendableDiscordMessage message) { return thread( channel -> channel.createForumPost(name, SendableDiscordMessageUtil.toJDASend(message)), ForumPost::getThreadChannel diff --git a/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/DiscordMediaChannelImpl.java b/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/DiscordMediaChannelImpl.java index dd611a72..499d4a6a 100644 --- a/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/DiscordMediaChannelImpl.java +++ b/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/DiscordMediaChannelImpl.java @@ -22,13 +22,12 @@ import com.discordsrv.api.discord.entity.channel.DiscordChannelType; import com.discordsrv.api.discord.entity.channel.DiscordMediaChannel; import com.discordsrv.api.discord.entity.channel.DiscordThreadChannel; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.discord.api.entity.message.util.SendableDiscordMessageUtil; import net.dv8tion.jda.api.entities.channel.concrete.MediaChannel; import net.dv8tion.jda.api.entities.channel.forums.ForumPost; -import java.util.concurrent.CompletableFuture; - public class DiscordMediaChannelImpl extends AbstractDiscordForumChannel implements DiscordMediaChannel { public DiscordMediaChannelImpl(DiscordSRV discordSRV, MediaChannel channel) { @@ -46,7 +45,7 @@ public class DiscordMediaChannelImpl extends AbstractDiscordForumChannel createPost(String name, SendableDiscordMessage message) { + public Task createPost(String name, SendableDiscordMessage message) { return thread( channel -> channel.createForumPost(name, SendableDiscordMessageUtil.toJDASend(message)), ForumPost::getThreadChannel diff --git a/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/DiscordThreadChannelImpl.java b/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/DiscordThreadChannelImpl.java index d04d8e60..43b77016 100644 --- a/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/DiscordThreadChannelImpl.java +++ b/common/src/main/java/com/discordsrv/common/discord/api/entity/channel/DiscordThreadChannelImpl.java @@ -22,6 +22,7 @@ import com.discordsrv.api.discord.entity.channel.DiscordChannelType; import com.discordsrv.api.discord.entity.channel.DiscordThreadChannel; import com.discordsrv.api.discord.entity.channel.DiscordThreadContainer; import com.discordsrv.api.discord.entity.guild.DiscordGuild; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; @@ -35,8 +36,6 @@ import net.dv8tion.jda.api.requests.restaction.WebhookMessageDeleteAction; import net.dv8tion.jda.api.requests.restaction.WebhookMessageEditAction; import org.jetbrains.annotations.NotNull; -import java.util.concurrent.CompletableFuture; - public class DiscordThreadChannelImpl extends AbstractDiscordGuildMessageChannel implements DiscordThreadChannel { private final DiscordThreadContainer threadContainer; @@ -51,7 +50,7 @@ public class DiscordThreadChannelImpl extends AbstractDiscordGuildMessageChannel } @Override - public CompletableFuture> queryWebhookClient() { + public Task> queryWebhookClient() { return discordSRV.discordAPI() .queryWebhookClient(getParentChannel().getId()); } diff --git a/common/src/main/java/com/discordsrv/common/discord/api/entity/component/DiscordInteractionHookImpl.java b/common/src/main/java/com/discordsrv/common/discord/api/entity/component/DiscordInteractionHookImpl.java index c67dd5ee..4af238e7 100644 --- a/common/src/main/java/com/discordsrv/common/discord/api/entity/component/DiscordInteractionHookImpl.java +++ b/common/src/main/java/com/discordsrv/common/discord/api/entity/component/DiscordInteractionHookImpl.java @@ -21,13 +21,12 @@ package com.discordsrv.common.discord.api.entity.component; import com.discordsrv.api.discord.entity.interaction.DiscordInteractionHook; import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessage; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.discord.api.entity.message.ReceivedDiscordMessageImpl; import com.discordsrv.common.discord.api.entity.message.util.SendableDiscordMessageUtil; import net.dv8tion.jda.api.interactions.InteractionHook; -import java.util.concurrent.CompletableFuture; - public class DiscordInteractionHookImpl implements DiscordInteractionHook { private final DiscordSRV discordSRV; @@ -54,14 +53,14 @@ public class DiscordInteractionHookImpl implements DiscordInteractionHook { } @Override - public CompletableFuture editOriginal(SendableDiscordMessage message) { - return hook.editOriginal(SendableDiscordMessageUtil.toJDAEdit(message)).submit() + public Task editOriginal(SendableDiscordMessage message) { + return discordSRV.discordAPI().toTask(() -> hook.editOriginal(SendableDiscordMessageUtil.toJDAEdit(message))) .thenApply(msg -> ReceivedDiscordMessageImpl.fromJDA(discordSRV, msg)); } @Override - public CompletableFuture sendMessage(SendableDiscordMessage message, boolean ephemeral) { - return hook.sendMessage(SendableDiscordMessageUtil.toJDASend(message)).setEphemeral(ephemeral).submit() + public Task sendMessage(SendableDiscordMessage message, boolean ephemeral) { + return discordSRV.discordAPI().toTask(() -> hook.sendMessage(SendableDiscordMessageUtil.toJDASend(message)).setEphemeral(ephemeral)) .thenApply(msg -> ReceivedDiscordMessageImpl.fromJDA(discordSRV, msg)); } } diff --git a/common/src/main/java/com/discordsrv/common/discord/api/entity/guild/DiscordGuildImpl.java b/common/src/main/java/com/discordsrv/common/discord/api/entity/guild/DiscordGuildImpl.java index 3a1f75d5..afec48b8 100644 --- a/common/src/main/java/com/discordsrv/common/discord/api/entity/guild/DiscordGuildImpl.java +++ b/common/src/main/java/com/discordsrv/common/discord/api/entity/guild/DiscordGuildImpl.java @@ -63,10 +63,8 @@ public class DiscordGuildImpl implements DiscordGuild { @Override public @NotNull Task retrieveMemberById(long id) { - return discordSRV.discordAPI().mapExceptions(() -> guild.retrieveMemberById(id) - .submit() - .thenApply(member -> new DiscordGuildMemberImpl(discordSRV, member)) - ); + return discordSRV.discordAPI().toTask(() -> guild.retrieveMemberById(id)) + .thenApply(member -> new DiscordGuildMemberImpl(discordSRV, member)); } @Override diff --git a/common/src/main/java/com/discordsrv/common/discord/api/entity/guild/DiscordGuildMemberImpl.java b/common/src/main/java/com/discordsrv/common/discord/api/entity/guild/DiscordGuildMemberImpl.java index f75ed93c..e3f3d543 100644 --- a/common/src/main/java/com/discordsrv/common/discord/api/entity/guild/DiscordGuildMemberImpl.java +++ b/common/src/main/java/com/discordsrv/common/discord/api/entity/guild/DiscordGuildMemberImpl.java @@ -26,6 +26,7 @@ import com.discordsrv.api.discord.entity.guild.DiscordRole; import com.discordsrv.api.placeholder.annotation.Placeholder; import com.discordsrv.api.placeholder.annotation.PlaceholderPrefix; import com.discordsrv.api.placeholder.annotation.PlaceholderRemainder; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; @@ -36,10 +37,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.time.OffsetDateTime; -import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CompletableFuture; @PlaceholderPrefix("user_") public class DiscordGuildMemberImpl implements DiscordGuildMember { @@ -101,17 +100,13 @@ public class DiscordGuildMemberImpl implements DiscordGuildMember { } @Override - public CompletableFuture addRole(@NotNull DiscordRole role) { - return discordSRV.discordAPI().mapExceptions(() -> - guild.asJDA().addRoleToMember(member, role.asJDA()).submit() - ); + public Task addRole(@NotNull DiscordRole role) { + return discordSRV.discordAPI().toTask(() -> guild.asJDA().addRoleToMember(member, role.asJDA())); } @Override - public CompletableFuture removeRole(@NotNull DiscordRole role) { - return discordSRV.discordAPI().mapExceptions(() -> - guild.asJDA().removeRoleFromMember(member, role.asJDA()).submit() - ); + public Task removeRole(@NotNull DiscordRole role) { + return discordSRV.discordAPI().toTask(() -> guild.asJDA().removeRoleFromMember(member, role.asJDA())); } @Override diff --git a/common/src/main/java/com/discordsrv/common/discord/api/entity/message/ReceivedDiscordMessageClusterImpl.java b/common/src/main/java/com/discordsrv/common/discord/api/entity/message/ReceivedDiscordMessageClusterImpl.java index 16865389..452bcaf1 100644 --- a/common/src/main/java/com/discordsrv/common/discord/api/entity/message/ReceivedDiscordMessageClusterImpl.java +++ b/common/src/main/java/com/discordsrv/common/discord/api/entity/message/ReceivedDiscordMessageClusterImpl.java @@ -21,11 +21,10 @@ package com.discordsrv.common.discord.api.entity.message; import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessage; import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessageCluster; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; -import com.discordsrv.common.util.CompletableFutureUtil; +import com.discordsrv.api.task.Task; import org.jetbrains.annotations.NotNull; import java.util.*; -import java.util.concurrent.CompletableFuture; public class ReceivedDiscordMessageClusterImpl implements ReceivedDiscordMessageCluster { @@ -41,22 +40,22 @@ public class ReceivedDiscordMessageClusterImpl implements ReceivedDiscordMessage } @Override - public @NotNull CompletableFuture deleteAll() { - List> futures = new ArrayList<>(messages.size()); + public @NotNull Task deleteAll() { + List> futures = new ArrayList<>(messages.size()); for (ReceivedDiscordMessage message : messages) { futures.add(message.delete()); } - return CompletableFutureUtil.combine(futures).thenApply(v -> null); + return Task.allOf(futures).thenApply(v -> null); } @Override - public @NotNull CompletableFuture editAll(SendableDiscordMessage newMessage) { - List> futures = new ArrayList<>(messages.size()); + public @NotNull Task editAll(SendableDiscordMessage newMessage) { + List> futures = new ArrayList<>(messages.size()); for (ReceivedDiscordMessage message : messages) { futures.add(message.edit(newMessage)); } - return CompletableFutureUtil.combine(futures).thenApply(ReceivedDiscordMessageClusterImpl::new); + return Task.allOf(futures).thenApply(ReceivedDiscordMessageClusterImpl::new); } } diff --git a/common/src/main/java/com/discordsrv/common/discord/api/entity/message/ReceivedDiscordMessageImpl.java b/common/src/main/java/com/discordsrv/common/discord/api/entity/message/ReceivedDiscordMessageImpl.java index 4486cf22..7ba674b7 100644 --- a/common/src/main/java/com/discordsrv/common/discord/api/entity/message/ReceivedDiscordMessageImpl.java +++ b/common/src/main/java/com/discordsrv/common/discord/api/entity/message/ReceivedDiscordMessageImpl.java @@ -30,8 +30,8 @@ import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessage; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; import com.discordsrv.api.discord.exception.RestErrorResponseException; import com.discordsrv.api.placeholder.annotation.PlaceholderPrefix; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; -import com.discordsrv.common.util.CompletableFutureUtil; import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.requests.ErrorResponse; import org.jetbrains.annotations.NotNull; @@ -256,17 +256,17 @@ public class ReceivedDiscordMessageImpl implements ReceivedDiscordMessage { } @Override - public @NotNull CompletableFuture delete() { + public @NotNull Task delete() { DiscordMessageChannel messageChannel = discordSRV.discordAPI().getMessageChannelById(channelId); if (messageChannel == null) { - return CompletableFutureUtil.failed(new RestErrorResponseException(ErrorResponse.UNKNOWN_CHANNEL)); + return Task.failed(new RestErrorResponseException(ErrorResponse.UNKNOWN_CHANNEL)); } return messageChannel.deleteMessageById(getId(), fromSelf && webhookMessage); } @Override - public @NotNull CompletableFuture edit( + public Task edit( @NotNull SendableDiscordMessage message ) { if (!webhookMessage && message.isWebhookMessage()) { @@ -275,21 +275,21 @@ public class ReceivedDiscordMessageImpl implements ReceivedDiscordMessage { DiscordMessageChannel messageChannel = discordSRV.discordAPI().getMessageChannelById(channelId); if (messageChannel == null) { - return CompletableFutureUtil.failed(new RestErrorResponseException(ErrorResponse.UNKNOWN_CHANNEL)); + return Task.failed(new RestErrorResponseException(ErrorResponse.UNKNOWN_CHANNEL)); } return messageChannel.editMessageById(getId(), message); } @Override - public CompletableFuture reply(@NotNull SendableDiscordMessage message) { + public Task reply(@NotNull SendableDiscordMessage message) { if (message.isWebhookMessage()) { throw new IllegalStateException("Webhook messages cannot be used as replies"); } DiscordMessageChannel messageChannel = discordSRV.discordAPI().getMessageChannelById(channelId); if (messageChannel == null) { - return CompletableFutureUtil.failed(new RestErrorResponseException(ErrorResponse.UNKNOWN_CHANNEL)); + return Task.failed(new RestErrorResponseException(ErrorResponse.UNKNOWN_CHANNEL)); } return messageChannel.sendMessage(message.withReplyingToMessageId(id)); diff --git a/common/src/main/java/com/discordsrv/common/discord/connection/jda/JDAConnectionManager.java b/common/src/main/java/com/discordsrv/common/discord/connection/jda/JDAConnectionManager.java index fd8133e8..1e85f4e0 100644 --- a/common/src/main/java/com/discordsrv/common/discord/connection/jda/JDAConnectionManager.java +++ b/common/src/main/java/com/discordsrv/common/discord/connection/jda/JDAConnectionManager.java @@ -29,6 +29,7 @@ import com.discordsrv.api.eventbus.Subscribe; import com.discordsrv.api.events.lifecycle.DiscordSRVShuttingDownEvent; import com.discordsrv.api.events.placeholder.PlaceholderLookupEvent; import com.discordsrv.api.placeholder.PlaceholderLookupResult; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.config.connection.BotConfig; import com.discordsrv.common.config.connection.ConnectionConfig; @@ -96,7 +97,7 @@ public class JDAConnectionManager implements DiscordConnectionManager { // Bot owner details private final Timeout botOwnerTimeout = new Timeout(Duration.ofMinutes(5)); - private final AtomicReference> botOwnerRequest = new AtomicReference<>(); + private final AtomicReference> botOwnerRequest = new AtomicReference<>(); // Logging timeouts private final Timeout mfaTimeout = new Timeout(Duration.ofSeconds(30)); @@ -168,16 +169,14 @@ public class JDAConnectionManager implements DiscordConnectionManager { * @param botOwnerConsumer the consumer that will be passed the bot owner or {@code null} */ private void withBotOwner(@NotNull Consumer botOwnerConsumer) { - CompletableFuture request = botOwnerRequest.get(); + Task request = botOwnerRequest.get(); if (request != null && !botOwnerTimeout.checkAndUpdate()) { request.whenComplete((user, t) -> botOwnerConsumer.accept(t != null ? null : user)); return; } - CompletableFuture future = instance.retrieveApplicationInfo() - .timeout(10, TimeUnit.SECONDS) - .map(applicationInfo -> (DiscordUser) api().getUser(applicationInfo.getOwner())) - .submit(); + Task future = discordSRV.discordAPI().toTask(instance.retrieveApplicationInfo().timeout(10, TimeUnit.SECONDS)) + .thenApply(applicationInfo -> api().getUser(applicationInfo.getOwner())); botOwnerRequest.set(future); future.whenComplete((user, t) -> botOwnerConsumer.accept(t != null ? null : user)); @@ -211,7 +210,7 @@ public class JDAConnectionManager implements DiscordConnectionManager { } builder.append("\n"); - CompletableFuture restPingFuture = instance.getRestPing().timeout(5, TimeUnit.SECONDS).submit(); + Task restPingFuture = discordSRV.discordAPI().toTask(instance.getRestPing().timeout(5, TimeUnit.SECONDS)); builder.append("\nGateway Ping: ").append(instance.getGatewayPing()).append("ms"); String restPing; diff --git a/common/src/main/java/com/discordsrv/common/events/discord/interaction/command/DiscordChatInputInteractionEventImpl.java b/common/src/main/java/com/discordsrv/common/events/discord/interaction/command/DiscordChatInputInteractionEventImpl.java index 7a5e0a70..b4d5b341 100644 --- a/common/src/main/java/com/discordsrv/common/events/discord/interaction/command/DiscordChatInputInteractionEventImpl.java +++ b/common/src/main/java/com/discordsrv/common/events/discord/interaction/command/DiscordChatInputInteractionEventImpl.java @@ -25,13 +25,12 @@ import com.discordsrv.api.discord.entity.interaction.DiscordInteractionHook; import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; import com.discordsrv.api.events.discord.interaction.command.DiscordChatInputInteractionEvent; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.discord.api.entity.component.DiscordInteractionHookImpl; import com.discordsrv.common.discord.api.entity.message.util.SendableDiscordMessageUtil; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; -import java.util.concurrent.CompletableFuture; - public class DiscordChatInputInteractionEventImpl extends DiscordChatInputInteractionEvent { private final DiscordSRV discordSRV; @@ -48,18 +47,14 @@ public class DiscordChatInputInteractionEventImpl extends DiscordChatInputIntera } @Override - public CompletableFuture reply(SendableDiscordMessage message, boolean ephemeral) { - return discordSRV.discordAPI().mapExceptions( - () -> jdaEvent.reply(SendableDiscordMessageUtil.toJDASend(message)).setEphemeral(ephemeral).submit() - .thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih)) - ); + public Task reply(SendableDiscordMessage message, boolean ephemeral) { + return discordSRV.discordAPI().toTask(() -> jdaEvent.reply(SendableDiscordMessageUtil.toJDASend(message)).setEphemeral(ephemeral)) + .thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih)); } @Override - public CompletableFuture deferReply(boolean ephemeral) { - return discordSRV.discordAPI().mapExceptions( - () -> jdaEvent.deferReply(ephemeral).submit() - .thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih)) - ); + public Task deferReply(boolean ephemeral) { + return discordSRV.discordAPI().toTask(() -> jdaEvent.deferReply(ephemeral)) + .thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih)); } } diff --git a/common/src/main/java/com/discordsrv/common/events/discord/interaction/command/DiscordMessageContextInteractionEventImpl.java b/common/src/main/java/com/discordsrv/common/events/discord/interaction/command/DiscordMessageContextInteractionEventImpl.java index eee3d13a..0b26c3ad 100644 --- a/common/src/main/java/com/discordsrv/common/events/discord/interaction/command/DiscordMessageContextInteractionEventImpl.java +++ b/common/src/main/java/com/discordsrv/common/events/discord/interaction/command/DiscordMessageContextInteractionEventImpl.java @@ -25,13 +25,12 @@ import com.discordsrv.api.discord.entity.interaction.DiscordInteractionHook; import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; import com.discordsrv.api.events.discord.interaction.command.DiscordMessageContextInteractionEvent; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.discord.api.entity.component.DiscordInteractionHookImpl; import com.discordsrv.common.discord.api.entity.message.util.SendableDiscordMessageUtil; import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent; -import java.util.concurrent.CompletableFuture; - public class DiscordMessageContextInteractionEventImpl extends DiscordMessageContextInteractionEvent { private final DiscordSRV discordSRV; @@ -50,18 +49,14 @@ public class DiscordMessageContextInteractionEventImpl extends DiscordMessageCon } @Override - public CompletableFuture reply(SendableDiscordMessage message, boolean ephemeral) { - return discordSRV.discordAPI().mapExceptions( - () -> jdaEvent.reply(SendableDiscordMessageUtil.toJDASend(message)).setEphemeral(ephemeral).submit() - .thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih)) - ); + public Task reply(SendableDiscordMessage message, boolean ephemeral) { + return discordSRV.discordAPI().toTask(() -> jdaEvent.reply(SendableDiscordMessageUtil.toJDASend(message)).setEphemeral(ephemeral)) + .thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih)); } @Override - public CompletableFuture deferReply(boolean ephemeral) { - return discordSRV.discordAPI().mapExceptions( - () -> jdaEvent.deferReply(ephemeral).submit() - .thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih)) - ); + public Task deferReply(boolean ephemeral) { + return discordSRV.discordAPI().toTask(() -> jdaEvent.deferReply(ephemeral)) + .thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih)); } } diff --git a/common/src/main/java/com/discordsrv/common/events/discord/interaction/command/DiscordUserContextInteractionEventImpl.java b/common/src/main/java/com/discordsrv/common/events/discord/interaction/command/DiscordUserContextInteractionEventImpl.java index a9c70fe2..df499f90 100644 --- a/common/src/main/java/com/discordsrv/common/events/discord/interaction/command/DiscordUserContextInteractionEventImpl.java +++ b/common/src/main/java/com/discordsrv/common/events/discord/interaction/command/DiscordUserContextInteractionEventImpl.java @@ -25,13 +25,12 @@ import com.discordsrv.api.discord.entity.interaction.DiscordInteractionHook; import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; import com.discordsrv.api.events.discord.interaction.command.DiscordUserContextInteractionEvent; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.discord.api.entity.component.DiscordInteractionHookImpl; import com.discordsrv.common.discord.api.entity.message.util.SendableDiscordMessageUtil; import net.dv8tion.jda.api.events.interaction.command.UserContextInteractionEvent; -import java.util.concurrent.CompletableFuture; - public class DiscordUserContextInteractionEventImpl extends DiscordUserContextInteractionEvent { private final DiscordSRV discordSRV; @@ -48,18 +47,14 @@ public class DiscordUserContextInteractionEventImpl extends DiscordUserContextIn } @Override - public CompletableFuture reply(SendableDiscordMessage message, boolean ephemeral) { - return discordSRV.discordAPI().mapExceptions( - () -> jdaEvent.reply(SendableDiscordMessageUtil.toJDASend(message)).setEphemeral(ephemeral).submit() - .thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih)) - ); + public Task reply(SendableDiscordMessage message, boolean ephemeral) { + return discordSRV.discordAPI().toTask(() -> jdaEvent.reply(SendableDiscordMessageUtil.toJDASend(message)).setEphemeral(ephemeral)) + .thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih)); } @Override - public CompletableFuture deferReply(boolean ephemeral) { - return discordSRV.discordAPI().mapExceptions( - () -> jdaEvent.deferReply(ephemeral).submit() - .thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih)) - ); + public Task deferReply(boolean ephemeral) { + return discordSRV.discordAPI().toTask(() -> jdaEvent.deferReply(ephemeral)) + .thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih)); } } diff --git a/common/src/main/java/com/discordsrv/common/feature/bansync/BanSyncModule.java b/common/src/main/java/com/discordsrv/common/feature/bansync/BanSyncModule.java index 9b3ad41e..390c83f6 100644 --- a/common/src/main/java/com/discordsrv/common/feature/bansync/BanSyncModule.java +++ b/common/src/main/java/com/discordsrv/common/feature/bansync/BanSyncModule.java @@ -55,7 +55,6 @@ import org.jetbrains.annotations.Nullable; import java.time.Duration; import java.util.*; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -297,10 +296,10 @@ public class BanSyncModule extends AbstractSyncModule { + .then(v -> { IPlayer player = discordSRV.playerProvider().player(playerUUID); if (player == null) { - return CompletableFuture.completedFuture(null); + return Task.completed(null); } MinecraftComponent kickMessage = discordSRV.componentFactory() diff --git a/common/src/main/java/com/discordsrv/common/feature/console/SingleConsoleHandler.java b/common/src/main/java/com/discordsrv/common/feature/console/SingleConsoleHandler.java index c7d17bfc..dff82cc8 100644 --- a/common/src/main/java/com/discordsrv/common/feature/console/SingleConsoleHandler.java +++ b/common/src/main/java/com/discordsrv/common/feature/console/SingleConsoleHandler.java @@ -30,6 +30,7 @@ import com.discordsrv.api.discord.util.DiscordFormattingUtil; import com.discordsrv.api.events.discord.message.DiscordMessageReceiveEvent; import com.discordsrv.api.placeholder.format.PlainPlaceholderFormat; import com.discordsrv.api.placeholder.provider.SinglePlaceholder; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.command.game.abstraction.GameCommandExecutionHelper; import com.discordsrv.common.config.main.ConsoleConfig; @@ -75,7 +76,7 @@ public class SingleConsoleHandler { // Sending private Future queueProcessingFuture; - private CompletableFuture sendFuture; + private Task sendFuture; private Queue messageQueue; private Deque> sendQueue; private boolean sentFirstBatch = false; @@ -545,51 +546,51 @@ public class SingleConsoleHandler { return " "; } - private CompletableFuture rotateToLatestChannel() { + private Task rotateToLatestChannel() { return discordSRV.destinations().lookupDestination( config.channel.asDestination(), true, true, ZonedDateTime.now() - ).thenCompose(channels -> { - if (channels.isEmpty()) { - // Nowhere to send to - return CompletableFuture.completedFuture(null); + ).thenApply(channels -> { + if (channels.isEmpty()) { + // Nowhere to send to + return null; + } + + DiscordGuildMessageChannel channel = channels.iterator().next(); + + int amountOfChannels = config.threadsToKeepInRotation; + if (amountOfChannels > 0) { + TemporaryLocalData.Model temporaryData = discordSRV.temporaryLocalData().get(); + + List channelsToDelete = null; + synchronized (temporaryData) { + Map> rotationIds = temporaryData.consoleThreadRotationIds; + List channelIds = rotationIds.computeIfAbsent(key, k -> new ArrayList<>(amountOfChannels)); + + if (channelIds.isEmpty() || channelIds.get(0) != channel.getId()) { + channelIds.add(0, channel.getId()); } + if (channelIds.size() > amountOfChannels) { + rotationIds.put(key, channelIds.subList(0, amountOfChannels)); + channelsToDelete = channelIds.subList(amountOfChannels, channelIds.size()); + } + } + discordSRV.temporaryLocalData().saveLater(); - DiscordGuildMessageChannel channel = channels.iterator().next(); - - int amountOfChannels = config.threadsToKeepInRotation; - if (amountOfChannels > 0) { - TemporaryLocalData.Model temporaryData = discordSRV.temporaryLocalData().get(); - - List channelsToDelete = null; - synchronized (temporaryData) { - Map> rotationIds = temporaryData.consoleThreadRotationIds; - List channelIds = rotationIds.computeIfAbsent(key, k -> new ArrayList<>(amountOfChannels)); - - if (channelIds.isEmpty() || channelIds.get(0) != channel.getId()) { - channelIds.add(0, channel.getId()); - } - if (channelIds.size() > amountOfChannels) { - rotationIds.put(key, channelIds.subList(0, amountOfChannels)); - channelsToDelete = channelIds.subList(amountOfChannels, channelIds.size()); - } - } - discordSRV.temporaryLocalData().saveLater(); - - if (channelsToDelete != null) { - for (Long channelId : channelsToDelete) { - DiscordChannel channelToDelete = discordSRV.discordAPI().getChannelById(channelId); - if (channelToDelete instanceof DiscordGuildChannel) { - ((DiscordGuildChannel) channelToDelete).delete(); - } - } + if (channelsToDelete != null) { + for (Long channelId : channelsToDelete) { + DiscordChannel channelToDelete = discordSRV.discordAPI().getChannelById(channelId); + if (channelToDelete instanceof DiscordGuildChannel) { + ((DiscordGuildChannel) channelToDelete).delete(); } } + } + } - return CompletableFuture.completedFuture(channel); - }); + return channel; + }); } private void processSendQueue() { @@ -604,25 +605,25 @@ public class SingleConsoleHandler { boolean lastEdit = pair.getValue(); if (sendFuture == null) { - sendFuture = CompletableFuture.completedFuture(null); + sendFuture = Task.completed(null); } sendFuture = sendFuture - .thenCompose(__ -> { + .then(__ -> { if (mostRecentMessageId.get() != 0) { // Don't rotate if editing long channelId = latestChannelId.get(); DiscordMessageChannel channel = discordSRV.discordAPI().getMessageChannelById(channelId); if (channel instanceof DiscordGuildMessageChannel) { - return CompletableFuture.completedFuture((DiscordGuildMessageChannel) channel); + return Task.completed((DiscordGuildMessageChannel) channel); } } return rotateToLatestChannel(); }) - .thenCompose(channel -> { + .then(channel -> { if (channel == null) { - return CompletableFuture.completedFuture(null); + return Task.completed(null); } synchronized (mostRecentMessageId) { @@ -647,7 +648,7 @@ public class SingleConsoleHandler { sentFirstBatch = true; return msg; - }).exceptionally(ex -> { + }).mapException(ex -> { synchronized (mostRecentMessageId) { mostRecentMessageId.set(0); } diff --git a/common/src/main/java/com/discordsrv/common/feature/groupsync/GroupSyncModule.java b/common/src/main/java/com/discordsrv/common/feature/groupsync/GroupSyncModule.java index bfc4588b..dd2e61d1 100644 --- a/common/src/main/java/com/discordsrv/common/feature/groupsync/GroupSyncModule.java +++ b/common/src/main/java/com/discordsrv/common/feature/groupsync/GroupSyncModule.java @@ -35,12 +35,10 @@ import com.discordsrv.common.feature.debug.file.TextDebugFile; import com.discordsrv.common.feature.groupsync.enums.GroupSyncCause; import com.discordsrv.common.feature.groupsync.enums.GroupSyncResult; import com.discordsrv.common.helper.Someone; -import com.discordsrv.common.util.CompletableFutureUtil; import com.github.benmanes.caffeine.cache.Cache; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -229,7 +227,7 @@ public class GroupSyncModule extends AbstractSyncModule { + return future.mapException(t -> { throw new SyncFail(GroupSyncResult.PERMISSION_BACKEND_FAILED, t); }); } @@ -249,9 +247,9 @@ public class GroupSyncModule extends AbstractSyncModule stateToApply - ? member.addRole(role).thenApply(v -> (ISyncResult) GenericSyncResults.ADD_DISCORD) - : member.removeRole(role).thenApply(v -> GenericSyncResults.REMOVE_DISCORD) + .then(member -> stateToApply + ? member.addRole(role).thenApply(v -> (ISyncResult) GenericSyncResults.ADD_DISCORD) + : member.removeRole(role).thenApply(v -> GenericSyncResults.REMOVE_DISCORD) ).whenComplete((r, t) -> { if (t != null) { //noinspection DataFlowIssue @@ -273,7 +271,7 @@ public class GroupSyncModule extends AbstractSyncModule GenericSyncResults.ADD_GAME) : removeGroup(playerUUID, config).thenApply(v -> GenericSyncResults.REMOVE_GAME); - return future.exceptionally(t -> { + return future.mapException(t -> { //noinspection DataFlowIssue expected.remove(config.groupName); throw new SyncFail(GroupSyncResult.PERMISSION_BACKEND_FAILED, t); diff --git a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/RequiredLinkingModule.java b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/RequiredLinkingModule.java index 19ce6057..8206b5f7 100644 --- a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/RequiredLinkingModule.java +++ b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/RequiredLinkingModule.java @@ -21,6 +21,7 @@ package com.discordsrv.common.feature.linking.requirelinking; import com.discordsrv.api.eventbus.Subscribe; import com.discordsrv.api.events.linking.AccountUnlinkedEvent; import com.discordsrv.api.reload.ReloadResult; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.abstraction.player.IPlayer; import com.discordsrv.common.config.main.linking.RequiredLinkingConfig; @@ -40,14 +41,10 @@ import com.discordsrv.common.feature.linking.requirelinking.requirement.type.Dis import com.discordsrv.common.feature.linking.requirelinking.requirement.type.DiscordServerRequirementType; import com.discordsrv.common.feature.linking.requirelinking.requirement.type.MinecraftAuthRequirementType; import com.discordsrv.common.helper.Someone; -import com.discordsrv.common.util.CompletableFutureUtil; import com.discordsrv.common.util.ComponentUtil; import net.kyori.adventure.text.Component; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.UUID; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; @@ -194,7 +191,7 @@ public abstract class RequiredLinkingModule extends Abstra return providers; } - public CompletableFuture getBlockReason( + public Task getBlockReason( RequirementsConfig config, List additionalRequirements, UUID playerUUID, @@ -204,7 +201,7 @@ public abstract class RequiredLinkingModule extends Abstra if (config.bypassUUIDs.contains(playerUUID.toString())) { // Bypasses: let them through logger().debug("Player " + playerName + " is bypassing required linking requirements"); - return CompletableFuture.completedFuture(null); + return Task.completed(null); } LinkProvider linkProvider = discordSRV.linkProvider(); @@ -213,10 +210,10 @@ public abstract class RequiredLinkingModule extends Abstra Component message = ComponentUtil.fromAPI( discordSRV.messagesConfig().minecraft.unableToCheckLinkingStatus.textBuilder().build() ); - return CompletableFuture.completedFuture(message); + return Task.completed(message); } - return linkProvider.queryUserId(playerUUID, true).thenCompose(opt -> { + return linkProvider.queryUserId(playerUUID, true).then(opt -> { if (!opt.isPresent()) { // User is not linked return linkProvider.getLinkingInstructions(playerName, playerUUID, null, join ? "join" : "freeze") @@ -227,29 +224,26 @@ public abstract class RequiredLinkingModule extends Abstra if (additionalRequirements.isEmpty()) { // No additional requirements: let them through - return CompletableFuture.completedFuture(null); + return Task.completed(null); } CompletableFuture pass = new CompletableFuture<>(); - List> all = new ArrayList<>(); + List> all = new ArrayList<>(); for (ParsedRequirements requirement : additionalRequirements) { - CompletableFuture future = requirement.predicate().apply(Someone.of(playerUUID, userId)); + Task future = requirement.predicate().apply(Someone.of(playerUUID, userId)); all.add(future.thenApply(val -> { if (val) { pass.complete(null); } return val; - }).exceptionally(t -> { - logger().debug("Check \"" + requirement.input() + "\" failed for " - + playerName + " / " + Long.toUnsignedString(userId), t); - return null; - })); + }).whenFailed(t -> logger().debug("Check \"" + requirement.input() + "\" failed for " + + playerName + " / " + Long.toUnsignedString(userId), t))); } // Complete when at least one passes or all of them completed - return CompletableFuture.anyOf(pass, CompletableFutureUtil.combine(all)).thenApply(v -> { + return Task.anyOfGeneric(Arrays.asList(Task.of(pass), Task.allOf(all))).thenApply(v -> { if (pass.isDone()) { // One of the futures passed: let them through return null; diff --git a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/ServerRequireLinkingModule.java b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/ServerRequireLinkingModule.java index d5a999af..3cb45959 100644 --- a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/ServerRequireLinkingModule.java +++ b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/ServerRequireLinkingModule.java @@ -18,6 +18,7 @@ package com.discordsrv.common.feature.linking.requirelinking; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.config.main.linking.ServerRequiredLinkingConfig; import com.discordsrv.common.feature.linking.requirelinking.requirement.parser.ParsedRequirements; @@ -25,7 +26,6 @@ import net.kyori.adventure.text.Component; import java.util.List; import java.util.UUID; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArrayList; public abstract class ServerRequireLinkingModule extends RequiredLinkingModule { @@ -52,7 +52,7 @@ public abstract class ServerRequireLinkingModule extends R return additionalRequirements; } - public CompletableFuture getBlockReason(UUID playerUUID, String playerName, boolean join) { + public Task getBlockReason(UUID playerUUID, String playerName, boolean join) { List additionalRequirements; synchronized (this.additionalRequirements) { additionalRequirements = this.additionalRequirements; diff --git a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/RequirementType.java b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/RequirementType.java index 78b8f39d..31f5161e 100644 --- a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/RequirementType.java +++ b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/RequirementType.java @@ -18,13 +18,12 @@ package com.discordsrv.common.feature.linking.requirelinking.requirement; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.core.module.type.AbstractModule; import com.discordsrv.common.feature.linking.requirelinking.RequiredLinkingModule; import com.discordsrv.common.helper.Someone; -import java.util.concurrent.CompletableFuture; - public abstract class RequirementType extends AbstractModule { protected final RequiredLinkingModule module; @@ -40,6 +39,6 @@ public abstract class RequirementType extends AbstractModule { public abstract String name(); public abstract T parse(String input); - public abstract CompletableFuture isMet(T value, Someone.Resolved someone); + public abstract Task isMet(T value, Someone.Resolved someone); } diff --git a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/parser/ParsedRequirements.java b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/parser/ParsedRequirements.java index 75f41575..515074b7 100644 --- a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/parser/ParsedRequirements.java +++ b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/parser/ParsedRequirements.java @@ -18,22 +18,22 @@ package com.discordsrv.common.feature.linking.requirelinking.requirement.parser; +import com.discordsrv.api.task.Task; import com.discordsrv.common.feature.linking.requirelinking.requirement.Requirement; import com.discordsrv.common.helper.Someone; import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.function.Function; public class ParsedRequirements { private final String input; - private final Function> predicate; + private final Function> predicate; private final List> usedRequirements; public ParsedRequirements( String input, - Function> predicate, + Function> predicate, List> usedRequirements ) { this.input = input; @@ -45,7 +45,7 @@ public class ParsedRequirements { return input; } - public Function> predicate() { + public Function> predicate() { return predicate; } diff --git a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/parser/RequirementParser.java b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/parser/RequirementParser.java index d05f7bf1..2e8ed7dc 100644 --- a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/parser/RequirementParser.java +++ b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/parser/RequirementParser.java @@ -18,15 +18,14 @@ package com.discordsrv.common.feature.linking.requirelinking.requirement.parser; +import com.discordsrv.api.task.Task; import com.discordsrv.common.feature.linking.requirelinking.requirement.Requirement; import com.discordsrv.common.feature.linking.requirelinking.requirement.RequirementType; import com.discordsrv.common.helper.Someone; -import com.discordsrv.common.util.CompletableFutureUtil; import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiFunction; import java.util.function.Function; @@ -203,7 +202,7 @@ public class RequirementParser { @FunctionalInterface private interface Func { - CompletableFuture test(Someone.Resolved someone); + Task test(Someone.Resolved someone); } private enum Operator { @@ -220,7 +219,7 @@ public class RequirementParser { } private static Func apply(Func one, Func two, BiFunction function) { - return someone -> CompletableFutureUtil.combine(one.test(someone), two.test(someone)) + return someone -> Task.allOf(one.test(someone), two.test(someone)) .thenApply(bools -> function.apply(bools.get(0), bools.get(1))); } } diff --git a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/type/DiscordBoostingRequirementType.java b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/type/DiscordBoostingRequirementType.java index 47633a26..d4c556d1 100644 --- a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/type/DiscordBoostingRequirementType.java +++ b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/type/DiscordBoostingRequirementType.java @@ -20,13 +20,12 @@ package com.discordsrv.common.feature.linking.requirelinking.requirement.type; import com.discordsrv.api.discord.entity.guild.DiscordGuild; import com.discordsrv.api.eventbus.Subscribe; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.feature.linking.requirelinking.RequiredLinkingModule; import com.discordsrv.common.helper.Someone; import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateBoostTimeEvent; -import java.util.concurrent.CompletableFuture; - public class DiscordBoostingRequirementType extends LongRequirementType { public DiscordBoostingRequirementType(RequiredLinkingModule module) { @@ -39,10 +38,10 @@ public class DiscordBoostingRequirementType extends LongRequirementType { } @Override - public CompletableFuture isMet(Long value, Someone.Resolved someone) { + public Task isMet(Long value, Someone.Resolved someone) { DiscordGuild guild = module.discordSRV().discordAPI().getGuildById(value); if (guild == null) { - return CompletableFuture.completedFuture(false); + return Task.completed(false); } return guild.retrieveMemberById(someone.userId()) diff --git a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/type/DiscordRoleRequirementType.java b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/type/DiscordRoleRequirementType.java index c1f57fdd..5d316ab1 100644 --- a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/type/DiscordRoleRequirementType.java +++ b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/type/DiscordRoleRequirementType.java @@ -22,12 +22,11 @@ import com.discordsrv.api.discord.entity.guild.DiscordRole; import com.discordsrv.api.eventbus.Subscribe; import com.discordsrv.api.events.discord.member.role.AbstractDiscordMemberRoleChangeEvent; import com.discordsrv.api.events.discord.member.role.DiscordMemberRoleAddEvent; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.feature.linking.requirelinking.RequiredLinkingModule; import com.discordsrv.common.helper.Someone; -import java.util.concurrent.CompletableFuture; - public class DiscordRoleRequirementType extends LongRequirementType { public DiscordRoleRequirementType(RequiredLinkingModule module) { @@ -40,10 +39,10 @@ public class DiscordRoleRequirementType extends LongRequirementType { } @Override - public CompletableFuture isMet(Long value, Someone.Resolved someone) { + public Task isMet(Long value, Someone.Resolved someone) { DiscordRole role = module.discordSRV().discordAPI().getRoleById(value); if (role == null) { - return CompletableFuture.completedFuture(false); + return Task.completed(false); } return role.getGuild() diff --git a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/type/DiscordServerRequirementType.java b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/type/DiscordServerRequirementType.java index 700d1999..ce181ff3 100644 --- a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/type/DiscordServerRequirementType.java +++ b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/type/DiscordServerRequirementType.java @@ -20,6 +20,7 @@ package com.discordsrv.common.feature.linking.requirelinking.requirement.type; import com.discordsrv.api.discord.entity.guild.DiscordGuild; import com.discordsrv.api.eventbus.Subscribe; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.feature.linking.requirelinking.RequiredLinkingModule; import com.discordsrv.common.helper.Someone; @@ -27,7 +28,6 @@ import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent; import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent; import java.util.Objects; -import java.util.concurrent.CompletableFuture; public class DiscordServerRequirementType extends LongRequirementType { @@ -41,10 +41,10 @@ public class DiscordServerRequirementType extends LongRequirementType { } @Override - public CompletableFuture isMet(Long value, Someone.Resolved someone) { + public Task isMet(Long value, Someone.Resolved someone) { DiscordGuild guild = module.discordSRV().discordAPI().getGuildById(value); if (guild == null) { - return CompletableFuture.completedFuture(false); + return Task.completed(false); } return guild.retrieveMemberById(someone.userId()) diff --git a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/type/MinecraftAuthRequirementType.java b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/type/MinecraftAuthRequirementType.java index e5cb9144..98380337 100644 --- a/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/type/MinecraftAuthRequirementType.java +++ b/common/src/main/java/com/discordsrv/common/feature/linking/requirelinking/requirement/type/MinecraftAuthRequirementType.java @@ -18,6 +18,7 @@ package com.discordsrv.common.feature.linking.requirelinking.requirement.type; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.feature.linking.requirelinking.RequiredLinkingModule; import com.discordsrv.common.feature.linking.requirelinking.requirement.RequirementType; @@ -30,7 +31,6 @@ import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.List; import java.util.UUID; -import java.util.concurrent.CompletableFuture; import java.util.function.Function; public class MinecraftAuthRequirementType extends RequirementType> { @@ -163,7 +163,7 @@ public class MinecraftAuthRequirementType extends RequirementType isMet(Reference atomicReference, Someone.Resolved someone) { + public Task isMet(Reference atomicReference, Someone.Resolved someone) { String token = module.discordSRV().connectionConfig().minecraftAuth.token; T value = atomicReference.getValue(); return module.discordSRV().scheduler().supply(() -> { diff --git a/common/src/main/java/com/discordsrv/common/feature/mention/MentionCachingModule.java b/common/src/main/java/com/discordsrv/common/feature/mention/MentionCachingModule.java index 686d968a..7ddd4a52 100644 --- a/common/src/main/java/com/discordsrv/common/feature/mention/MentionCachingModule.java +++ b/common/src/main/java/com/discordsrv/common/feature/mention/MentionCachingModule.java @@ -20,13 +20,13 @@ package com.discordsrv.common.feature.mention; import com.discordsrv.api.discord.connection.details.DiscordGatewayIntent; import com.discordsrv.api.eventbus.Subscribe; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.abstraction.player.IPlayer; import com.discordsrv.common.config.main.channels.MinecraftToDiscordChatConfig; import com.discordsrv.common.config.main.channels.base.BaseChannelConfig; import com.discordsrv.common.core.module.type.AbstractModule; import com.discordsrv.common.permission.game.Permissions; -import com.discordsrv.common.util.CompletableFutureUtil; import com.github.benmanes.caffeine.cache.Cache; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; @@ -96,14 +96,14 @@ public class MentionCachingModule extends AbstractModule { channelMentions.clear(); } - public CompletableFuture> lookup( + public Task> lookup( MinecraftToDiscordChatConfig.Mentions config, Guild guild, IPlayer player, String messageContent, Set lookedUpMembers ) { - List>> futures = new ArrayList<>(); + List>> futures = new ArrayList<>(); List mentions = new ArrayList<>(); if (config.users) { @@ -137,7 +137,7 @@ public class MentionCachingModule extends AbstractModule { mentions.addAll(getChannelMentions(guild).values()); } - return CompletableFutureUtil.combine(futures).thenApply(lists -> { + return Task.allOf(futures).thenApply(lists -> { lists.forEach(mentions::addAll); // From longest to shortest @@ -159,7 +159,7 @@ public class MentionCachingModule extends AbstractModule { // Member // - private CompletableFuture> lookupMemberMentions( + private Task> lookupMemberMentions( Guild guild, String username, Set lookedUpMembers @@ -168,7 +168,7 @@ public class MentionCachingModule extends AbstractModule { guild.retrieveMembersByPrefix(username, 100) .onSuccess(memberFuture::complete).onError(memberFuture::completeExceptionally); - return memberFuture.thenApply(members -> { + return Task.of(memberFuture).thenApply(members -> { if (lookedUpMembers != null) { lookedUpMembers.addAll(members); } diff --git a/common/src/main/java/com/discordsrv/common/feature/messageforwarding/discord/DiscordMessageMirroringModule.java b/common/src/main/java/com/discordsrv/common/feature/messageforwarding/discord/DiscordMessageMirroringModule.java index d8b7947e..b7666aa7 100644 --- a/common/src/main/java/com/discordsrv/common/feature/messageforwarding/discord/DiscordMessageMirroringModule.java +++ b/common/src/main/java/com/discordsrv/common/feature/messageforwarding/discord/DiscordMessageMirroringModule.java @@ -36,6 +36,7 @@ import com.discordsrv.api.events.message.forward.game.AbstractGameMessageForward import com.discordsrv.api.events.message.receive.discord.DiscordChatMessageReceiveEvent; import com.discordsrv.api.placeholder.format.PlainPlaceholderFormat; import com.discordsrv.api.placeholder.provider.SinglePlaceholder; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.config.main.channels.MirroringConfig; import com.discordsrv.common.config.main.channels.base.BaseChannelConfig; @@ -43,7 +44,6 @@ import com.discordsrv.common.config.main.channels.base.IChannelConfig; import com.discordsrv.common.config.main.generic.DiscordIgnoresConfig; import com.discordsrv.common.core.logging.NamedLogger; import com.discordsrv.common.core.module.type.AbstractModule; -import com.discordsrv.common.util.CompletableFutureUtil; import com.discordsrv.common.util.DiscordPermissionUtil; import com.github.benmanes.caffeine.cache.Cache; import net.dv8tion.jda.api.Permission; @@ -59,8 +59,6 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; import java.util.concurrent.TimeUnit; public class DiscordMessageMirroringModule extends AbstractModule { @@ -104,7 +102,7 @@ public class DiscordMessageMirroringModule extends AbstractModule { ReceivedDiscordMessage message = event.getMessage(); - List> futures = new ArrayList<>(); + List> futures = new ArrayList<>(); Map attachments = new LinkedHashMap<>(); DiscordMessageEmbed.Builder attachmentEmbed = DiscordMessageEmbed.builder().setDescription("Attachments"); @@ -175,10 +173,10 @@ public class DiscordMessageMirroringModule extends AbstractModule { ); } - CompletableFutureUtil.combine(futures).whenComplete((lists, v) -> { + Task.allOf(futures).whenComplete((lists, v) -> { Set channelIdsHandled = new HashSet<>(); for (MirrorOperation operation : lists) { - List> mirrorFutures = new ArrayList<>(); + List> mirrorFutures = new ArrayList<>(); for (MirrorTarget target : operation.targets) { DiscordGuildMessageChannel mirrorChannel = target.targetChannel; @@ -231,26 +229,22 @@ public class DiscordMessageMirroringModule extends AbstractModule { }); } - CompletableFuture future = + Task future = mirrorChannel.sendMessage(messageBuilder.build()) .thenApply(msg -> new MirroredMessage(msg, config)); mirrorFutures.add(future); - future.exceptionally(t -> { - if (t instanceof CompletionException) { - t = t.getCause(); - } + future.whenFailed(t -> { logger().error("Failed to mirror message to " + describeChannel(mirrorChannel), t); for (InputStream stream : streams) { try { stream.close(); } catch (IOException ignored) {} } - return null; }); } - CompletableFutureUtil.combine(mirrorFutures).whenComplete((messages, t2) -> { + Task.allOf(mirrorFutures).whenComplete((messages, t2) -> { MessageReference reference = getReference(operation.originalMessage, operation.configForOriginalMessage); Map references = new LinkedHashMap<>(); @@ -262,13 +256,7 @@ public class DiscordMessageMirroringModule extends AbstractModule { putIntoCache(reference, references); }); } - }).exceptionally(t -> { - if (t instanceof CompletionException) { - t = t.getCause(); - } - logger().error("Failed to mirror message", t); - return null; - }); + }).whenFailed(t -> logger().error("Failed to mirror message", t)); } private String describeChannel(DiscordGuildMessageChannel channel) { @@ -299,10 +287,8 @@ public class DiscordMessageMirroringModule extends AbstractModule { } SendableDiscordMessage sendableMessage = convert(message, channel, reference.config).build(); - channel.editMessageById(reference.messageId, sendableMessage).exceptionally(t -> { - logger().error("Failed to update mirrored message in " + channel); - return null; - }); + channel.editMessageById(reference.messageId, sendableMessage) + .whenFailed(t -> logger().error("Failed to update mirrored message in " + channel)); } } @@ -325,10 +311,8 @@ public class DiscordMessageMirroringModule extends AbstractModule { continue; } - channel.deleteMessageById(reference.messageId, reference.webhookMessage).exceptionally(t -> { - logger().error("Failed to delete mirrored message in " + describeChannel(channel)); - return null; - }); + channel.deleteMessageById(reference.messageId, reference.webhookMessage) + .whenFailed(t -> logger().error("Failed to delete mirrored message in " + describeChannel(channel))); } } diff --git a/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/AbstractGameMessageModule.java b/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/AbstractGameMessageModule.java index 9da4f7b6..1a517eaa 100644 --- a/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/AbstractGameMessageModule.java +++ b/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/AbstractGameMessageModule.java @@ -28,6 +28,7 @@ import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessageCluster; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; import com.discordsrv.api.events.message.receive.game.AbstractGameMessageReceiveEvent; import com.discordsrv.api.player.DiscordSRVPlayer; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.abstraction.player.IPlayer; import com.discordsrv.common.config.main.channels.base.BaseChannelConfig; @@ -37,7 +38,6 @@ import com.discordsrv.common.core.logging.NamedLogger; import com.discordsrv.common.core.module.type.AbstractModule; import com.discordsrv.common.discord.api.entity.message.ReceivedDiscordMessageClusterImpl; import com.discordsrv.common.helper.TestHelper; -import com.discordsrv.common.util.CompletableFutureUtil; import com.discordsrv.common.util.DiscordPermissionUtil; import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel; @@ -47,7 +47,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.concurrent.CompletableFuture; /** * An abstracted flow to send in-game messages to a given destination and publish the results to the event bus. @@ -86,7 +85,7 @@ public abstract class AbstractGameMessageModule process( + public final Task process( @Nullable E event, @Nullable DiscordSRVPlayer player, @Nullable GameChannel channel @@ -98,26 +97,26 @@ public abstract class AbstractGameMessageModule> futures = new ArrayList<>(); + List> futures = new ArrayList<>(); for (BaseChannelConfig channelConfig : discordSRV.channelConfig().getAllChannels()) { - CompletableFuture future = forwardToChannel(event, srvPlayer, channelConfig, null); + Task future = forwardToChannel(event, srvPlayer, channelConfig, null); if (future != null) { futures.add(future); } } - return CompletableFutureUtil.combine(futures); + return Task.allOf(futures); } BaseChannelConfig channelConfig = discordSRV.channelConfig().get(channel); if (channelConfig == null) { - return CompletableFuture.completedFuture(null); + return Task.completed(null); } return forwardToChannel(event, srvPlayer, channelConfig, channel); } @SuppressWarnings("unchecked") // Wacky generis - protected CompletableFuture forwardToChannel( + protected Task forwardToChannel( @Nullable E event, @Nullable IPlayer player, @NotNull BaseChannelConfig config, @@ -133,22 +132,22 @@ public abstract class AbstractGameMessageModule { + return discordSRV.destinations().lookupDestination(channelConfig.destination(), true, true).then(messageChannels -> { SendableDiscordMessage.Builder format = moduleConfig.format(); if (format == null || format.isEmpty()) { logger().debug("Message from " + player + " skipped, format is empty"); - return CompletableFuture.completedFuture(null); + return Task.completed(null); } - List> messageFutures = sendMessageToChannels( + List> messageFutures = sendMessageToChannels( moduleConfig, player, format, messageChannels, event, // Context config, player ); - return CompletableFutureUtil.combine(messageFutures).whenComplete((vo, t2) -> { + return Task.allOf(messageFutures).whenComplete((vo, t2) -> { Set messages = new LinkedHashSet<>(); - for (CompletableFuture future : messageFutures) { + for (Task future : messageFutures) { ReceivedDiscordMessage message = future.join(); if (message != null) { messages.add(message); @@ -161,19 +160,17 @@ public abstract class AbstractGameMessageModule { + }).whenFailed(t -> { discordSRV.logger().error("Failed to publish to event bus", t); TestHelper.fail(t); - return null; }).thenApply(v -> (Void) null); - }).exceptionally(t -> { + }).whenFailed(t -> { discordSRV.logger().error("Error in forwarding message", t); TestHelper.fail(t); - return null; }); } - public List> sendMessageToChannels( + public List> sendMessageToChannels( T config, IPlayer player, SendableDiscordMessage.Builder format, @@ -194,7 +191,7 @@ public abstract class AbstractGameMessageModule> futures = new ArrayList<>(); + List> futures = new ArrayList<>(); for (DiscordGuildMessageChannel channel : channels) { futures.add(sendMessageToChannel(channel, discordMessage)); } @@ -202,7 +199,7 @@ public abstract class AbstractGameMessageModule sendMessageToChannel(DiscordGuildMessageChannel channel, SendableDiscordMessage message) { + protected final @NotNull Task sendMessageToChannel(DiscordGuildMessageChannel channel, SendableDiscordMessage message) { GuildChannel permissionChannel = (GuildMessageChannel) channel.getAsJDAMessageChannel(); Permission sendPermission; @@ -220,13 +217,12 @@ public abstract class AbstractGameMessageModule { + return channel.sendMessage(message).whenFailed(t -> { ErrorCallbackContext.context("Failed to deliver a message to " + describeDestination(channel)).accept(t); TestHelper.fail(t); - return null; }); } diff --git a/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/JoinMessageModule.java b/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/JoinMessageModule.java index ace47745..219fda67 100644 --- a/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/JoinMessageModule.java +++ b/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/JoinMessageModule.java @@ -27,6 +27,7 @@ import com.discordsrv.api.eventbus.Subscribe; import com.discordsrv.api.events.message.forward.game.JoinMessageForwardedEvent; import com.discordsrv.api.events.message.receive.game.JoinMessageReceiveEvent; import com.discordsrv.api.player.DiscordSRVPlayer; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.abstraction.player.IPlayer; import com.discordsrv.common.config.main.channels.base.BaseChannelConfig; @@ -42,7 +43,6 @@ import java.time.Duration; import java.util.HashMap; import java.util.Map; import java.util.UUID; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; public class JoinMessageModule extends AbstractGameMessageModule { @@ -70,7 +70,7 @@ public class JoinMessageModule extends AbstractGameMessageModule forwardToChannel( + protected Task forwardToChannel( @Nullable JoinMessageReceiveEvent event, @Nullable IPlayer player, @NotNull BaseChannelConfig config, @@ -78,23 +78,22 @@ public class JoinMessageModule extends AbstractGameMessageModule 0) { UUID playerUUID = player.uniqueId(); - CompletableFuture completableFuture = new CompletableFuture<>(); synchronized (delayedTasks) { - CompletableFuture future = discordSRV.scheduler() + Task future = discordSRV.scheduler() .supplyLater(() -> super.forwardToChannel(event, player, config, channel), Duration.ofMillis(delay)) - .thenCompose(r -> r) + .then(r -> r) .whenComplete((v, t) -> delayedTasks.remove(playerUUID)); delayedTasks.put(playerUUID, future); + return future; } - return completableFuture; } return super.forwardToChannel(event, player, config, channel); } diff --git a/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/LeaveMessageModule.java b/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/LeaveMessageModule.java index 7c4a4b51..d66196ea 100644 --- a/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/LeaveMessageModule.java +++ b/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/LeaveMessageModule.java @@ -27,6 +27,7 @@ import com.discordsrv.api.eventbus.Subscribe; import com.discordsrv.api.events.message.forward.game.LeaveMessageForwardedEvent; import com.discordsrv.api.events.message.receive.game.LeaveMessageReceiveEvent; import com.discordsrv.api.player.DiscordSRVPlayer; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.abstraction.player.IPlayer; import com.discordsrv.common.config.main.channels.LeaveMessageConfig; @@ -42,7 +43,6 @@ import org.jetbrains.annotations.Nullable; import java.time.Duration; import java.util.Map; import java.util.UUID; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; @@ -93,7 +93,7 @@ public class LeaveMessageModule extends AbstractGameMessageModule forwardToChannel( + protected Task forwardToChannel( @Nullable LeaveMessageReceiveEvent event, @Nullable IPlayer player, @NotNull BaseChannelConfig config, @@ -105,14 +105,14 @@ public class LeaveMessageModule extends AbstractGameMessageModule { @@ -75,7 +75,7 @@ public class MinecraftToDiscordChatModule extends AbstractGameMessageModule> sendMessageToChannels( + public List> sendMessageToChannels( MinecraftToDiscordChatConfig config, IPlayer player, SendableDiscordMessage.Builder format, @@ -92,15 +92,15 @@ public class MinecraftToDiscordChatModule extends AbstractGameMessageModule> futures = new ArrayList<>(); + List> futures = new ArrayList<>(); // Format messages per-Guild for (Map.Entry> entry : channelMap.entrySet()) { Guild guild = entry.getKey().asJDA(); - CompletableFuture messageFuture = getMessageForGuild(config, format, guild, message, player, context); + Task messageFuture = getMessageForGuild(config, format, guild, message, player, context); for (DiscordGuildMessageChannel channel : entry.getValue()) { - futures.add(messageFuture.thenCompose(msg -> sendMessageToChannel(channel, msg))); + futures.add(messageFuture.then(msg -> sendMessageToChannel(channel, msg))); } } @@ -110,7 +110,7 @@ public class MinecraftToDiscordChatModule extends AbstractGameMessageModule getMessageForGuild( + private Task getMessageForGuild( MinecraftToDiscordChatConfig config, SendableDiscordMessage.Builder format, Guild guild, @@ -125,7 +125,7 @@ public class MinecraftToDiscordChatModule extends AbstractGameMessageModule getMessageForGuildWithMentions(config, format, guild, message, player, context, mentions)); } - return CompletableFuture.completedFuture(getMessageForGuildWithMentions(config, format, guild, message, player, context, null)); + return Task.completed(getMessageForGuildWithMentions(config, format, guild, message, player, context, null)); } private SendableDiscordMessage getMessageForGuildWithMentions( diff --git a/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/StartMessageModule.java b/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/StartMessageModule.java index b72b11c9..5c416b28 100644 --- a/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/StartMessageModule.java +++ b/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/StartMessageModule.java @@ -24,6 +24,7 @@ import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessage; import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessageCluster; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; import com.discordsrv.api.events.message.receive.game.AbstractGameMessageReceiveEvent; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.abstraction.player.IPlayer; import com.discordsrv.common.config.main.channels.StartMessageConfig; @@ -33,7 +34,6 @@ import org.jetbrains.annotations.NotNull; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.concurrent.CompletableFuture; public class StartMessageModule extends AbstractGameMessageModule { @@ -55,7 +55,7 @@ public class StartMessageModule extends AbstractGameMessageModule> sendMessageToChannels( + public List> sendMessageToChannels( StartMessageConfig config, IPlayer player, SendableDiscordMessage.Builder format, diff --git a/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/StopMessageModule.java b/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/StopMessageModule.java index 927bfbaf..70488c8d 100644 --- a/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/StopMessageModule.java +++ b/common/src/main/java/com/discordsrv/common/feature/messageforwarding/game/StopMessageModule.java @@ -24,6 +24,7 @@ import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessage; import com.discordsrv.api.discord.entity.message.ReceivedDiscordMessageCluster; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; import com.discordsrv.api.events.message.receive.game.AbstractGameMessageReceiveEvent; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.abstraction.player.IPlayer; import com.discordsrv.common.config.main.channels.StopMessageConfig; @@ -33,7 +34,6 @@ import org.jetbrains.annotations.NotNull; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -58,7 +58,7 @@ public class StopMessageModule extends AbstractGameMessageModule> sendMessageToChannels( + public List> sendMessageToChannels( StopMessageConfig config, IPlayer player, SendableDiscordMessage.Builder format, diff --git a/common/src/main/java/com/discordsrv/common/helper/DestinationLookupHelper.java b/common/src/main/java/com/discordsrv/common/helper/DestinationLookupHelper.java index d69a2e86..3b447729 100644 --- a/common/src/main/java/com/discordsrv/common/helper/DestinationLookupHelper.java +++ b/common/src/main/java/com/discordsrv/common/helper/DestinationLookupHelper.java @@ -20,6 +20,7 @@ package com.discordsrv.common.helper; import com.discordsrv.api.discord.entity.channel.*; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.config.main.generic.DestinationConfig; import com.discordsrv.common.config.main.generic.ThreadConfig; @@ -32,26 +33,26 @@ import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel; import org.apache.commons.lang3.StringUtils; import java.util.*; -import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; public class DestinationLookupHelper { private final DiscordSRV discordSRV; private final Logger logger; - private final Map> threadActions = new HashMap<>(); + private final Map> threadActions = new HashMap<>(); public DestinationLookupHelper(DiscordSRV discordSRV) { this.discordSRV = discordSRV; this.logger = new NamedLogger(discordSRV, "DESTINATION_LOOKUP"); } - public CompletableFuture> lookupDestination( + public Task> lookupDestination( DestinationConfig config, boolean allowRequests, boolean logFailures, Object... threadNameContext ) { - List> futures = new ArrayList<>(); + List> futures = new ArrayList<>(); for (Long channelId : config.channelIds) { if (channelId == 0) { @@ -68,7 +69,7 @@ public class DestinationLookupHelper { if (!(channel instanceof DiscordGuildMessageChannel)) { continue; } - futures.add(CompletableFuture.completedFuture((DiscordGuildMessageChannel) channel)); + futures.add(Task.completed((DiscordGuildMessageChannel) channel)); } for (ThreadConfig threadConfig : config.threads) { @@ -101,7 +102,7 @@ public class DestinationLookupHelper { DiscordThreadChannel existingThread = findThread(threadContainer.getActiveThreads(), threadName, privateThread); if (existingThread != null && !existingThread.isArchived()) { - futures.add(CompletableFuture.completedFuture(existingThread)); + futures.add(Task.completed(existingThread)); continue; } @@ -111,9 +112,9 @@ public class DestinationLookupHelper { String threadKey = Long.toUnsignedString(channelId) + ":" + threadName + "/" + privateThread; - CompletableFuture future; + Task future; synchronized (threadActions) { - CompletableFuture existingFuture = threadActions.get(threadKey); + Task existingFuture = threadActions.get(threadKey); if (existingFuture != null) { future = existingFuture; @@ -125,12 +126,12 @@ public class DestinationLookupHelper { future = unarchiveThread(existingThread, logFailures); } else { // Lookup threads - CompletableFuture> threads = + Task> threads = privateThread ? threadContainer.retrieveArchivedPrivateThreads() : threadContainer.retrieveArchivedPublicThreads(); - future = threads.thenCompose(archivedThreads -> { + future = threads.then(archivedThreads -> { DiscordThreadChannel archivedThread = findThread(archivedThreads, threadName, privateThread); if (archivedThread != null) { // Unarchive existing thread @@ -139,7 +140,7 @@ public class DestinationLookupHelper { // Create thread return createThread(threadContainer, threadName, privateThread, logFailures); - }).exceptionally(t -> { + }).mapException(t -> { if (logFailures) { logger.error("Failed to lookup threads in channel #" + threadContainer.getName(), t); } @@ -155,15 +156,15 @@ public class DestinationLookupHelper { futures.add(future); } - return CompletableFuture.allOf( + return Task.allOf( futures.stream() - .map(future -> (CompletableFuture) future) - .toArray(CompletableFuture[]::new) + .map(future -> (Task) future) + .collect(Collectors.toList()) ).thenApply(v -> { Set idsDuplicateCheck = new HashSet<>(); List channels = new ArrayList<>(); - for (CompletableFuture future : futures) { + for (Task future : futures) { DiscordGuildMessageChannel channel = future.join(); if (channel != null && idsDuplicateCheck.add(channel.getId())) { channels.add(channel); @@ -182,7 +183,7 @@ public class DestinationLookupHelper { return null; } - private CompletableFuture createThread( + private Task createThread( DiscordThreadContainer threadContainer, String threadName, boolean privateThread, @@ -208,10 +209,10 @@ public class DestinationLookupHelper { logger.error("Failed to create thread \"" + threadName + "\" " + "in channel #" + threadContainer.getName() + ": " + missingPermissions); } - return CompletableFuture.completedFuture(null); + return Task.completed(null); } - CompletableFuture future; + Task future; if (forum) { SendableDiscordMessage message = SendableDiscordMessage.builder().setContent("\u200B").build(); // zero-width-space @@ -223,7 +224,7 @@ public class DestinationLookupHelper { } else { future = threadContainer.createThread(threadName, privateThread); } - return future.exceptionally(t -> { + return future.mapException(t -> { if (logFailures) { logger.error("Failed to create thread \"" + threadName + "\" " + "in channel #" + threadContainer.getName(), t); @@ -232,7 +233,7 @@ public class DestinationLookupHelper { }); } - private CompletableFuture unarchiveThread(DiscordThreadChannel channel, boolean logFailures) { + private Task unarchiveThread(DiscordThreadChannel channel, boolean logFailures) { ThreadChannel jdaChannel = channel.asJDA(); EnumSet requiredPermissions = EnumSet.of(Permission.VIEW_CHANNEL); @@ -246,20 +247,18 @@ public class DestinationLookupHelper { logger.error("Cannot unarchive thread \"" + channel.getName() + "\" " + "in channel #" + channel.getParentChannel().getName() + ": " + missingPermissions); } - return CompletableFuture.completedFuture(null); + return Task.completed(null); } - return discordSRV.discordAPI().mapExceptions( - channel.asJDA().getManager() - .setArchived(false) - .reason("DiscordSRV destination lookup") - .submit() - ).thenApply(v -> channel).handle(t -> { - if (logFailures) { - logger.error("Failed to unarchive thread \"" + channel.getName() + "\" " - + "in channel #" + channel.getParentChannel().getName(), t); - } - return null; - }); + return discordSRV.discordAPI() + .toTask(() -> channel.asJDA().getManager().setArchived(false).reason("DiscordSRV destination lookup")) + .thenApply(v -> channel) + .mapException(t -> { + if (logFailures) { + logger.error("Failed to unarchive thread \"" + channel.getName() + "\" " + + "in channel #" + channel.getParentChannel().getName(), t); + } + return null; + }); } } diff --git a/common/src/main/java/com/discordsrv/common/integration/LuckPermsIntegration.java b/common/src/main/java/com/discordsrv/common/integration/LuckPermsIntegration.java index a5c3b2d0..5737473d 100644 --- a/common/src/main/java/com/discordsrv/common/integration/LuckPermsIntegration.java +++ b/common/src/main/java/com/discordsrv/common/integration/LuckPermsIntegration.java @@ -25,7 +25,6 @@ import com.discordsrv.common.core.module.type.PluginIntegration; import com.discordsrv.common.exception.MessageException; import com.discordsrv.common.feature.groupsync.GroupSyncModule; import com.discordsrv.common.feature.groupsync.enums.GroupSyncCause; -import com.discordsrv.common.util.CompletableFutureUtil; import net.luckperms.api.LuckPerms; import net.luckperms.api.LuckPermsProvider; import net.luckperms.api.context.ContextSet; @@ -156,7 +155,7 @@ public class LuckPermsIntegration extends PluginIntegration implemen if (group == null) { return Task.failed(new MessageException("Group does not exist")); } - return user(player).thenCompose(user -> { + return user(player).then(user -> { ContextSet contexts; if (serverContext != null) { if (isNotGlobalOnly(serverContext)) { @@ -179,10 +178,10 @@ public class LuckPermsIntegration extends PluginIntegration implemen InheritanceNode node = InheritanceNode.builder(group).context(contexts).build(); DataMutateResult result = function.apply(user.data(), node); if (!result.wasSuccessful()) { - return CompletableFutureUtil.failed(new MessageException("Group mutate failed: " + result.name())); + return Task.failed(new MessageException("Group mutate failed: " + result.name())); } - return luckPerms.getUserManager().saveUser(user); + return Task.of(luckPerms.getUserManager().saveUser(user)); }); } diff --git a/common/src/main/java/com/discordsrv/common/util/CommandUtil.java b/common/src/main/java/com/discordsrv/common/util/CommandUtil.java index ab0a40ed..dcdf08d6 100644 --- a/common/src/main/java/com/discordsrv/common/util/CommandUtil.java +++ b/common/src/main/java/com/discordsrv/common/util/CommandUtil.java @@ -19,6 +19,7 @@ package com.discordsrv.common.util; import com.discordsrv.api.DiscordSRVApi; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.abstraction.player.IPlayer; import com.discordsrv.common.command.combined.abstraction.CommandExecution; @@ -38,7 +39,6 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.UUID; -import java.util.concurrent.CompletableFuture; public final class CommandUtil { @@ -60,7 +60,7 @@ public final class CommandUtil { } } - public static CompletableFuture lookupPlayer( + public static Task lookupPlayer( DiscordSRV discordSRV, Logger logger, CommandExecution execution, @@ -77,7 +77,7 @@ public final class CommandUtil { }); } - public static CompletableFuture lookupUser( + public static Task lookupUser( DiscordSRV discordSRV, Logger logger, CommandExecution execution, @@ -94,7 +94,7 @@ public final class CommandUtil { }); } - public static CompletableFuture lookupTarget( + public static Task lookupTarget( DiscordSRV discordSRV, Logger logger, CommandExecution execution, @@ -111,7 +111,7 @@ public final class CommandUtil { return lookupTarget(discordSRV, logger, execution, target, selfPermitted, true, true, otherPermission); } - private static CompletableFuture lookupTarget( + private static Task lookupTarget( DiscordSRV discordSRV, Logger logger, CommandExecution execution, @@ -128,7 +128,7 @@ public final class CommandUtil { if (target != null) { if (otherPermission != null && !sender.hasPermission(otherPermission)) { sender.sendMessage(discordSRV.messagesConfig(sender).noPermission.asComponent()); - return CompletableFuture.completedFuture(TargetLookupResult.INVALID); + return Task.completed(TargetLookupResult.INVALID); } } else if (sender instanceof IPlayer && selfPermitted && lookupPlayer) { target = ((IPlayer) sender).uniqueId().toString(); @@ -142,7 +142,7 @@ public final class CommandUtil { messages.minecraft.pleaseSpecifyUser.asComponent(), messages.discord.pleaseSpecifyUser.get() ); - return CompletableFuture.completedFuture(TargetLookupResult.INVALID); + return Task.completed(TargetLookupResult.INVALID); } } } else { @@ -150,7 +150,7 @@ public final class CommandUtil { } if (target == null) { - return CompletableFuture.completedFuture(requireTarget(execution, lookupUser, lookupPlayer, messages)); + return Task.completed(requireTarget(execution, lookupUser, lookupPlayer, messages)); } if (lookupUser) { @@ -164,10 +164,10 @@ public final class CommandUtil { messages.minecraft.userNotFound.asComponent(), messages.discord.userNotFound.get() ); - return CompletableFuture.completedFuture(TargetLookupResult.INVALID); + return Task.completed(TargetLookupResult.INVALID); } - return CompletableFuture.completedFuture(new TargetLookupResult(true, null, id)); + return Task.completed(new TargetLookupResult(true, null, id)); } else if (target.startsWith("@")) { // Discord username String username = target.substring(1); @@ -176,7 +176,7 @@ public final class CommandUtil { List users = jda.getUsersByName(username, true); if (users.size() == 1) { - return CompletableFuture.completedFuture(new TargetLookupResult(true, null, users.get(0).getIdLong())); + return Task.completed(new TargetLookupResult(true, null, users.get(0).getIdLong())); } } } @@ -198,9 +198,9 @@ public final class CommandUtil { messages.minecraft.playerNotFound.asComponent(), messages.discord.playerNotFound.get() ); - return CompletableFuture.completedFuture(TargetLookupResult.INVALID); + return Task.completed(TargetLookupResult.INVALID); } - return CompletableFuture.completedFuture(new TargetLookupResult(true, uuid, 0L)); + return Task.completed(new TargetLookupResult(true, uuid, 0L)); } else if (target.matches("[a-zA-Z0-9_]{1,16}")) { // Player name IPlayer playerByName = discordSRV.playerProvider().player(target); @@ -209,16 +209,16 @@ public final class CommandUtil { } else { return discordSRV.playerProvider().lookupOfflinePlayer(target) .thenApply(offlinePlayer -> new TargetLookupResult(true, offlinePlayer.uniqueId(), 0L)) - .exceptionally(t -> { + .mapException(t -> { logger.error("Failed to lookup offline player by username", t); return TargetLookupResult.INVALID; }); } - return CompletableFuture.completedFuture(new TargetLookupResult(true, uuid, 0L)); + return Task.completed(new TargetLookupResult(true, uuid, 0L)); } } - return CompletableFuture.completedFuture(requireTarget(execution, lookupUser, lookupPlayer, messages)); + return Task.completed(requireTarget(execution, lookupUser, lookupPlayer, messages)); } private static TargetLookupResult requireTarget(CommandExecution execution, boolean lookupUser, boolean lookupPlayer, MessagesConfig messages) { diff --git a/common/src/main/java/com/discordsrv/common/util/CompletableFutureUtil.java b/common/src/main/java/com/discordsrv/common/util/TaskUtil.java similarity index 53% rename from common/src/main/java/com/discordsrv/common/util/CompletableFutureUtil.java rename to common/src/main/java/com/discordsrv/common/util/TaskUtil.java index 30fa27da..d5cd7e85 100644 --- a/common/src/main/java/com/discordsrv/common/util/CompletableFutureUtil.java +++ b/common/src/main/java/com/discordsrv/common/util/TaskUtil.java @@ -18,63 +18,25 @@ package com.discordsrv.common.util; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.util.function.CheckedRunnable; import com.discordsrv.common.util.function.CheckedSupplier; import org.jetbrains.annotations.NotNull; import java.time.Duration; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeoutException; -public final class CompletableFutureUtil { - - private CompletableFutureUtil() {} - - /** - * Same as {@link CompletableFuture#completedFuture(Object)} but for failing. - */ - @NotNull - public static CompletableFuture failed(@NotNull Throwable throwable) { - CompletableFuture future = new CompletableFuture<>(); - future.completeExceptionally(throwable); - return future; - } - - @SuppressWarnings("unchecked") - @NotNull - public static CompletableFuture> combine(@NotNull Collection<@NotNull CompletableFuture> futures) { - return combine(futures.toArray(new CompletableFuture[0])); - } - - @SuppressWarnings("unchecked") - @NotNull - public static CompletableFuture> combineGeneric(@NotNull Collection<@NotNull CompletableFuture> futures) { - return combine(futures.toArray(new CompletableFuture[0])); - } - - @SafeVarargs - @NotNull - public static CompletableFuture> combine(@NotNull CompletableFuture<@NotNull T>... futures) { - return CompletableFuture.allOf(futures).thenApply(v -> { - List results = new ArrayList<>(); - for (CompletableFuture aFuture : futures) { - results.add(aFuture.join()); - } - return results; - }); - } +public final class TaskUtil { @NotNull - public static CompletableFuture timeout(@NotNull DiscordSRV discordSRV, @NotNull CompletableFuture future, @NotNull Duration timeout) { + public static Task timeout(@NotNull DiscordSRV discordSRV, @NotNull Task future, @NotNull Duration timeout) { ScheduledFuture scheduledFuture = discordSRV.scheduler().runLater(() -> { if (!future.isDone()) { - future.completeExceptionally(new TimeoutException()); + future.getFuture().completeExceptionally(new TimeoutException()); } }, timeout); return future.whenComplete((__, t) -> { @@ -85,7 +47,7 @@ public final class CompletableFutureUtil { } @NotNull - public static CompletableFuture supplyAsync(@NotNull CheckedSupplier supplier, @NotNull Executor executor) { + public static Task supplyAsync(@NotNull CheckedSupplier supplier, @NotNull Executor executor) { CompletableFuture future = new CompletableFuture<>(); executor.execute(() -> { if (future.isCancelled()) { @@ -99,11 +61,11 @@ public final class CompletableFutureUtil { future.completeExceptionally(t); } }); - return future; + return Task.of(future); } @NotNull - public static CompletableFuture runAsync(@NotNull CheckedRunnable runnable, @NotNull Executor executor) { + public static Task runAsync(@NotNull CheckedRunnable runnable, @NotNull Executor executor) { return supplyAsync(() -> { runnable.run(); return null; diff --git a/common/src/test/java/com/discordsrv/common/command/game/GameCommandFilterTest.java b/common/src/test/java/com/discordsrv/common/command/game/GameCommandFilterTest.java index 3edf442c..c15cf641 100644 --- a/common/src/test/java/com/discordsrv/common/command/game/GameCommandFilterTest.java +++ b/common/src/test/java/com/discordsrv/common/command/game/GameCommandFilterTest.java @@ -18,6 +18,7 @@ package com.discordsrv.common.command.game; +import com.discordsrv.api.task.Task; import com.discordsrv.common.command.game.abstraction.GameCommandExecutionHelper; import com.discordsrv.common.config.main.generic.GameCommandExecutionConditionConfig; import org.junit.jupiter.api.Assertions; @@ -26,7 +27,6 @@ import org.junit.jupiter.api.Test; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.concurrent.CompletableFuture; public class GameCommandFilterTest { @@ -110,7 +110,7 @@ public class GameCommandFilterTest { private final List TESTER = Arrays.asList("tester", "plugin2:tester"); @Override - public CompletableFuture> suggestCommands(List parts) { + public Task> suggestCommands(List parts) { return null; } diff --git a/common/src/test/java/com/discordsrv/common/linking/requirement/parser/RequirementTypeParserTest.java b/common/src/test/java/com/discordsrv/common/linking/requirement/parser/RequirementTypeParserTest.java index 65ff7a7c..a0edbfd2 100644 --- a/common/src/test/java/com/discordsrv/common/linking/requirement/parser/RequirementTypeParserTest.java +++ b/common/src/test/java/com/discordsrv/common/linking/requirement/parser/RequirementTypeParserTest.java @@ -18,6 +18,7 @@ package com.discordsrv.common.linking.requirement.parser; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.MockDiscordSRV; import com.discordsrv.common.abstraction.player.IPlayer; @@ -34,7 +35,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.UUID; -import java.util.concurrent.CompletableFuture; import static org.junit.jupiter.api.Assertions.*; @@ -71,8 +71,8 @@ public class RequirementTypeParserTest { } @Override - public CompletableFuture isMet(Boolean value, Someone.Resolved someone) { - return CompletableFuture.completedFuture(value); + public Task isMet(Boolean value, Someone.Resolved someone) { + return Task.completed(value); } }, new RequirementType(module) { @@ -87,7 +87,7 @@ public class RequirementTypeParserTest { } @Override - public CompletableFuture isMet(Object value, Someone.Resolved someone) { + public Task isMet(Object value, Someone.Resolved someone) { return null; } } diff --git a/common/src/test/java/com/discordsrv/common/messageforwarding/game/MinecraftToDiscordChatMessageTest.java b/common/src/test/java/com/discordsrv/common/messageforwarding/game/MinecraftToDiscordChatMessageTest.java index 92f42ecf..8d3b6eaf 100644 --- a/common/src/test/java/com/discordsrv/common/messageforwarding/game/MinecraftToDiscordChatMessageTest.java +++ b/common/src/test/java/com/discordsrv/common/messageforwarding/game/MinecraftToDiscordChatMessageTest.java @@ -24,6 +24,7 @@ import com.discordsrv.api.eventbus.EventBus; import com.discordsrv.api.eventbus.Subscribe; import com.discordsrv.api.events.message.forward.game.GameChatMessageForwardedEvent; import com.discordsrv.api.events.message.receive.game.GameChatMessageReceiveEvent; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.FullBootExtension; import com.discordsrv.common.MockDiscordSRV; @@ -93,7 +94,7 @@ public class MinecraftToDiscordChatMessageTest { } @Override - public CompletableFuture kick(Component component) { + public Task kick(Component component) { return null; } diff --git a/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java b/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java index 66165ec9..64919e85 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java +++ b/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java @@ -18,6 +18,7 @@ package com.discordsrv.fabric.command.game; +import com.discordsrv.api.task.Task; import com.discordsrv.common.command.game.abstraction.GameCommandExecutionHelper; import com.discordsrv.fabric.FabricDiscordSRV; import com.mojang.brigadier.CommandDispatcher; @@ -31,7 +32,6 @@ import net.minecraft.server.command.ServerCommandSource; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; @@ -46,7 +46,7 @@ public class FabricGameCommandExecutionHelper implements GameCommandExecutionHel } @Override - public CompletableFuture> suggestCommands(List parts) { + public Task> suggestCommands(List parts) { String fullCommand = String.join(" ", parts); if (parts.isEmpty() || fullCommand.isBlank()) { return getRootCommands(); @@ -59,7 +59,7 @@ public class FabricGameCommandExecutionHelper implements GameCommandExecutionHel data.add(fullCommand); parse.getExceptions().values().stream().map(Exception::getMessage).map(this::splitErrorMessage).forEach(data::addAll); - return CompletableFuture.completedFuture(data); + return Task.completed(data); } List> nodes = parse.getContext().getNodes(); @@ -67,7 +67,7 @@ public class FabricGameCommandExecutionHelper implements GameCommandExecutionHel CommandNode lastNode = nodes.getLast().getNode(); if (lastNode.getChildren().isEmpty() && lastNode.getRedirect() == null) { // We reached the end of the command tree. Suggest the full command as a valid command. - return CompletableFuture.completedFuture(Collections.singletonList(fullCommand)); + return Task.completed(Collections.singletonList(fullCommand)); } } @@ -93,9 +93,9 @@ public class FabricGameCommandExecutionHelper implements GameCommandExecutionHel } } data = data.stream().map(String::trim).distinct().collect(Collectors.toList()); - return CompletableFuture.completedFuture(data); + return Task.completed(data); } catch (InterruptedException | ExecutionException e) { - return CompletableFuture.completedFuture(Collections.emptyList()); + return Task.completed(Collections.emptyList()); } } @@ -114,8 +114,8 @@ public class FabricGameCommandExecutionHelper implements GameCommandExecutionHel return false; } - private CompletableFuture> getRootCommands() { - return CompletableFuture.completedFuture( + private Task> getRootCommands() { + return Task.completed( dispatcher.getRoot().getChildren() .stream() .map(CommandNode::getName) diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java index 118f0b9e..7a161104 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java @@ -21,6 +21,7 @@ package com.discordsrv.fabric.module.ban; import com.discordsrv.api.component.MinecraftComponent; import com.discordsrv.api.module.type.PunishmentModule; import com.discordsrv.api.punishment.Punishment; +import com.discordsrv.api.task.Task; import com.discordsrv.common.abstraction.player.IPlayer; import com.discordsrv.common.core.logging.NamedLogger; import com.discordsrv.common.feature.bansync.BanSyncModule; @@ -42,7 +43,6 @@ import java.util.Date; import java.util.Objects; import java.util.Optional; import java.util.UUID; -import java.util.concurrent.CompletableFuture; public class FabricBanModule extends AbstractFabricModule implements PunishmentModule.Bans { @@ -77,7 +77,7 @@ public class FabricBanModule extends AbstractFabricModule implements PunishmentM if (instance == null) return; FabricDiscordSRV discordSRV = instance.discordSRV; BanSyncModule module = discordSRV.getModule(BanSyncModule.class); - if (module != null) instance.removeBan(gameProfile.getId()).complete(null); + if (module != null) instance.removeBan(gameProfile.getId()); } @Override @@ -86,21 +86,21 @@ public class FabricBanModule extends AbstractFabricModule implements PunishmentM } @Override - public CompletableFuture<@Nullable Punishment> getBan(@NotNull UUID playerUUID) { + public Task<@Nullable Punishment> getBan(@NotNull UUID playerUUID) { BannedPlayerList banList = discordSRV.getServer().getPlayerManager().getUserBanList(); Optional gameProfile = Objects.requireNonNull(discordSRV.getServer().getUserCache()).getByUuid(playerUUID); if (gameProfile.isEmpty()) { - return CompletableFuture.completedFuture(null); + return Task.completed(null); } BannedPlayerEntry banEntry = banList.get(gameProfile.get()); if (banEntry == null) { - return CompletableFuture.completedFuture(null); + return Task.completed(null); } Date expiration = banEntry.getExpiryDate(); - return CompletableFuture.completedFuture(new Punishment( + return Task.completed(new Punishment( expiration != null ? expiration.toInstant() : null, ComponentUtil.fromPlain(banEntry.getReason()), ComponentUtil.fromPlain(banEntry.getSource()) @@ -108,7 +108,7 @@ public class FabricBanModule extends AbstractFabricModule implements PunishmentM } @Override - public CompletableFuture addBan( + public Task addBan( @NotNull UUID playerUUID, @Nullable Instant until, @Nullable MinecraftComponent reason, @@ -141,19 +141,19 @@ public class FabricBanModule extends AbstractFabricModule implements PunishmentM discordSRV.logger().error("Failed to ban player", e); } - return CompletableFuture.completedFuture(null); + return Task.completed(null); } @Override - public CompletableFuture removeBan(@NotNull UUID playerUUID) { + public Task removeBan(@NotNull UUID playerUUID) { BannedPlayerList banList = discordSRV.getServer().getPlayerManager().getUserBanList(); Optional gameProfile = Objects.requireNonNull(discordSRV.getServer().getUserCache()).getByUuid(playerUUID); if (gameProfile.isEmpty()) { - return CompletableFuture.completedFuture(null); + return Task.completed(null); } banList.remove(gameProfile.get()); - return CompletableFuture.completedFuture(null); + return Task.completed(null); } } diff --git a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java index 117778ae..4da1d27c 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java +++ b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java @@ -18,6 +18,7 @@ package com.discordsrv.fabric.player; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.abstraction.player.IPlayer; import com.discordsrv.common.abstraction.player.provider.model.SkinInfo; @@ -35,7 +36,6 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; import java.util.Locale; -import java.util.concurrent.CompletableFuture; public class FabricPlayer extends FabricCommandSender implements IPlayer { @@ -62,9 +62,9 @@ public class FabricPlayer extends FabricCommandSender implements IPlayer { } @Override - public CompletableFuture kick(Component component) { + public Task kick(Component component) { player.networkHandler.disconnect(Text.of(component.toString())); - return CompletableFuture.completedFuture(null); + return Task.completed(null); } @Override diff --git a/velocity/src/main/java/com/discordsrv/velocity/player/VelocityPlayer.java b/velocity/src/main/java/com/discordsrv/velocity/player/VelocityPlayer.java index 42bc8723..f91863fc 100644 --- a/velocity/src/main/java/com/discordsrv/velocity/player/VelocityPlayer.java +++ b/velocity/src/main/java/com/discordsrv/velocity/player/VelocityPlayer.java @@ -18,6 +18,7 @@ package com.discordsrv.velocity.player; +import com.discordsrv.api.task.Task; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.abstraction.player.IPlayer; import com.discordsrv.common.abstraction.player.provider.model.SkinInfo; @@ -34,7 +35,6 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Locale; -import java.util.concurrent.CompletableFuture; public class VelocityPlayer extends VelocityCommandSender implements IPlayer { @@ -56,9 +56,9 @@ public class VelocityPlayer extends VelocityCommandSender implements IPlayer { } @Override - public CompletableFuture kick(Component component) { + public Task kick(Component component) { player.disconnect(component); - return CompletableFuture.completedFuture(null); + return Task.completed(null); } @Override