Complete conversion to Task from CompletableFuture

This commit is contained in:
Vankka 2025-02-14 22:19:44 +02:00
parent 269f286838
commit f7dcd69b77
No known key found for this signature in database
GPG Key ID: 62E48025ED4E7EBB
81 changed files with 696 additions and 628 deletions

View File

@ -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<ForumChannel> {
CompletableFuture<DiscordThreadChannel> createPost(String name, SendableDiscordMessage message);
Task<DiscordThreadChannel> createPost(String name, SendableDiscordMessage message);
}

View File

@ -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<Void> delete();
Task<Void> delete();
}

View File

@ -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<MediaChannel> {
CompletableFuture<DiscordThreadChannel> createPost(String name, SendableDiscordMessage message);
Task<DiscordThreadChannel> createPost(String name, SendableDiscordMessage message);
}

View File

@ -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<ReceivedDiscordMessage> sendMessage(@NotNull SendableDiscordMessage message);
Task<ReceivedDiscordMessage> 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<Void> deleteMessageById(long id, boolean webhookMessage);
Task<Void> 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<ReceivedDiscordMessage> editMessageById(long id, @NotNull SendableDiscordMessage message);
Task<ReceivedDiscordMessage> editMessageById(long id, @NotNull SendableDiscordMessage message);
/**
* Returns the JDA representation of this object. This should not be used if it can be avoided.

View File

@ -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<DiscordThreadChannel> getActiveThreads();
CompletableFuture<List<DiscordThreadChannel>> retrieveArchivedPrivateThreads();
CompletableFuture<List<DiscordThreadChannel>> retrieveArchivedJoinedPrivateThreads();
CompletableFuture<List<DiscordThreadChannel>> retrieveArchivedPublicThreads();
Task<List<DiscordThreadChannel>> retrieveArchivedPrivateThreads();
Task<List<DiscordThreadChannel>> retrieveArchivedJoinedPrivateThreads();
Task<List<DiscordThreadChannel>> retrieveArchivedPublicThreads();
CompletableFuture<DiscordThreadChannel> createThread(String name, boolean privateThread);
CompletableFuture<DiscordThreadChannel> createThread(String name, long messageId);
Task<DiscordThreadChannel> createThread(String name, boolean privateThread);
Task<DiscordThreadChannel> createThread(String name, long messageId);
/**
* Returns the JDA representation of this object. This should not be used if it can be avoided.

View File

@ -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.

View File

@ -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<Member>, Mentionable {
* @param role the role to give
* @return a future
*/
CompletableFuture<Void> addRole(@NotNull DiscordRole role);
Task<Void> addRole(@NotNull DiscordRole role);
/**
* Takes the given role from this member.
* @param role the role to take
* @return a future
*/
CompletableFuture<Void> removeRole(@NotNull DiscordRole role);
Task<Void> removeRole(@NotNull DiscordRole role);
/**
* Gets the effective name of this Discord server member.

View File

@ -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<InteractionHook> {
long getExpiryTime();
boolean isExpired();
CompletableFuture<ReceivedDiscordMessage> editOriginal(SendableDiscordMessage message);
CompletableFuture<ReceivedDiscordMessage> sendMessage(SendableDiscordMessage message, boolean ephemeral);
default CompletableFuture<ReceivedDiscordMessage> sendMessage(SendableDiscordMessage message) {
Task<ReceivedDiscordMessage> editOriginal(SendableDiscordMessage message);
Task<ReceivedDiscordMessage> sendMessage(SendableDiscordMessage message, boolean ephemeral);
default Task<ReceivedDiscordMessage> sendMessage(SendableDiscordMessage message) {
return sendMessage(message, false);
}
}

View File

@ -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<Void> delete();
Task<Void> 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<ReceivedDiscordMessage> edit(@NotNull SendableDiscordMessage message);
Task<ReceivedDiscordMessage> 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<ReceivedDiscordMessage> reply(@NotNull SendableDiscordMessage message);
Task<ReceivedDiscordMessage> reply(@NotNull SendableDiscordMessage message);
class Attachment {

View File

@ -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<Void> deleteAll();
@NotNull Task<Void> 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<ReceivedDiscordMessageCluster> editAll(SendableDiscordMessage newMessage);
@NotNull Task<ReceivedDiscordMessageCluster> editAll(SendableDiscordMessage newMessage);
}

View File

@ -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<E extends GenericCommandInteractionEvent>
extends AbstractInteractionWithHookEvent<E> {
@ -57,13 +56,13 @@ public abstract class AbstractCommandInteractionEvent<E extends GenericCommandIn
this.discordSRV = discordSRV;
}
public abstract CompletableFuture<DiscordInteractionHook> reply(SendableDiscordMessage message, boolean ephemeral);
public abstract Task<DiscordInteractionHook> reply(SendableDiscordMessage message, boolean ephemeral);
public CompletableFuture<DiscordInteractionHook> reply(SendableDiscordMessage message) {
public Task<DiscordInteractionHook> reply(SendableDiscordMessage message) {
return reply(message, false);
}
public abstract CompletableFuture<DiscordInteractionHook> deferReply(boolean ephemeral);
public abstract Task<DiscordInteractionHook> deferReply(boolean ephemeral);
@Nullable
public String getOptionAsString(String name) {

View File

@ -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<T> implements Future<T> {
public static <T> Task<T> of(@NotNull CompletableFuture<T> future) {
return new Task<>(future);
}
public static <T> Task<T> failed(@NotNull Throwable throwable) {
return of(failedFuture(throwable));
}
public static <T> Task<T> completed(@Nullable T result) {
return of(CompletableFuture.completedFuture(result));
}
@SuppressWarnings("unchecked")
public static <T> Task<T> anyOf(@NotNull Collection<Task<T>> tasks) {
return anyOf(tasks.toArray(new Task[0]));
}
@SuppressWarnings("unchecked")
@NotNull
public static <T> Task<T> anyOfGeneric(@NotNull Collection<@NotNull Task<? extends T>> futures) {
return anyOf(futures.toArray(new Task[0]));
}
@SuppressWarnings("unchecked")
public static <T> Task<T> anyOf(@NotNull Task<T>... tasks) {
CompletableFuture<T>[] 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 <T> Task<List<T>> allOf(@NotNull Collection<Task<T>> tasks) {
return allOf(tasks.toArray(new Task[0]));
}
@SuppressWarnings("unchecked")
@NotNull
public static <T> Task<List<T>> allOfGeneric(@NotNull Collection<@NotNull Task<? extends T>> futures) {
return allOf(futures.toArray(new Task[0]));
}
@SuppressWarnings("unchecked")
@SafeVarargs
public static <T> Task<List<T>> allOf(@NotNull Task<T>... tasks) {
CompletableFuture<T>[] 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<T> results = new ArrayList<>(futures.length);
for (CompletableFuture<T> aFuture : futures) {
results.add(aFuture.join());
}
return results;
}));
}
private static <T> CompletableFuture<T> failedFuture(@NotNull Throwable throwable) {
CompletableFuture<T> future = new CompletableFuture<>();
future.completeExceptionally(throwable);
return future;
}
private final CompletableFuture<T> future;
private Task(@NotNull CompletableFuture<T> future) {
this.future = future;
}
public CompletableFuture<T> 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<T> whenSuccessful(@NotNull Consumer<T> successConsumer) {
return of(future.whenComplete((result, throwable) -> {
if (throwable == null) {
successConsumer.accept(result);
}
}));
}
public Task<T> whenFailed(@NotNull Consumer<Throwable> failureConsumer) {
return of(future.whenComplete((result, throwable) -> {
if (throwable != null) {
failureConsumer.accept(throwable);
}
}));
}
public Task<T> whenComplete(@NotNull BiConsumer<T, Throwable> consumer) {
return of(future.whenComplete(consumer));
}
public <U> Task<U> thenApply(@NotNull Function<T, U> mappingFunction) {
return of(future.thenCompose(result -> map(mappingFunction, result)));
}
public <U> Task<U> then(@NotNull Function<T, Task<U>> mappingFunction) {
return of(future.thenCompose(result -> {
try {
return mappingFunction.apply(result).future;
} catch (Throwable throwable) {
return failedFuture(throwable);
}
}));
}
public <U> Task<U> thenCompose(@NotNull Function<T, CompletionStage<U>> mappingFunction) {
return of(future.thenCompose(result -> {
try {
return mappingFunction.apply(result);
} catch (Throwable throwable) {
return failedFuture(throwable);
}
}));
}
public Task<T> mapException(@NotNull Function<Throwable, T> mappingFunction) {
return mapException(Throwable.class, mappingFunction);
}
@SuppressWarnings("unchecked")
public <E extends Throwable> Task<T> mapException(@NotNull Class<E> type, @NotNull Function<E, T> 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 <I, O> CompletableFuture<O> map(Function<I, O> function, I result) {
try {
O mappedResult = function.apply(result);
return CompletableFuture.completedFuture(mappedResult);
} catch (Throwable throwable) {
return failedFuture(throwable);
}
}
}

View File

@ -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<BukkitDiscordSRV> implements Listener, PunishmentModule.Bans {
@ -69,7 +69,7 @@ public class PaperBanModule extends AbstractModule<BukkitDiscordSRV> 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<BukkitDiscordSRV> 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<BukkitDiscordSRV> implements
}
@Override
public CompletableFuture<Void> addBan(
public Task<Void> addBan(
@NotNull UUID playerUUID,
@Nullable Instant until,
@Nullable MinecraftComponent reason,
@ -100,14 +100,14 @@ public class PaperBanModule extends AbstractModule<BukkitDiscordSRV> 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<Void> removeBan(@NotNull UUID playerUUID) {
public Task<Void> 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);
}
}

View File

@ -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<List<String>> getRootCommands(CommandSender commandSender) {
public Task<List<String>> getRootCommands(CommandSender commandSender) {
return discordSRV.scheduler().supplyOnMainThread(
commandSender,
() -> new ArrayList<>(discordSRV.server().getCommandMap().getKnownCommands().keySet())

View File

@ -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<BukkitDiscordSRV> implements Listener, PunishmentModule.Bans {
@ -72,7 +72,7 @@ public class BukkitBanModule extends AbstractModule<BukkitDiscordSRV> 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<BukkitDiscordSRV> implements
}
@Override
public CompletableFuture<Void> addBan(
public Task<Void> addBan(
@NotNull UUID playerUUID,
@Nullable Instant until,
@Nullable MinecraftComponent reason,
@ -107,7 +107,7 @@ public class BukkitBanModule extends AbstractModule<BukkitDiscordSRV> implements
}
@Override
public CompletableFuture<Void> removeBan(@NotNull UUID playerUUID) {
public Task<Void> removeBan(@NotNull UUID playerUUID) {
BanList banList = discordSRV.server().getBanList(BanList.Type.NAME);
return discordSRV.playerProvider().lookupOfflinePlayer(playerUUID).thenApply(offlinePlayer -> {
banList.pardon(offlinePlayer.username());

View File

@ -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<List<String>> getRootCommands(CommandSender commandSender) {
return CompletableFuture.completedFuture(Collections.emptyList());
public Task<List<String>> getRootCommands(CommandSender commandSender) {
return Task.completed(Collections.emptyList());
}
@Override
public CompletableFuture<List<String>> suggestCommands(List<String> parts) {
public Task<List<String>> suggestCommands(List<String> 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<String> suggestions = new ArrayList<>(commands.size());

View File

@ -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<Void> kick(Component component) {
public Task<Void> kick(Component component) {
String legacy = BukkitComponentSerializer.legacy().serialize(component);
return discordSRV.scheduler().executeOnMainThread(player, () -> player.kickPlayer(legacy));
}

View File

@ -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<Void> executeOnMainThread(CommandSender sender, Runnable runnable) {
return CompletableFuture.runAsync(runnable, task -> runOnMainThread(sender, task));
public Task<Void> executeOnMainThread(CommandSender sender, CheckedRunnable runnable) {
return TaskUtil.runAsync(runnable, task -> runOnMainThread(sender, task));
}
@CheckReturnValue
public <T> CompletableFuture<T> supplyOnMainThread(CommandSender sender, CheckedSupplier<T> supplier) {
return CompletableFutureUtil.supplyAsync(supplier, task -> runOnMainThread(sender, task));
public <T> Task<T> supplyOnMainThread(CommandSender sender, CheckedSupplier<T> supplier) {
return TaskUtil.supplyAsync(supplier, task -> runOnMainThread(sender, task));
}
}

View File

@ -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<Void> kick(Component component) {
public Task<Void> kick(Component component) {
if (PaperComponentHandle.IS_AVAILABLE) {
return discordSRV.scheduler().executeOnMainThread(player, () -> PaperPlayerUtil.kick(player, ComponentUtil.toAPI(component)));
}

View File

@ -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<Void> kick(Component component) {
public Task<Void> kick(Component component) {
player.disconnect(BungeeComponentSerializer.get().serialize(component));
return CompletableFuture.completedFuture(null);
return Task.completed(null);
}
@Override

View File

@ -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<Void> runServerStarted() {
public final Task<Void> 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<Void> runDisable() {
public final Task<Void> runDisable() {
return scheduler().execute(this::disable);
}

View File

@ -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<ReloadResult> runReload(Set<ReloadFlag> flags);
CompletableFuture<Void> runDisable();
Task<Void> runDisable();
boolean isServerStarted();
ZonedDateTime getInitializeTime();

View File

@ -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,

View File

@ -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<Void> kick(Component component);
Task<Void> kick(Component component);
void addChatSuggestions(Collection<String> suggestions);
void removeChatSuggestions(Collection<String> suggestions);

View File

@ -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<SyncSummary<C>> resync(ISyncCause cause, C config, Someone someone) {
protected Task<SyncSummary<C>> 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);

View File

@ -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<UUID> playerUUIDFuture = CommandUtil.lookupPlayer(discordSRV, logger, execution, false, playerArgument, null);
CompletableFuture<Long> userIdFuture = CommandUtil.lookupUser(discordSRV, logger, execution, false, userArgument, null);
Task<UUID> playerUUIDFuture = CommandUtil.lookupPlayer(discordSRV, logger, execution, false, playerArgument, null);
Task<Long> userIdFuture = CommandUtil.lookupUser(discordSRV, logger, execution, false, userArgument, null);
playerUUIDFuture.whenComplete((playerUUID, __) -> userIdFuture.whenComplete((userId, ___) -> {
if (playerUUID == null) {

View File

@ -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<Task<? extends SyncSummary<?>>> futures = resyncOnlinePlayers(module);
Task.allOfGeneric(futures).thenCompose(result -> {
Task.allOfGeneric(futures).then(result -> {
List<Task<?>> results = new ArrayList<>();
for (SyncSummary<?> summary : result) {
results.add(summary.resultFuture());
@ -153,7 +152,7 @@ public class ResyncCommand extends CombinedCommand {
int total = 0;
List<ISyncResult> results = new ArrayList<>();
for (CompletableFuture<? extends SyncSummary<?>> future : futures) {
for (Task<? extends SyncSummary<?>> future : futures) {
SyncSummary<?> summary = future.join();
ISyncResult allFailResult = summary.allFailReason();
if (allFailResult != null) {

View File

@ -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<List<String>> suggestCommands(List<String> parts);
Task<List<String>> suggestCommands(List<String> parts);
List<String> getAliases(String command);
boolean isSameCommand(String command1, String command2);

View File

@ -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<DiscordMessageChannel> channels = new HashSet<>();
CompletableFuture<List<DiscordGuildMessageChannel>> future = null;
Task<List<DiscordGuildMessageChannel>> future = null;
try {
long id = Long.parseUnsignedLong(channel);

View File

@ -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<Void> downloadRelocateAndLoad() {
public Task<Void> downloadRelocateAndLoad() {
return downloadRelocateAndLoad(classpathAppender);
}
private CompletableFuture<Void> downloadRelocateAndLoad(ClasspathAppender appender) {
return dependencyManager.downloadAll(executor, REPOSITORIES)
private Task<Void> downloadRelocateAndLoad(ClasspathAppender appender) {
return Task.of(dependencyManager.downloadAll(executor, REPOSITORIES))
.thenCompose(v -> dependencyManager.relocateAll(executor))
.thenCompose(v -> dependencyManager.loadAll(executor, appender));
}

View File

@ -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<PermissionModule.PrefixAndSuffix, CompletableFuture<String>> function
Function<PermissionModule.PrefixAndSuffix, Task<String>> function
) {
PermissionModule.PrefixAndSuffix permission = discordSRV.getModule(PermissionModule.PrefixAndSuffix.class);
if (permission == null) {

View File

@ -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<Void> executeOnMainThreadLaterInTicks(@NotNull CheckedRunnable task, int ticks) {
return CompletableFutureUtil.runAsync(task, t -> runOnMainThreadLaterInTicks(t, ticks));
default @NotNull Task<Void> executeOnMainThreadLaterInTicks(@NotNull CheckedRunnable task, int ticks) {
return TaskUtil.runAsync(task, t -> runOnMainThreadLaterInTicks(t, ticks));
}
@NotNull
default <T> CompletableFuture<T> supplyOnMainThreadLaterInTicks(@NotNull CheckedSupplier<T> task, int ticks) {
return CompletableFutureUtil.supplyAsync(task, t -> runOnMainThreadLaterInTicks(t, ticks));
default @NotNull <T> Task<T> supplyOnMainThreadLaterInTicks(@NotNull CheckedSupplier<T> task, int ticks) {
return TaskUtil.supplyAsync(task, t -> runOnMainThreadLaterInTicks(t, ticks));
}
/**

View File

@ -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<WebhookClient<Message>> queryWebhookClient(long channelId) {
return cachedClients.get(channelId);
public Task<WebhookClient<Message>> queryWebhookClient(long channelId) {
return Task.of(cachedClients.get(channelId));
}
public AsyncLoadingCache<Long, WebhookClient<Message>> getCachedClients() {
return cachedClients;
}
public <T> CompletableFuture<T> mapExceptions(CheckedSupplier<CompletableFuture<T>> futureSupplier) {
public <T> Task<T> toTask(Supplier<RestAction<T>> jdaRestActionSupplier) {
try {
return mapExceptions(futureSupplier.get());
} catch (Throwable t) {
return CompletableFutureUtil.failed(t);
}
}
public <T> CompletableFuture<T> mapExceptions(CompletableFuture<T> 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 <T> Task<T> mapExceptions(CheckedSupplier<Task<T>> futureSupplier) {
try {
return mapExceptions(futureSupplier.get());
RestAction<T> restAction = jdaRestActionSupplier.get();
return toTask(restAction);
} catch (Throwable t) {
return Task.failed(t);
}
}
public <T> Task<T> mapExceptions(Task<T> future) {
return future
.mapException(ErrorResponseException.class, t -> {
int code = t.getErrorCode();
ErrorResponse errorResponse = t.getErrorResponse();
throw new RestErrorResponseException(code, errorResponse.getMeaning(), t);
public <T> Task<T> toTask(RestAction<T> 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<WebhookClient<Message>> asyncLoad(@NotNull Long channelId, @NotNull Executor executor) {
JDA jda = discordSRV.jda();
if (jda == null) {
return CompletableFutureUtil.failed(new NotReadyException());
CompletableFuture<WebhookClient<Message>> 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<WebhookClient<Message>> future = new CompletableFuture<>();
future.completeExceptionally(new IllegalArgumentException("Channel could not be found"));
return future;
}
return webhookContainer.retrieveWebhooks().submit().thenApply(webhooks -> {

View File

@ -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

View File

@ -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<PC extends IPostContainer> imp
}
@Override
public CompletableFuture<Void> delete() {
return discordSRV.discordAPI().mapExceptions(() -> channel.delete().submit());
public Task<Void> delete() {
return discordSRV.discordAPI().toTask(channel::delete);
}
@Override
@ -84,40 +84,35 @@ public abstract class AbstractDiscordForumChannel<PC extends IPostContainer> imp
}
@Override
public CompletableFuture<List<DiscordThreadChannel>> retrieveArchivedPrivateThreads() {
public Task<List<DiscordThreadChannel>> retrieveArchivedPrivateThreads() {
return threads(IThreadContainer::retrieveArchivedPrivateThreadChannels);
}
@Override
public CompletableFuture<List<DiscordThreadChannel>> retrieveArchivedJoinedPrivateThreads() {
public Task<List<DiscordThreadChannel>> retrieveArchivedJoinedPrivateThreads() {
return threads(IThreadContainer::retrieveArchivedPrivateJoinedThreadChannels);
}
@Override
public CompletableFuture<List<DiscordThreadChannel>> retrieveArchivedPublicThreads() {
public Task<List<DiscordThreadChannel>> retrieveArchivedPublicThreads() {
return threads(IThreadContainer::retrieveArchivedPublicThreadChannels);
}
@SuppressWarnings("CodeBlock2Expr")
private CompletableFuture<List<DiscordThreadChannel>> threads(
Function<IThreadContainer, ThreadChannelPaginationAction> 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<List<DiscordThreadChannel>> threads(Function<IThreadContainer, ThreadChannelPaginationAction> action) {
return discordSRV.discordAPI().toTask(() -> action.apply(channel))
.thenApply(channels -> channels.stream()
.map(channel -> discordSRV.discordAPI().getThreadChannel(channel))
.collect(Collectors.toList())
);
}
@Override
public CompletableFuture<DiscordThreadChannel> createThread(String name, boolean privateThread) {
public Task<DiscordThreadChannel> createThread(String name, boolean privateThread) {
throw new IllegalStateException("Cannot create Threads in Forums without a message");
}
@Override
public CompletableFuture<DiscordThreadChannel> createThread(String name, long messageId) {
public Task<DiscordThreadChannel> createThread(String name, long messageId) {
return thread(channel -> channel.createThreadChannel(name, messageId), result -> result);
}
@ -126,16 +121,12 @@ public abstract class AbstractDiscordForumChannel<PC extends IPostContainer> imp
return channel;
}
@SuppressWarnings("CodeBlock2Expr")
protected <R> CompletableFuture<DiscordThreadChannel> thread(
protected <R> Task<DiscordThreadChannel> thread(
Function<PC, AbstractThreadCreateAction<R, ?>> action,
Function<R, ThreadChannel> 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)));
});
}
}

View File

@ -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<T extends GuildMessageChannel>
extends AbstractDiscordMessageChannel<T>
implements DiscordGuildMessageChannel {
@ -52,7 +51,7 @@ public abstract class AbstractDiscordGuildMessageChannel<T extends GuildMessageC
this.guild = discordSRV.discordAPI().getGuild(channel.getGuild());
}
public CompletableFuture<WebhookClient<Message>> queryWebhookClient() {
public Task<WebhookClient<Message>> queryWebhookClient() {
return discordSRV.discordAPI().queryWebhookClient(getId());
}
@ -77,7 +76,7 @@ public abstract class AbstractDiscordGuildMessageChannel<T extends GuildMessageC
}
@Override
public @NotNull CompletableFuture<ReceivedDiscordMessage> sendMessage(@NotNull SendableDiscordMessage message) {
public @NotNull Task<ReceivedDiscordMessage> sendMessage(@NotNull SendableDiscordMessage message) {
return sendInternal(message);
}
@ -86,10 +85,10 @@ public abstract class AbstractDiscordGuildMessageChannel<T extends GuildMessageC
}
@SuppressWarnings("unchecked") // Generics
private <R extends MessageCreateRequest<? extends MessageCreateRequest<?>> & RestAction<Message>> CompletableFuture<ReceivedDiscordMessage> sendInternal(SendableDiscordMessage message) {
private <R extends MessageCreateRequest<? extends MessageCreateRequest<?>> & RestAction<Message>> Task<ReceivedDiscordMessage> sendInternal(SendableDiscordMessage message) {
MessageCreateData createData = SendableDiscordMessageUtil.toJDASend(message);
CompletableFuture<R> createRequest;
Task<R> createRequest;
if (message.isWebhookMessage()) {
createRequest = queryWebhookClient()
.thenApply(client -> (R) mapAction(client.sendMessage(createData))
@ -103,7 +102,7 @@ public abstract class AbstractDiscordGuildMessageChannel<T extends GuildMessageC
if (referencedMessageId != null) {
action = action.setMessageReference(referencedMessageId);
}
createRequest = CompletableFuture.completedFuture((R) action);
createRequest = Task.completed((R) action);
}
return createRequest
@ -112,7 +111,7 @@ public abstract class AbstractDiscordGuildMessageChannel<T extends GuildMessageC
}
@Override
public @NotNull CompletableFuture<ReceivedDiscordMessage> editMessageById(
public @NotNull Task<ReceivedDiscordMessage> editMessageById(
long id,
@NotNull SendableDiscordMessage message
) {
@ -124,21 +123,21 @@ public abstract class AbstractDiscordGuildMessageChannel<T extends GuildMessageC
}
@SuppressWarnings("unchecked") // Generics
private <R extends MessageEditRequest<? extends MessageEditRequest<?>> & RestAction<Message>> CompletableFuture<ReceivedDiscordMessage> editInternal(
private <R extends MessageEditRequest<? extends MessageEditRequest<?>> & RestAction<Message>> Task<ReceivedDiscordMessage> editInternal(
long id,
SendableDiscordMessage message
) {
MessageEditData editData = SendableDiscordMessageUtil.toJDAEdit(message);
CompletableFuture<R> editRequest;
Task<R> 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<T extends GuildMessageC
}
@Override
public CompletableFuture<Void> deleteMessageById(long id, boolean webhookMessage) {
CompletableFuture<Void> future;
public Task<Void> deleteMessageById(long id, boolean webhookMessage) {
Task<Void> 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<Void> delete() {
return discordSRV.discordAPI().mapExceptions(() -> channel.delete().submit());
public Task<Void> delete() {
return discordSRV.discordAPI().toTask(channel::delete);
}
}

View File

@ -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<T extends Guild
}
@Override
public CompletableFuture<List<DiscordThreadChannel>> retrieveArchivedPrivateThreads() {
public Task<List<DiscordThreadChannel>> retrieveArchivedPrivateThreads() {
return threads(IThreadContainer::retrieveArchivedPrivateThreadChannels);
}
@Override
public CompletableFuture<List<DiscordThreadChannel>> retrieveArchivedJoinedPrivateThreads() {
public Task<List<DiscordThreadChannel>> retrieveArchivedJoinedPrivateThreads() {
return threads(IThreadContainer::retrieveArchivedPrivateJoinedThreadChannels);
}
@Override
public CompletableFuture<List<DiscordThreadChannel>> retrieveArchivedPublicThreads() {
public Task<List<DiscordThreadChannel>> retrieveArchivedPublicThreads() {
return threads(IThreadContainer::retrieveArchivedPublicThreadChannels);
}
@SuppressWarnings("CodeBlock2Expr")
private CompletableFuture<List<DiscordThreadChannel>> threads(
Function<IThreadContainer, ThreadChannelPaginationAction> 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<List<DiscordThreadChannel>> threads(Function<IThreadContainer, ThreadChannelPaginationAction> action) {
return discordSRV.discordAPI().toTask(() -> action.apply(channel))
.thenApply(channels -> channels.stream()
.map(channel -> discordSRV.discordAPI().getThreadChannel(channel))
.collect(Collectors.toList())
);
}
@Override
public CompletableFuture<DiscordThreadChannel> createThread(String name, boolean privateThread) {
public Task<DiscordThreadChannel> createThread(String name, boolean privateThread) {
return thread(channel -> channel.createThreadChannel(name, privateThread));
}
@Override
public CompletableFuture<DiscordThreadChannel> createThread(String name, long messageId) {
public Task<DiscordThreadChannel> createThread(String name, long messageId) {
return thread(channel -> channel.createThreadChannel(name, messageId));
}
@SuppressWarnings("CodeBlock2Expr")
private CompletableFuture<DiscordThreadChannel> thread(Function<T, ThreadChannelAction> action) {
return discordSRV.discordAPI().mapExceptions(() -> {
return action.apply(channel)
.submit()
private Task<DiscordThreadChannel> thread(Function<T, ThreadChannelAction> action) {
return discordSRV.discordAPI().toTask(() -> action.apply(channel))
.thenApply(channel -> discordSRV.discordAPI().getThreadChannel(channel));
});
}
@Override

View File

@ -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<PrivateChannel> implements DiscordDMChannel {
@ -49,7 +49,7 @@ public class DiscordDMChannelImpl extends AbstractDiscordMessageChannel<PrivateC
}
@Override
public @NotNull CompletableFuture<ReceivedDiscordMessage> sendMessage(@NotNull SendableDiscordMessage message) {
public @NotNull Task<ReceivedDiscordMessage> 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<PrivateC
action = action.setMessageReference(referencedMessageId);
}
CompletableFuture<ReceivedDiscordMessage> future = action.submit()
return discordSRV.discordAPI().toTask(action)
.thenApply(msg -> ReceivedDiscordMessageImpl.fromJDA(discordSRV, msg));
return discordSRV.discordAPI().mapExceptions(future);
}
@Override
public CompletableFuture<Void> deleteMessageById(long id, boolean webhookMessage) {
public Task<Void> 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<ReceivedDiscordMessage> editMessageById(
public @NotNull Task<ReceivedDiscordMessage> editMessageById(
long id,
@NotNull SendableDiscordMessage message
) {
@ -83,12 +83,9 @@ public class DiscordDMChannelImpl extends AbstractDiscordMessageChannel<PrivateC
throw new IllegalArgumentException("Cannot send webhook messages to DMChannels");
}
CompletableFuture<ReceivedDiscordMessage> 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

View File

@ -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<ForumChannel> implements DiscordForumChannel {
public DiscordForumChannelImpl(DiscordSRV discordSRV, ForumChannel channel) {
@ -46,7 +45,7 @@ public class DiscordForumChannelImpl extends AbstractDiscordForumChannel<ForumCh
}
@Override
public CompletableFuture<DiscordThreadChannel> createPost(String name, SendableDiscordMessage message) {
public Task<DiscordThreadChannel> createPost(String name, SendableDiscordMessage message) {
return thread(
channel -> channel.createForumPost(name, SendableDiscordMessageUtil.toJDASend(message)),
ForumPost::getThreadChannel

View File

@ -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<MediaChannel> implements DiscordMediaChannel {
public DiscordMediaChannelImpl(DiscordSRV discordSRV, MediaChannel channel) {
@ -46,7 +45,7 @@ public class DiscordMediaChannelImpl extends AbstractDiscordForumChannel<MediaCh
}
@Override
public CompletableFuture<DiscordThreadChannel> createPost(String name, SendableDiscordMessage message) {
public Task<DiscordThreadChannel> createPost(String name, SendableDiscordMessage message) {
return thread(
channel -> channel.createForumPost(name, SendableDiscordMessageUtil.toJDASend(message)),
ForumPost::getThreadChannel

View File

@ -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<ThreadChannel> implements DiscordThreadChannel {
private final DiscordThreadContainer threadContainer;
@ -51,7 +50,7 @@ public class DiscordThreadChannelImpl extends AbstractDiscordGuildMessageChannel
}
@Override
public CompletableFuture<WebhookClient<Message>> queryWebhookClient() {
public Task<WebhookClient<Message>> queryWebhookClient() {
return discordSRV.discordAPI()
.queryWebhookClient(getParentChannel().getId());
}

View File

@ -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<ReceivedDiscordMessage> editOriginal(SendableDiscordMessage message) {
return hook.editOriginal(SendableDiscordMessageUtil.toJDAEdit(message)).submit()
public Task<ReceivedDiscordMessage> editOriginal(SendableDiscordMessage message) {
return discordSRV.discordAPI().toTask(() -> hook.editOriginal(SendableDiscordMessageUtil.toJDAEdit(message)))
.thenApply(msg -> ReceivedDiscordMessageImpl.fromJDA(discordSRV, msg));
}
@Override
public CompletableFuture<ReceivedDiscordMessage> sendMessage(SendableDiscordMessage message, boolean ephemeral) {
return hook.sendMessage(SendableDiscordMessageUtil.toJDASend(message)).setEphemeral(ephemeral).submit()
public Task<ReceivedDiscordMessage> sendMessage(SendableDiscordMessage message, boolean ephemeral) {
return discordSRV.discordAPI().toTask(() -> hook.sendMessage(SendableDiscordMessageUtil.toJDASend(message)).setEphemeral(ephemeral))
.thenApply(msg -> ReceivedDiscordMessageImpl.fromJDA(discordSRV, msg));
}
}

View File

@ -63,10 +63,8 @@ public class DiscordGuildImpl implements DiscordGuild {
@Override
public @NotNull Task<DiscordGuildMember> 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

View File

@ -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<Void> addRole(@NotNull DiscordRole role) {
return discordSRV.discordAPI().mapExceptions(() ->
guild.asJDA().addRoleToMember(member, role.asJDA()).submit()
);
public Task<Void> addRole(@NotNull DiscordRole role) {
return discordSRV.discordAPI().toTask(() -> guild.asJDA().addRoleToMember(member, role.asJDA()));
}
@Override
public CompletableFuture<Void> removeRole(@NotNull DiscordRole role) {
return discordSRV.discordAPI().mapExceptions(() ->
guild.asJDA().removeRoleFromMember(member, role.asJDA()).submit()
);
public Task<Void> removeRole(@NotNull DiscordRole role) {
return discordSRV.discordAPI().toTask(() -> guild.asJDA().removeRoleFromMember(member, role.asJDA()));
}
@Override

View File

@ -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<Void> deleteAll() {
List<CompletableFuture<Void>> futures = new ArrayList<>(messages.size());
public @NotNull Task<Void> deleteAll() {
List<Task<Void>> 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<ReceivedDiscordMessageCluster> editAll(SendableDiscordMessage newMessage) {
List<CompletableFuture<ReceivedDiscordMessage>> futures = new ArrayList<>(messages.size());
public @NotNull Task<ReceivedDiscordMessageCluster> editAll(SendableDiscordMessage newMessage) {
List<Task<ReceivedDiscordMessage>> 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);
}
}

View File

@ -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<Void> delete() {
public @NotNull Task<Void> 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<ReceivedDiscordMessage> edit(
public Task<ReceivedDiscordMessage> 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<ReceivedDiscordMessage> reply(@NotNull SendableDiscordMessage message) {
public Task<ReceivedDiscordMessage> 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));

View File

@ -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<CompletableFuture<DiscordUser>> botOwnerRequest = new AtomicReference<>();
private final AtomicReference<Task<DiscordUser>> 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<DiscordUser> botOwnerConsumer) {
CompletableFuture<DiscordUser> request = botOwnerRequest.get();
Task<DiscordUser> request = botOwnerRequest.get();
if (request != null && !botOwnerTimeout.checkAndUpdate()) {
request.whenComplete((user, t) -> botOwnerConsumer.accept(t != null ? null : user));
return;
}
CompletableFuture<DiscordUser> future = instance.retrieveApplicationInfo()
.timeout(10, TimeUnit.SECONDS)
.map(applicationInfo -> (DiscordUser) api().getUser(applicationInfo.getOwner()))
.submit();
Task<DiscordUser> 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<Long> restPingFuture = instance.getRestPing().timeout(5, TimeUnit.SECONDS).submit();
Task<Long> restPingFuture = discordSRV.discordAPI().toTask(instance.getRestPing().timeout(5, TimeUnit.SECONDS));
builder.append("\nGateway Ping: ").append(instance.getGatewayPing()).append("ms");
String restPing;

View File

@ -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<DiscordInteractionHook> 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<DiscordInteractionHook> 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<DiscordInteractionHook> deferReply(boolean ephemeral) {
return discordSRV.discordAPI().mapExceptions(
() -> jdaEvent.deferReply(ephemeral).submit()
.thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih))
);
public Task<DiscordInteractionHook> deferReply(boolean ephemeral) {
return discordSRV.discordAPI().toTask(() -> jdaEvent.deferReply(ephemeral))
.thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih));
}
}

View File

@ -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<DiscordInteractionHook> 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<DiscordInteractionHook> 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<DiscordInteractionHook> deferReply(boolean ephemeral) {
return discordSRV.discordAPI().mapExceptions(
() -> jdaEvent.deferReply(ephemeral).submit()
.thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih))
);
public Task<DiscordInteractionHook> deferReply(boolean ephemeral) {
return discordSRV.discordAPI().toTask(() -> jdaEvent.deferReply(ephemeral))
.thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih));
}
}

View File

@ -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<DiscordInteractionHook> 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<DiscordInteractionHook> 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<DiscordInteractionHook> deferReply(boolean ephemeral) {
return discordSRV.discordAPI().mapExceptions(
() -> jdaEvent.deferReply(ephemeral).submit()
.thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih))
);
public Task<DiscordInteractionHook> deferReply(boolean ephemeral) {
return discordSRV.discordAPI().toTask(() -> jdaEvent.deferReply(ephemeral))
.thenApply(ih -> new DiscordInteractionHookImpl(discordSRV, ih));
}
}

View File

@ -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<DiscordSRV, BanSyncConfig,
.applyPlaceholderService()
.build();
return bans.addBan(playerUUID, null, reason, punisher)
.thenCompose(v -> {
.then(v -> {
IPlayer player = discordSRV.playerProvider().player(playerUUID);
if (player == null) {
return CompletableFuture.completedFuture(null);
return Task.completed(null);
}
MinecraftComponent kickMessage = discordSRV.componentFactory()

View File

@ -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<LogEntry> messageQueue;
private Deque<Pair<SendableDiscordMessage, Boolean>> sendQueue;
private boolean sentFirstBatch = false;
@ -545,51 +546,51 @@ public class SingleConsoleHandler {
return " ";
}
private CompletableFuture<DiscordGuildMessageChannel> rotateToLatestChannel() {
private Task<DiscordGuildMessageChannel> 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<Long> channelsToDelete = null;
synchronized (temporaryData) {
Map<String, List<Long>> rotationIds = temporaryData.consoleThreadRotationIds;
List<Long> 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<Long> channelsToDelete = null;
synchronized (temporaryData) {
Map<String, List<Long>> rotationIds = temporaryData.consoleThreadRotationIds;
List<Long> 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);
}

View File

@ -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<DiscordSRV, GroupSyncCon
future = permissionProvider.hasGroup(playerUUID, config.groupName, false);
}
return future.exceptionally(t -> {
return future.mapException(t -> {
throw new SyncFail(GroupSyncResult.PERMISSION_BACKEND_FAILED, t);
});
}
@ -249,9 +247,9 @@ public class GroupSyncModule extends AbstractSyncModule<DiscordSRV, GroupSyncCon
}
return role.getGuild().retrieveMemberById(userId)
.thenCompose(member -> 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<DiscordSRV, GroupSyncCon
stateToApply
? addGroup(playerUUID, config).thenApply(v -> 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);

View File

@ -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<T extends DiscordSRV> extends Abstra
return providers;
}
public CompletableFuture<Component> getBlockReason(
public Task<Component> getBlockReason(
RequirementsConfig config,
List<ParsedRequirements> additionalRequirements,
UUID playerUUID,
@ -204,7 +201,7 @@ public abstract class RequiredLinkingModule<T extends DiscordSRV> 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<T extends DiscordSRV> 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<T extends DiscordSRV> extends Abstra
if (additionalRequirements.isEmpty()) {
// No additional requirements: let them through
return CompletableFuture.completedFuture(null);
return Task.completed(null);
}
CompletableFuture<Void> pass = new CompletableFuture<>();
List<CompletableFuture<Boolean>> all = new ArrayList<>();
List<Task<Boolean>> all = new ArrayList<>();
for (ParsedRequirements requirement : additionalRequirements) {
CompletableFuture<Boolean> future = requirement.predicate().apply(Someone.of(playerUUID, userId));
Task<Boolean> 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;

View File

@ -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<T extends DiscordSRV> extends RequiredLinkingModule<T> {
@ -52,7 +52,7 @@ public abstract class ServerRequireLinkingModule<T extends DiscordSRV> extends R
return additionalRequirements;
}
public CompletableFuture<Component> getBlockReason(UUID playerUUID, String playerName, boolean join) {
public Task<Component> getBlockReason(UUID playerUUID, String playerName, boolean join) {
List<ParsedRequirements> additionalRequirements;
synchronized (this.additionalRequirements) {
additionalRequirements = this.additionalRequirements;

View File

@ -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<T> extends AbstractModule<DiscordSRV> {
protected final RequiredLinkingModule<? extends DiscordSRV> module;
@ -40,6 +39,6 @@ public abstract class RequirementType<T> extends AbstractModule<DiscordSRV> {
public abstract String name();
public abstract T parse(String input);
public abstract CompletableFuture<Boolean> isMet(T value, Someone.Resolved someone);
public abstract Task<Boolean> isMet(T value, Someone.Resolved someone);
}

View File

@ -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<Someone.Resolved, CompletableFuture<Boolean>> predicate;
private final Function<Someone.Resolved, Task<Boolean>> predicate;
private final List<Requirement<?>> usedRequirements;
public ParsedRequirements(
String input,
Function<Someone.Resolved, CompletableFuture<Boolean>> predicate,
Function<Someone.Resolved, Task<Boolean>> predicate,
List<Requirement<?>> usedRequirements
) {
this.input = input;
@ -45,7 +45,7 @@ public class ParsedRequirements {
return input;
}
public Function<Someone.Resolved, CompletableFuture<Boolean>> predicate() {
public Function<Someone.Resolved, Task<Boolean>> predicate() {
return predicate;
}

View File

@ -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<Boolean> test(Someone.Resolved someone);
Task<Boolean> test(Someone.Resolved someone);
}
private enum Operator {
@ -220,7 +219,7 @@ public class RequirementParser {
}
private static Func apply(Func one, Func two, BiFunction<Boolean, Boolean, Boolean> 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)));
}
}

View File

@ -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<? extends DiscordSRV> module) {
@ -39,10 +38,10 @@ public class DiscordBoostingRequirementType extends LongRequirementType {
}
@Override
public CompletableFuture<Boolean> isMet(Long value, Someone.Resolved someone) {
public Task<Boolean> 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())

View File

@ -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<? extends DiscordSRV> module) {
@ -40,10 +39,10 @@ public class DiscordRoleRequirementType extends LongRequirementType {
}
@Override
public CompletableFuture<Boolean> isMet(Long value, Someone.Resolved someone) {
public Task<Boolean> 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()

View File

@ -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<Boolean> isMet(Long value, Someone.Resolved someone) {
public Task<Boolean> 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())

View File

@ -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<T> extends RequirementType<MinecraftAuthRequirementType.Reference<T>> {
@ -163,7 +163,7 @@ public class MinecraftAuthRequirementType<T> extends RequirementType<MinecraftAu
}
@Override
public CompletableFuture<Boolean> isMet(Reference<T> atomicReference, Someone.Resolved someone) {
public Task<Boolean> isMet(Reference<T> atomicReference, Someone.Resolved someone) {
String token = module.discordSRV().connectionConfig().minecraftAuth.token;
T value = atomicReference.getValue();
return module.discordSRV().scheduler().supply(() -> {

View File

@ -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<DiscordSRV> {
channelMentions.clear();
}
public CompletableFuture<List<CachedMention>> lookup(
public Task<List<CachedMention>> lookup(
MinecraftToDiscordChatConfig.Mentions config,
Guild guild,
IPlayer player,
String messageContent,
Set<Member> lookedUpMembers
) {
List<CompletableFuture<List<CachedMention>>> futures = new ArrayList<>();
List<Task<List<CachedMention>>> futures = new ArrayList<>();
List<CachedMention> mentions = new ArrayList<>();
if (config.users) {
@ -137,7 +137,7 @@ public class MentionCachingModule extends AbstractModule<DiscordSRV> {
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<DiscordSRV> {
// Member
//
private CompletableFuture<List<CachedMention>> lookupMemberMentions(
private Task<List<CachedMention>> lookupMemberMentions(
Guild guild,
String username,
Set<Member> lookedUpMembers
@ -168,7 +168,7 @@ public class MentionCachingModule extends AbstractModule<DiscordSRV> {
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);
}

View File

@ -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<DiscordSRV> {
@ -104,7 +102,7 @@ public class DiscordMessageMirroringModule extends AbstractModule<DiscordSRV> {
ReceivedDiscordMessage message = event.getMessage();
List<CompletableFuture<MirrorOperation>> futures = new ArrayList<>();
List<Task<MirrorOperation>> futures = new ArrayList<>();
Map<ReceivedDiscordMessage.Attachment, byte[]> attachments = new LinkedHashMap<>();
DiscordMessageEmbed.Builder attachmentEmbed = DiscordMessageEmbed.builder().setDescription("Attachments");
@ -175,10 +173,10 @@ public class DiscordMessageMirroringModule extends AbstractModule<DiscordSRV> {
);
}
CompletableFutureUtil.combine(futures).whenComplete((lists, v) -> {
Task.allOf(futures).whenComplete((lists, v) -> {
Set<Long> channelIdsHandled = new HashSet<>();
for (MirrorOperation operation : lists) {
List<CompletableFuture<MirroredMessage>> mirrorFutures = new ArrayList<>();
List<Task<MirroredMessage>> mirrorFutures = new ArrayList<>();
for (MirrorTarget target : operation.targets) {
DiscordGuildMessageChannel mirrorChannel = target.targetChannel;
@ -231,26 +229,22 @@ public class DiscordMessageMirroringModule extends AbstractModule<DiscordSRV> {
});
}
CompletableFuture<MirroredMessage> future =
Task<MirroredMessage> 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<ReceivedDiscordMessage, MessageReference> references = new LinkedHashMap<>();
@ -262,13 +256,7 @@ public class DiscordMessageMirroringModule extends AbstractModule<DiscordSRV> {
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<DiscordSRV> {
}
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<DiscordSRV> {
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)));
}
}

View File

@ -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<T extends IMessageConfig, E exte
public abstract T mapConfig(BaseChannelConfig channelConfig);
public abstract void postClusterToEventBus(@Nullable GameChannel channel, @NotNull ReceivedDiscordMessageCluster cluster);
public final CompletableFuture<?> process(
public final Task<?> process(
@Nullable E event,
@Nullable DiscordSRVPlayer player,
@Nullable GameChannel channel
@ -98,26 +97,26 @@ public abstract class AbstractGameMessageModule<T extends IMessageConfig, E exte
if (channel == null) {
// Send to all channels due to lack of specified channel
List<CompletableFuture<Void>> futures = new ArrayList<>();
List<Task<Void>> futures = new ArrayList<>();
for (BaseChannelConfig channelConfig : discordSRV.channelConfig().getAllChannels()) {
CompletableFuture<Void> future = forwardToChannel(event, srvPlayer, channelConfig, null);
Task<Void> 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 <CC extends BaseChannelConfig & IChannelConfig> CompletableFuture<Void> forwardToChannel(
protected <CC extends BaseChannelConfig & IChannelConfig> Task<Void> forwardToChannel(
@Nullable E event,
@Nullable IPlayer player,
@NotNull BaseChannelConfig config,
@ -133,22 +132,22 @@ public abstract class AbstractGameMessageModule<T extends IMessageConfig, E exte
return null;
}
return discordSRV.destinations().lookupDestination(channelConfig.destination(), true, true).thenCompose(messageChannels -> {
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<CompletableFuture<ReceivedDiscordMessage>> messageFutures = sendMessageToChannels(
List<Task<ReceivedDiscordMessage>> 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<ReceivedDiscordMessage> messages = new LinkedHashSet<>();
for (CompletableFuture<ReceivedDiscordMessage> future : messageFutures) {
for (Task<ReceivedDiscordMessage> future : messageFutures) {
ReceivedDiscordMessage message = future.join();
if (message != null) {
messages.add(message);
@ -161,19 +160,17 @@ public abstract class AbstractGameMessageModule<T extends IMessageConfig, E exte
}
postClusterToEventBus(channel, new ReceivedDiscordMessageClusterImpl(messages));
}).exceptionally(t -> {
}).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<CompletableFuture<ReceivedDiscordMessage>> sendMessageToChannels(
public List<Task<ReceivedDiscordMessage>> sendMessageToChannels(
T config,
IPlayer player,
SendableDiscordMessage.Builder format,
@ -194,7 +191,7 @@ public abstract class AbstractGameMessageModule<T extends IMessageConfig, E exte
return Collections.emptyList();
}
List<CompletableFuture<ReceivedDiscordMessage>> futures = new ArrayList<>();
List<Task<ReceivedDiscordMessage>> futures = new ArrayList<>();
for (DiscordGuildMessageChannel channel : channels) {
futures.add(sendMessageToChannel(channel, discordMessage));
}
@ -202,7 +199,7 @@ public abstract class AbstractGameMessageModule<T extends IMessageConfig, E exte
return futures;
}
protected final @NotNull CompletableFuture<ReceivedDiscordMessage> sendMessageToChannel(DiscordGuildMessageChannel channel, SendableDiscordMessage message) {
protected final @NotNull Task<ReceivedDiscordMessage> sendMessageToChannel(DiscordGuildMessageChannel channel, SendableDiscordMessage message) {
GuildChannel permissionChannel = (GuildMessageChannel) channel.getAsJDAMessageChannel();
Permission sendPermission;
@ -220,13 +217,12 @@ public abstract class AbstractGameMessageModule<T extends IMessageConfig, E exte
String missingPermissions = DiscordPermissionUtil.missingPermissionsString(permissionChannel, Permission.VIEW_CHANNEL, sendPermission);
if (missingPermissions != null) {
logger().error("Failed to send message to " + describeDestination(channel) + ": " + missingPermissions);
return CompletableFuture.completedFuture(null);
return Task.completed(null);
}
return channel.sendMessage(message).exceptionally(t -> {
return channel.sendMessage(message).whenFailed(t -> {
ErrorCallbackContext.context("Failed to deliver a message to " + describeDestination(channel)).accept(t);
TestHelper.fail(t);
return null;
});
}

View File

@ -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<IMessageConfig, JoinMessageReceiveEvent> {
@ -70,7 +70,7 @@ public class JoinMessageModule extends AbstractGameMessageModule<IMessageConfig,
}
@Override
protected CompletableFuture<Void> forwardToChannel(
protected Task<Void> forwardToChannel(
@Nullable JoinMessageReceiveEvent event,
@Nullable IPlayer player,
@NotNull BaseChannelConfig config,
@ -78,23 +78,22 @@ public class JoinMessageModule extends AbstractGameMessageModule<IMessageConfig,
) {
if (player != null && config.joinMessages().enableSilentPermission && silentJoinPermission.get()) {
logger().info(player.username() + " is joining silently, join message will not be sent");
return CompletableFuture.completedFuture(null);
return Task.completed(null);
}
long delay = config.joinMessages().ignoreIfLeftWithinMS;
if (player != null && delay > 0) {
UUID playerUUID = player.uniqueId();
CompletableFuture<Void> completableFuture = new CompletableFuture<>();
synchronized (delayedTasks) {
CompletableFuture<Void> future = discordSRV.scheduler()
Task<Void> 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);
}

View File

@ -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<LeaveMessageCo
}
@Override
protected CompletableFuture<Void> forwardToChannel(
protected Task<Void> forwardToChannel(
@Nullable LeaveMessageReceiveEvent event,
@Nullable IPlayer player,
@NotNull BaseChannelConfig config,
@ -105,14 +105,14 @@ public class LeaveMessageModule extends AbstractGameMessageModule<LeaveMessageCo
long delta = System.currentTimeMillis() - pair.getKey();
if (delta < config.leaveMessages.ignoreIfJoinedWithinMS) {
logger().info(player.username() + " joined within timeout period, join message will not be sent");
return CompletableFuture.completedFuture(null);
return Task.completed(null);
}
}
}
if (player != null && config.leaveMessages.enableSilentPermission && silentQuitPermission.get()) {
logger().info(player.username() + " is leaving silently, leave message will not be sent");
return CompletableFuture.completedFuture(null);
return Task.completed(null);
}
return super.forwardToChannel(event, player, config, channel);
}

View File

@ -32,6 +32,7 @@ import com.discordsrv.api.events.message.receive.game.GameChatMessageReceiveEven
import com.discordsrv.api.placeholder.format.FormattedText;
import com.discordsrv.api.placeholder.format.PlainPlaceholderFormat;
import com.discordsrv.api.placeholder.util.Placeholders;
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;
@ -46,7 +47,6 @@ import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.concurrent.CompletableFuture;
public class MinecraftToDiscordChatModule extends AbstractGameMessageModule<MinecraftToDiscordChatConfig, GameChatMessageReceiveEvent> {
@ -75,7 +75,7 @@ public class MinecraftToDiscordChatModule extends AbstractGameMessageModule<Mine
}
@Override
public List<CompletableFuture<ReceivedDiscordMessage>> sendMessageToChannels(
public List<Task<ReceivedDiscordMessage>> sendMessageToChannels(
MinecraftToDiscordChatConfig config,
IPlayer player,
SendableDiscordMessage.Builder format,
@ -92,15 +92,15 @@ public class MinecraftToDiscordChatModule extends AbstractGameMessageModule<Mine
}
Component message = ComponentUtil.fromAPI(event.getMessage());
List<CompletableFuture<ReceivedDiscordMessage>> futures = new ArrayList<>();
List<Task<ReceivedDiscordMessage>> futures = new ArrayList<>();
// Format messages per-Guild
for (Map.Entry<DiscordGuild, Set<DiscordGuildMessageChannel>> entry : channelMap.entrySet()) {
Guild guild = entry.getKey().asJDA();
CompletableFuture<SendableDiscordMessage> messageFuture = getMessageForGuild(config, format, guild, message, player, context);
Task<SendableDiscordMessage> 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<Mine
@Override
public void setPlaceholders(MinecraftToDiscordChatConfig config, GameChatMessageReceiveEvent event, SendableDiscordMessage.Formatter formatter) {}
private CompletableFuture<SendableDiscordMessage> getMessageForGuild(
private Task<SendableDiscordMessage> getMessageForGuild(
MinecraftToDiscordChatConfig config,
SendableDiscordMessage.Builder format,
Guild guild,
@ -125,7 +125,7 @@ public class MinecraftToDiscordChatModule extends AbstractGameMessageModule<Mine
.thenApply(mentions -> 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(

View File

@ -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<StartMessageConfig, AbstractGameMessageReceiveEvent> {
@ -55,7 +55,7 @@ public class StartMessageModule extends AbstractGameMessageModule<StartMessageCo
public void postClusterToEventBus(GameChannel channel, @NotNull ReceivedDiscordMessageCluster cluster) {}
@Override
public List<CompletableFuture<ReceivedDiscordMessage>> sendMessageToChannels(
public List<Task<ReceivedDiscordMessage>> sendMessageToChannels(
StartMessageConfig config,
IPlayer player,
SendableDiscordMessage.Builder format,

View File

@ -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<StopMessageConf
public void postClusterToEventBus(GameChannel channel, @NotNull ReceivedDiscordMessageCluster cluster) {}
@Override
public List<CompletableFuture<ReceivedDiscordMessage>> sendMessageToChannels(
public List<Task<ReceivedDiscordMessage>> sendMessageToChannels(
StopMessageConfig config,
IPlayer player,
SendableDiscordMessage.Builder format,

View File

@ -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<String, CompletableFuture<DiscordThreadChannel>> threadActions = new HashMap<>();
private final Map<String, Task<DiscordThreadChannel>> threadActions = new HashMap<>();
public DestinationLookupHelper(DiscordSRV discordSRV) {
this.discordSRV = discordSRV;
this.logger = new NamedLogger(discordSRV, "DESTINATION_LOOKUP");
}
public CompletableFuture<List<DiscordGuildMessageChannel>> lookupDestination(
public Task<List<DiscordGuildMessageChannel>> lookupDestination(
DestinationConfig config,
boolean allowRequests,
boolean logFailures,
Object... threadNameContext
) {
List<CompletableFuture<? extends DiscordGuildMessageChannel>> futures = new ArrayList<>();
List<Task<? extends DiscordGuildMessageChannel>> 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<DiscordThreadChannel> future;
Task<DiscordThreadChannel> future;
synchronized (threadActions) {
CompletableFuture<DiscordThreadChannel> existingFuture = threadActions.get(threadKey);
Task<DiscordThreadChannel> existingFuture = threadActions.get(threadKey);
if (existingFuture != null) {
future = existingFuture;
@ -125,12 +126,12 @@ public class DestinationLookupHelper {
future = unarchiveThread(existingThread, logFailures);
} else {
// Lookup threads
CompletableFuture<List<DiscordThreadChannel>> threads =
Task<List<DiscordThreadChannel>> 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<Long> idsDuplicateCheck = new HashSet<>();
List<DiscordGuildMessageChannel> channels = new ArrayList<>();
for (CompletableFuture<? extends DiscordGuildMessageChannel> future : futures) {
for (Task<? extends DiscordGuildMessageChannel> 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<DiscordThreadChannel> createThread(
private Task<DiscordThreadChannel> 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<DiscordThreadChannel> future;
Task<DiscordThreadChannel> 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<DiscordThreadChannel> unarchiveThread(DiscordThreadChannel channel, boolean logFailures) {
private Task<DiscordThreadChannel> unarchiveThread(DiscordThreadChannel channel, boolean logFailures) {
ThreadChannel jdaChannel = channel.asJDA();
EnumSet<Permission> 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;
});
}
}

View File

@ -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<DiscordSRV> 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<DiscordSRV> 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));
});
}

View File

@ -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<UUID> lookupPlayer(
public static Task<UUID> lookupPlayer(
DiscordSRV discordSRV,
Logger logger,
CommandExecution execution,
@ -77,7 +77,7 @@ public final class CommandUtil {
});
}
public static CompletableFuture<Long> lookupUser(
public static Task<Long> lookupUser(
DiscordSRV discordSRV,
Logger logger,
CommandExecution execution,
@ -94,7 +94,7 @@ public final class CommandUtil {
});
}
public static CompletableFuture<TargetLookupResult> lookupTarget(
public static Task<TargetLookupResult> 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<TargetLookupResult> lookupTarget(
private static Task<TargetLookupResult> 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<User> 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) {

View File

@ -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 <T> CompletableFuture<T> failed(@NotNull Throwable throwable) {
CompletableFuture<T> future = new CompletableFuture<>();
future.completeExceptionally(throwable);
return future;
}
@SuppressWarnings("unchecked")
@NotNull
public static <T> CompletableFuture<List<T>> combine(@NotNull Collection<@NotNull CompletableFuture<T>> futures) {
return combine(futures.toArray(new CompletableFuture[0]));
}
@SuppressWarnings("unchecked")
@NotNull
public static <T> CompletableFuture<List<T>> combineGeneric(@NotNull Collection<@NotNull CompletableFuture<? extends T>> futures) {
return combine(futures.toArray(new CompletableFuture[0]));
}
@SafeVarargs
@NotNull
public static <T> CompletableFuture<List<T>> combine(@NotNull CompletableFuture<@NotNull T>... futures) {
return CompletableFuture.allOf(futures).thenApply(v -> {
List<T> results = new ArrayList<>();
for (CompletableFuture<T> aFuture : futures) {
results.add(aFuture.join());
}
return results;
});
}
public final class TaskUtil {
@NotNull
public static <T> CompletableFuture<T> timeout(@NotNull DiscordSRV discordSRV, @NotNull CompletableFuture<T> future, @NotNull Duration timeout) {
public static <T> Task<T> timeout(@NotNull DiscordSRV discordSRV, @NotNull Task<T> 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 <T> CompletableFuture<T> supplyAsync(@NotNull CheckedSupplier<T> supplier, @NotNull Executor executor) {
public static <T> Task<T> supplyAsync(@NotNull CheckedSupplier<T> supplier, @NotNull Executor executor) {
CompletableFuture<T> 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<Void> runAsync(@NotNull CheckedRunnable runnable, @NotNull Executor executor) {
public static Task<Void> runAsync(@NotNull CheckedRunnable runnable, @NotNull Executor executor) {
return supplyAsync(() -> {
runnable.run();
return null;

View File

@ -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<String> TESTER = Arrays.asList("tester", "plugin2:tester");
@Override
public CompletableFuture<List<String>> suggestCommands(List<String> parts) {
public Task<List<String>> suggestCommands(List<String> parts) {
return null;
}

View File

@ -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<Boolean> isMet(Boolean value, Someone.Resolved someone) {
return CompletableFuture.completedFuture(value);
public Task<Boolean> isMet(Boolean value, Someone.Resolved someone) {
return Task.completed(value);
}
},
new RequirementType<Object>(module) {
@ -87,7 +87,7 @@ public class RequirementTypeParserTest {
}
@Override
public CompletableFuture<Boolean> isMet(Object value, Someone.Resolved someone) {
public Task<Boolean> isMet(Object value, Someone.Resolved someone) {
return null;
}
}

View File

@ -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<Void> kick(Component component) {
public Task<Void> kick(Component component) {
return null;
}

View File

@ -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<List<String>> suggestCommands(List<String> parts) {
public Task<List<String>> suggestCommands(List<String> 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<ParsedCommandNode<ServerCommandSource>> nodes = parse.getContext().getNodes();
@ -67,7 +67,7 @@ public class FabricGameCommandExecutionHelper implements GameCommandExecutionHel
CommandNode<ServerCommandSource> 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<List<String>> getRootCommands() {
return CompletableFuture.completedFuture(
private Task<List<String>> getRootCommands() {
return Task.completed(
dispatcher.getRoot().getChildren()
.stream()
.map(CommandNode::getName)

View File

@ -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> 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<Void> addBan(
public Task<Void> 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<Void> removeBan(@NotNull UUID playerUUID) {
public Task<Void> removeBan(@NotNull UUID playerUUID) {
BannedPlayerList banList = discordSRV.getServer().getPlayerManager().getUserBanList();
Optional<GameProfile> 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);
}
}

View File

@ -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<Void> kick(Component component) {
public Task<Void> kick(Component component) {
player.networkHandler.disconnect(Text.of(component.toString()));
return CompletableFuture.completedFuture(null);
return Task.completed(null);
}
@Override

View File

@ -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<Void> kick(Component component) {
public Task<Void> kick(Component component) {
player.disconnect(component);
return CompletableFuture.completedFuture(null);
return Task.completed(null);
}
@Override