mirror of
https://github.com/DiscordSRV/Ascension.git
synced 2024-11-26 12:35:20 +01:00
Various improvements to 1st party Discord API
This commit is contained in:
parent
0c9732fe11
commit
7457fd90d0
@ -28,6 +28,7 @@ import com.discordsrv.api.discord.api.entity.channel.DiscordDMChannel;
|
||||
import com.discordsrv.api.placeholder.annotation.Placeholder;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@ -64,6 +65,23 @@ public interface DiscordUser extends Snowflake, Mentionable {
|
||||
@NotNull
|
||||
String getDiscriminator();
|
||||
|
||||
/**
|
||||
* Gets the Discord user's avatar url, if an avatar is set.
|
||||
* @return the user's avatar url or {@code null}
|
||||
*/
|
||||
@Placeholder("user_avatar_url")
|
||||
@Nullable
|
||||
String getAvatarUrl();
|
||||
|
||||
/**
|
||||
* Gets the Discord user's avatar that is currently active,
|
||||
* if an avatar isn't set it'll be the url to the default avatar provided by Discord.
|
||||
* @return the user's avatar url
|
||||
*/
|
||||
@Placeholder("user_effective_avatar_url")
|
||||
@NotNull
|
||||
String getEffectiveAvatarUrl();
|
||||
|
||||
/**
|
||||
* Gets the Discord user's username followed by a {@code #} and their discriminator.
|
||||
* @return the Discord user's username & discriminator in the following format {@code Username#1234}
|
||||
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* This file is part of the DiscordSRV API, licensed under the MIT License
|
||||
* Copyright (c) 2016-2021 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.discord.api.entity.channel;
|
||||
|
||||
import com.discordsrv.api.discord.api.entity.guild.DiscordGuild;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface DiscordGuildChannel {
|
||||
|
||||
/**
|
||||
* Gets the name of the channel.
|
||||
* @return the name of the channel
|
||||
*/
|
||||
@NotNull
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Gets the Discord server that this channel is in.
|
||||
* @return the Discord server that contains this channel
|
||||
*/
|
||||
@NotNull
|
||||
DiscordGuild getGuild();
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of the DiscordSRV API, licensed under the MIT License
|
||||
* Copyright (c) 2016-2021 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.discord.api.entity.channel;
|
||||
|
||||
import com.discordsrv.api.discord.api.entity.Mentionable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* A regular Discord channel that messages can be sent to (threads not included).
|
||||
*/
|
||||
public interface DiscordGuildMessageChannel extends DiscordMessageChannel, DiscordGuildChannel, Mentionable {
|
||||
|
||||
@NotNull
|
||||
List<DiscordThreadChannel> getActiveThreads();
|
||||
|
||||
CompletableFuture<List<DiscordThreadChannel>> retrieveArchivedPrivateThreads();
|
||||
CompletableFuture<List<DiscordThreadChannel>> retrieveArchivedJoinedPrivateThreads();
|
||||
CompletableFuture<List<DiscordThreadChannel>> retrieveArchivedPublicThreads();
|
||||
|
||||
CompletableFuture<DiscordThreadChannel> createThread(String name, boolean privateThread);
|
||||
CompletableFuture<DiscordThreadChannel> createThread(String name, long messageId);
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of the DiscordSRV API, licensed under the MIT License
|
||||
* Copyright (c) 2016-2021 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.discord.api.entity.channel;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import net.dv8tion.jda.api.entities.NewsChannel;
|
||||
|
||||
public interface DiscordNewsChannel extends DiscordGuildMessageChannel {
|
||||
|
||||
/**
|
||||
* Returns the JDA representation of this object. This should not be used if it can be avoided.
|
||||
* @return the JDA representation of this object
|
||||
* @see DiscordSRVApi#jda()
|
||||
*/
|
||||
NewsChannel getAsJDANewsChannel();
|
||||
}
|
@ -24,23 +24,13 @@
|
||||
package com.discordsrv.api.discord.api.entity.channel;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import com.discordsrv.api.discord.api.entity.Mentionable;
|
||||
import com.discordsrv.api.discord.api.entity.guild.DiscordGuild;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A Discord text channel.
|
||||
*/
|
||||
public interface DiscordTextChannel extends DiscordMessageChannel, Mentionable {
|
||||
|
||||
/**
|
||||
* Gets the name of the text channel.
|
||||
* @return the name of the channel
|
||||
*/
|
||||
@NotNull
|
||||
String getName();
|
||||
public interface DiscordTextChannel extends DiscordGuildMessageChannel {
|
||||
|
||||
/**
|
||||
* Gets the topic of the text channel.
|
||||
@ -49,13 +39,6 @@ public interface DiscordTextChannel extends DiscordMessageChannel, Mentionable {
|
||||
@Nullable
|
||||
String getTopic();
|
||||
|
||||
/**
|
||||
* Gets the Discord server that this channel is in.
|
||||
* @return the Discord server that contains this channel
|
||||
*/
|
||||
@NotNull
|
||||
DiscordGuild getGuild();
|
||||
|
||||
/**
|
||||
* Returns the JDA representation of this object. This should not be used if it can be avoided.
|
||||
* @return the JDA representation of this object
|
||||
|
@ -67,6 +67,13 @@ public interface DiscordGuildMember extends DiscordUser, Mentionable {
|
||||
return getNickname().orElseGet(this::getUsername);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the avatar url that is active for this user in this server.
|
||||
* @return the user's avatar url in this server
|
||||
*/
|
||||
@Placeholder("user_effective_avatar_url")
|
||||
String getEffectiveServerAvatarUrl();
|
||||
|
||||
/**
|
||||
* Gets the color of this user's highest role that has a color.
|
||||
* @return the color that will be used for this user
|
||||
|
@ -160,6 +160,20 @@ public class SendableDiscordMessageImpl implements SendableDiscordMessage {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Builder convertToNonWebhook() {
|
||||
String webhookUsername = this.webhookUsername;
|
||||
if (webhookUsername == null) {
|
||||
return this;
|
||||
}
|
||||
|
||||
// TODO: configuration?
|
||||
this.content = webhookUsername + " > " + content;
|
||||
this.webhookUsername = null;
|
||||
this.webhookAvatarUrl = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull SendableDiscordMessage build() {
|
||||
return new SendableDiscordMessageImpl(content, embeds, allowedMentions, webhookUsername, webhookAvatarUrl);
|
||||
@ -167,8 +181,7 @@ public class SendableDiscordMessageImpl implements SendableDiscordMessage {
|
||||
|
||||
@Override
|
||||
public Formatter toFormatter() {
|
||||
return new FormatterImpl(
|
||||
clone());
|
||||
return new FormatterImpl(clone());
|
||||
}
|
||||
|
||||
@SuppressWarnings("MethodDoesntCallSuperMethod")
|
||||
@ -218,6 +231,12 @@ public class SendableDiscordMessageImpl implements SendableDiscordMessage {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Formatter convertToNonWebhook() {
|
||||
builder.convertToNonWebhook();
|
||||
return this;
|
||||
}
|
||||
|
||||
private Function<Matcher, Object> wrapFunction(Function<Matcher, Object> function) {
|
||||
return matcher -> {
|
||||
Object result = function.apply(matcher);
|
||||
|
@ -16,15 +16,19 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.module.modules;
|
||||
package com.discordsrv.common.discord.api;
|
||||
|
||||
import com.discordsrv.api.discord.events.DiscordMessageDeleteEvent;
|
||||
import com.discordsrv.api.discord.events.DiscordMessageReceiveEvent;
|
||||
import com.discordsrv.api.discord.events.DiscordMessageUpdateEvent;
|
||||
import com.discordsrv.api.event.bus.Subscribe;
|
||||
import com.discordsrv.api.discord.events.DiscordMessageReceivedEvent;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.discord.api.channel.DiscordMessageChannelImpl;
|
||||
import com.discordsrv.common.discord.api.message.ReceivedDiscordMessageImpl;
|
||||
import com.discordsrv.common.discord.api.entity.channel.DiscordMessageChannelImpl;
|
||||
import com.discordsrv.common.discord.api.entity.message.ReceivedDiscordMessageImpl;
|
||||
import com.discordsrv.common.module.type.AbstractModule;
|
||||
import net.dv8tion.jda.api.events.message.MessageDeleteEvent;
|
||||
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
||||
import net.dv8tion.jda.api.events.message.MessageUpdateEvent;
|
||||
|
||||
public class DiscordAPIEventModule extends AbstractModule {
|
||||
|
||||
@ -33,10 +37,26 @@ public class DiscordAPIEventModule extends AbstractModule {
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onMessageReceivedEvent(MessageReceivedEvent event) {
|
||||
discordSRV.eventBus().publish(new DiscordMessageReceivedEvent(
|
||||
ReceivedDiscordMessageImpl.fromJDA(discordSRV, event.getMessage()),
|
||||
DiscordMessageChannelImpl.get(discordSRV, event.getChannel()))
|
||||
);
|
||||
public void onMessageReceived(MessageReceivedEvent event) {
|
||||
discordSRV.eventBus().publish(new DiscordMessageReceiveEvent(
|
||||
DiscordMessageChannelImpl.get(discordSRV, event.getChannel()),
|
||||
ReceivedDiscordMessageImpl.fromJDA(discordSRV, event.getMessage())
|
||||
));
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onMessageUpdate(MessageUpdateEvent event) {
|
||||
discordSRV.eventBus().publish(new DiscordMessageUpdateEvent(
|
||||
DiscordMessageChannelImpl.get(discordSRV, event.getChannel()),
|
||||
ReceivedDiscordMessageImpl.fromJDA(discordSRV, event.getMessage())
|
||||
));
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onMessageDelete(MessageDeleteEvent event) {
|
||||
discordSRV.eventBus().publish(new DiscordMessageDeleteEvent(
|
||||
DiscordMessageChannelImpl.get(discordSRV, event.getChannel()),
|
||||
event.getMessageIdLong()
|
||||
));
|
||||
}
|
||||
}
|
@ -21,10 +21,12 @@ package com.discordsrv.common.discord.api;
|
||||
import club.minnced.discord.webhook.WebhookClient;
|
||||
import club.minnced.discord.webhook.WebhookClientBuilder;
|
||||
import com.discordsrv.api.discord.api.DiscordAPI;
|
||||
import com.discordsrv.api.discord.api.ThreadChannelLookup;
|
||||
import com.discordsrv.api.discord.api.entity.DiscordUser;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordDMChannel;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordMessageChannel;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordTextChannel;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordThreadChannel;
|
||||
import com.discordsrv.api.discord.api.entity.guild.DiscordGuild;
|
||||
import com.discordsrv.api.discord.api.entity.guild.DiscordRole;
|
||||
import com.discordsrv.api.discord.api.exception.NotReadyException;
|
||||
@ -32,35 +34,43 @@ import com.discordsrv.api.discord.api.exception.RestErrorResponseException;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
|
||||
import com.discordsrv.common.config.main.channels.base.IChannelConfig;
|
||||
import com.discordsrv.common.discord.api.channel.DiscordDMChannelImpl;
|
||||
import com.discordsrv.common.discord.api.channel.DiscordTextChannelImpl;
|
||||
import com.discordsrv.common.discord.api.guild.DiscordGuildImpl;
|
||||
import com.discordsrv.common.discord.api.guild.DiscordRoleImpl;
|
||||
import com.discordsrv.common.config.main.channels.base.ThreadConfig;
|
||||
import com.discordsrv.common.discord.api.entity.DiscordUserImpl;
|
||||
import com.discordsrv.common.discord.api.entity.channel.DiscordDMChannelImpl;
|
||||
import com.discordsrv.common.discord.api.entity.channel.DiscordTextChannelImpl;
|
||||
import com.discordsrv.common.discord.api.entity.guild.DiscordGuildImpl;
|
||||
import com.discordsrv.common.discord.api.entity.guild.DiscordRoleImpl;
|
||||
import com.discordsrv.common.function.CheckedSupplier;
|
||||
import com.github.benmanes.caffeine.cache.AsyncCacheLoader;
|
||||
import com.github.benmanes.caffeine.cache.AsyncLoadingCache;
|
||||
import com.github.benmanes.caffeine.cache.Expiry;
|
||||
import com.github.benmanes.caffeine.cache.RemovalListener;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.ThreadChannel;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.entities.Webhook;
|
||||
import net.dv8tion.jda.api.exceptions.ErrorResponseException;
|
||||
import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
|
||||
import net.dv8tion.jda.api.requests.ErrorResponse;
|
||||
import net.dv8tion.jda.api.requests.GatewayIntent;
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class DiscordAPIImpl implements DiscordAPI {
|
||||
|
||||
private final DiscordSRV discordSRV;
|
||||
|
||||
private final AsyncLoadingCache<Long, WebhookClient> cachedClients;
|
||||
private final List<ThreadChannelLookup> threadLookups = new CopyOnWriteArrayList<>();
|
||||
|
||||
public DiscordAPIImpl(DiscordSRV discordSRV) {
|
||||
this.discordSRV = discordSRV;
|
||||
@ -82,6 +92,226 @@ public class DiscordAPIImpl implements DiscordAPI {
|
||||
return cachedClients;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds active threads based for the provided {@link IChannelConfig}.
|
||||
* @param config the config that specified the threads
|
||||
* @return the list of active threads
|
||||
*/
|
||||
public List<DiscordThreadChannel> findThreads(IChannelConfig config) {
|
||||
List<DiscordThreadChannel> channels = new ArrayList<>();
|
||||
findOrCreateThreads(config, channels::add, null);
|
||||
return channels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds or potentially unarchives or creates threads based on the provided {@link IChannelConfig}.
|
||||
* @param config the config
|
||||
* @param channelConsumer the consumer that will take the channels as they are gathered
|
||||
* @param futures a possibly null list of {@link CompletableFuture} for tasks that need to be completed to get all threads
|
||||
*/
|
||||
public void findOrCreateThreads(
|
||||
IChannelConfig config,
|
||||
Consumer<DiscordThreadChannel> channelConsumer,
|
||||
@Nullable List<CompletableFuture<DiscordThreadChannel>> futures
|
||||
) {
|
||||
List<ThreadConfig> threads = config.threads();
|
||||
if (threads == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ThreadConfig threadConfig : threads) {
|
||||
long channelId = threadConfig.channelId;
|
||||
DiscordTextChannel channel = getTextChannelById(channelId).orElse(null);
|
||||
if (channel == null) {
|
||||
if (channelId > 0) {
|
||||
discordSRV.logger().error("Unable to find channel with ID "
|
||||
+ Long.toUnsignedString(channelId)
|
||||
+ ", unable to forward message to Discord");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if a thread by the same name is still active
|
||||
DiscordThreadChannel thread = findThread(threadConfig, channel.getActiveThreads());
|
||||
if (thread != null) {
|
||||
ThreadChannel jdaChannel = thread.getAsJDAThreadChannel();
|
||||
if (!jdaChannel.isLocked() && !jdaChannel.isArchived()) {
|
||||
channelConsumer.accept(thread);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (futures == null) {
|
||||
// Futures not specified, don't try to unarchive or create threads
|
||||
continue;
|
||||
}
|
||||
|
||||
CompletableFuture<DiscordThreadChannel> future;
|
||||
if (thread != null) {
|
||||
// Unarchive the thread
|
||||
future = new CompletableFuture<>();
|
||||
unarchiveOrCreateThread(threadConfig, channel, thread, future);
|
||||
} else {
|
||||
// Find or create the thread
|
||||
future = findOrCreateThread(threadConfig, channel);
|
||||
}
|
||||
|
||||
futures.add(future.handle((threadChannel, t) -> {
|
||||
if (t instanceof InsufficientPermissionException) {
|
||||
discordSRV.logger().error(
|
||||
"Unable to send message to channel " + channel
|
||||
+ " because the bot is lacking the "
|
||||
+ ((InsufficientPermissionException) t).getPermission().getName()
|
||||
+ " permission");
|
||||
throw new RuntimeException();
|
||||
} else if (t != null) {
|
||||
discordSRV.logger().error("Failed to find thread in channel " + channel, t);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
if (threadChannel != null) {
|
||||
channelConsumer.accept(threadChannel);
|
||||
}
|
||||
return threadChannel;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
private DiscordThreadChannel findThread(ThreadConfig config, List<DiscordThreadChannel> threads) {
|
||||
for (DiscordThreadChannel thread : threads) {
|
||||
if (thread.getName().equals(config.threadName)) {
|
||||
return thread;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private CompletableFuture<DiscordThreadChannel> findOrCreateThread(ThreadConfig config, DiscordTextChannel textChannel) {
|
||||
if (!config.unarchive) {
|
||||
return textChannel.createThread(config.threadName, config.privateThread);
|
||||
}
|
||||
|
||||
CompletableFuture<DiscordThreadChannel> completableFuture = new CompletableFuture<>();
|
||||
lookupThreads(
|
||||
textChannel,
|
||||
config.privateThread,
|
||||
lookup -> findOrCreateThread(config, textChannel, lookup, completableFuture),
|
||||
(thread, throwable) -> {
|
||||
if (throwable != null) {
|
||||
completableFuture.completeExceptionally(throwable);
|
||||
} else {
|
||||
completableFuture.complete(thread);
|
||||
}
|
||||
});
|
||||
return completableFuture;
|
||||
}
|
||||
|
||||
private void findOrCreateThread(
|
||||
ThreadConfig config,
|
||||
DiscordTextChannel textChannel,
|
||||
ThreadChannelLookup lookup,
|
||||
CompletableFuture<DiscordThreadChannel> completableFuture
|
||||
) {
|
||||
completableFuture.whenComplete((threadChannel, throwable) -> {
|
||||
CompletableFuture<DiscordThreadChannel> future = lookup.getChannelFuture();
|
||||
if (throwable != null) {
|
||||
future.completeExceptionally(throwable);
|
||||
} else {
|
||||
future.complete(threadChannel);
|
||||
}
|
||||
});
|
||||
lookup.getFuture().whenComplete((channels, throwable) -> {
|
||||
if (throwable != null) {
|
||||
completableFuture.completeExceptionally(throwable);
|
||||
return;
|
||||
}
|
||||
|
||||
DiscordThreadChannel thread = findThread(config, channels);
|
||||
unarchiveOrCreateThread(config, textChannel, thread, completableFuture);
|
||||
}).exceptionally(t -> {
|
||||
if (t instanceof CompletionException) {
|
||||
completableFuture.completeExceptionally(t.getCause());
|
||||
return null;
|
||||
}
|
||||
completableFuture.completeExceptionally(t);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private void unarchiveOrCreateThread(
|
||||
ThreadConfig config,
|
||||
DiscordTextChannel textChannel,
|
||||
DiscordThreadChannel thread,
|
||||
CompletableFuture<DiscordThreadChannel> future
|
||||
) {
|
||||
if (thread != null) {
|
||||
ThreadChannel channel = thread.getAsJDAThreadChannel();
|
||||
if (channel.isLocked() || channel.isArchived()) {
|
||||
try {
|
||||
channel.getManager().setArchived(false).queue(
|
||||
v -> future.complete(thread),
|
||||
future::completeExceptionally
|
||||
);
|
||||
} catch (Throwable t) {
|
||||
future.completeExceptionally(t);
|
||||
}
|
||||
} else {
|
||||
future.complete(thread);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
textChannel.createThread(config.threadName, config.privateThread).whenComplete(((threadChannel, t) -> {
|
||||
if (t != null) {
|
||||
future.completeExceptionally(t);
|
||||
} else {
|
||||
future.complete(threadChannel);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public void lookupThreads(
|
||||
DiscordTextChannel textChannel,
|
||||
boolean privateThreads,
|
||||
Consumer<ThreadChannelLookup> lookupConsumer,
|
||||
BiConsumer<DiscordThreadChannel, Throwable> channelConsumer
|
||||
) {
|
||||
ThreadChannelLookup lookup;
|
||||
synchronized (threadLookups) {
|
||||
for (ThreadChannelLookup threadLookup : threadLookups) {
|
||||
if (threadLookup.isPrivateThreads() != privateThreads
|
||||
|| threadLookup.getChannelId() != textChannel.getId()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
threadLookup.getChannelFuture().whenComplete(channelConsumer);
|
||||
return;
|
||||
}
|
||||
|
||||
lookup = new ThreadChannelLookup(
|
||||
textChannel.getId(), privateThreads,
|
||||
privateThreads
|
||||
? textChannel.retrieveArchivedPrivateThreads()
|
||||
: textChannel.retrieveArchivedPublicThreads()
|
||||
);
|
||||
threadLookups.add(lookup);
|
||||
}
|
||||
|
||||
lookup.getChannelFuture().whenComplete(channelConsumer);
|
||||
lookupConsumer.accept(lookup);
|
||||
lookup.getFuture().whenComplete((channel, t) -> threadLookups.remove(lookup));
|
||||
}
|
||||
|
||||
public <T> CompletableFuture<T> mapExceptions(CheckedSupplier<CompletableFuture<T>> futureSupplier) {
|
||||
try {
|
||||
return mapExceptions(futureSupplier.get());
|
||||
} catch (Throwable t) {
|
||||
CompletableFuture<T> future = new CompletableFuture<>();
|
||||
future.completeExceptionally(t);
|
||||
return future;
|
||||
}
|
||||
}
|
||||
|
||||
public <T> CompletableFuture<T> mapExceptions(CompletableFuture<T> future) {
|
||||
return future.handle((msg, t) -> {
|
||||
if (t instanceof ErrorResponseException) {
|
||||
@ -172,7 +402,7 @@ public class DiscordAPIImpl implements DiscordAPI {
|
||||
public @NonNull CompletableFuture<WebhookClient> asyncLoad(@NonNull Long channelId, @NonNull Executor executor) {
|
||||
JDA jda = discordSRV.jda().orElse(null);
|
||||
if (jda == null) {
|
||||
return discordSRV.discordAPI().notReady();
|
||||
return notReady();
|
||||
}
|
||||
|
||||
CompletableFuture<WebhookClient> future = new CompletableFuture<>();
|
||||
@ -208,7 +438,7 @@ public class DiscordAPIImpl implements DiscordAPI {
|
||||
}).thenApply(webhook ->
|
||||
WebhookClientBuilder.fromJDA(webhook)
|
||||
.setHttpClient(jda.getHttpClient())
|
||||
.setExecutorService(discordSRV.scheduler().scheduledExecutor())
|
||||
.setExecutorService(discordSRV.scheduler().scheduledExecutorService())
|
||||
.build()
|
||||
);
|
||||
}
|
||||
@ -219,7 +449,7 @@ public class DiscordAPIImpl implements DiscordAPI {
|
||||
private boolean isConfiguredChannel(Long channelId) {
|
||||
for (BaseChannelConfig config : discordSRV.config().channels.values()) {
|
||||
if (config instanceof IChannelConfig
|
||||
&& ((IChannelConfig) config).ids().contains(channelId)) {
|
||||
&& ((IChannelConfig) config).channelIds().contains(channelId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1,127 +0,0 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2021 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.discord.api.channel;
|
||||
|
||||
import club.minnced.discord.webhook.WebhookClient;
|
||||
import club.minnced.discord.webhook.receive.ReadonlyMessage;
|
||||
import club.minnced.discord.webhook.send.WebhookMessage;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordTextChannel;
|
||||
import com.discordsrv.api.discord.api.entity.guild.DiscordGuild;
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessage;
|
||||
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.discord.api.guild.DiscordGuildImpl;
|
||||
import com.discordsrv.common.discord.api.message.ReceivedDiscordMessageImpl;
|
||||
import com.discordsrv.common.discord.api.message.util.SendableDiscordMessageUtil;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.requests.restaction.MessageAction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class DiscordTextChannelImpl extends DiscordMessageChannelImpl implements DiscordTextChannel {
|
||||
|
||||
private final DiscordSRV discordSRV;
|
||||
private final TextChannel textChannel;
|
||||
private final DiscordGuild guild;
|
||||
|
||||
public DiscordTextChannelImpl(DiscordSRV discordSRV, TextChannel textChannel) {
|
||||
this.discordSRV = discordSRV;
|
||||
this.textChannel = textChannel;
|
||||
this.guild = new DiscordGuildImpl(discordSRV, textChannel.getGuild());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return textChannel.getIdLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getName() {
|
||||
return textChannel.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getTopic() {
|
||||
return textChannel.getTopic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull DiscordGuild getGuild() {
|
||||
return guild;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextChannel getAsJDATextChannel() {
|
||||
return textChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<ReceivedDiscordMessage> sendMessage(SendableDiscordMessage message) {
|
||||
return message(message, WebhookClient::send, MessageChannel::sendMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> deleteMessageById(long id) {
|
||||
return null; // TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<ReceivedDiscordMessage> editMessageById(long id, SendableDiscordMessage message) {
|
||||
return message(
|
||||
message,
|
||||
(client, msg) -> client.edit(id, msg),
|
||||
(textChannel, msg) -> textChannel.editMessageById(id, msg)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageChannel getAsJDAMessageChannel() {
|
||||
return textChannel;
|
||||
}
|
||||
|
||||
private CompletableFuture<ReceivedDiscordMessage> message(
|
||||
SendableDiscordMessage message,
|
||||
BiFunction<WebhookClient, WebhookMessage, CompletableFuture<ReadonlyMessage>> webhookFunction,
|
||||
BiFunction<TextChannel, Message, MessageAction> jdaFunction) {
|
||||
CompletableFuture<ReceivedDiscordMessage> future;
|
||||
if (message.isWebhookMessage()) {
|
||||
future = discordSRV.discordAPI().queryWebhookClient(getId())
|
||||
.thenCompose(client -> webhookFunction.apply(
|
||||
client, SendableDiscordMessageUtil.toWebhook(message)))
|
||||
.thenApply(msg -> ReceivedDiscordMessageImpl.fromWebhook(discordSRV, msg));
|
||||
} else {
|
||||
future = jdaFunction
|
||||
.apply(textChannel, SendableDiscordMessageUtil.toJDA(message))
|
||||
.submit()
|
||||
.thenApply(msg -> ReceivedDiscordMessageImpl.fromJDA(discordSRV, msg));
|
||||
}
|
||||
|
||||
return discordSRV.discordAPI().mapExceptions(future);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAsMention() {
|
||||
return textChannel.getAsMention();
|
||||
}
|
||||
}
|
@ -16,15 +16,16 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.discord.api;
|
||||
package com.discordsrv.common.discord.api.entity;
|
||||
|
||||
import com.discordsrv.api.discord.api.entity.DiscordUser;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordDMChannel;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.discord.api.channel.DiscordDMChannelImpl;
|
||||
import com.discordsrv.common.discord.api.entity.channel.DiscordDMChannelImpl;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@ -65,6 +66,16 @@ public class DiscordUserImpl implements DiscordUser {
|
||||
return user.getDiscriminator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getAvatarUrl() {
|
||||
return user.getAvatarUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getEffectiveAvatarUrl() {
|
||||
return user.getEffectiveAvatarUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<DiscordDMChannel> openPrivateChannel() {
|
||||
JDA jda = discordSRV.jda().orElse(null);
|
@ -16,56 +16,42 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.discord.api.channel;
|
||||
package com.discordsrv.common.discord.api.entity.channel;
|
||||
|
||||
import com.discordsrv.api.discord.api.entity.DiscordUser;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordDMChannel;
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessage;
|
||||
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.discord.api.DiscordUserImpl;
|
||||
import com.discordsrv.common.discord.api.message.ReceivedDiscordMessageImpl;
|
||||
import com.discordsrv.common.discord.api.message.util.SendableDiscordMessageUtil;
|
||||
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||
import com.discordsrv.common.discord.api.entity.DiscordUserImpl;
|
||||
import com.discordsrv.common.discord.api.entity.message.ReceivedDiscordMessageImpl;
|
||||
import com.discordsrv.common.discord.api.entity.message.util.SendableDiscordMessageUtil;
|
||||
import net.dv8tion.jda.api.entities.PrivateChannel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class DiscordDMChannelImpl extends DiscordMessageChannelImpl implements DiscordDMChannel {
|
||||
public class DiscordDMChannelImpl extends DiscordMessageChannelImpl<PrivateChannel> implements DiscordDMChannel {
|
||||
|
||||
private final DiscordSRV discordSRV;
|
||||
private final PrivateChannel privateChannel;
|
||||
private final DiscordUser user;
|
||||
|
||||
public DiscordDMChannelImpl(DiscordSRV discordSRV, PrivateChannel privateChannel) {
|
||||
this.discordSRV = discordSRV;
|
||||
this.privateChannel = privateChannel;
|
||||
super(discordSRV, privateChannel);
|
||||
this.user = new DiscordUserImpl(discordSRV, privateChannel.getUser());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return privateChannel.getIdLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiscordUser getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrivateChannel getAsJDAPrivateChannel() {
|
||||
return privateChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<ReceivedDiscordMessage> sendMessage(SendableDiscordMessage message) {
|
||||
public @NotNull CompletableFuture<ReceivedDiscordMessage> sendMessage(@NotNull SendableDiscordMessage message) {
|
||||
if (message.isWebhookMessage()) {
|
||||
throw new IllegalArgumentException("Cannot send webhook messages to DMChannels");
|
||||
}
|
||||
|
||||
CompletableFuture<ReceivedDiscordMessage> future = privateChannel
|
||||
CompletableFuture<ReceivedDiscordMessage> future = channel
|
||||
.sendMessage(SendableDiscordMessageUtil.toJDA(message))
|
||||
.submit()
|
||||
.thenApply(msg -> ReceivedDiscordMessageImpl.fromJDA(discordSRV, msg));
|
||||
@ -74,17 +60,20 @@ public class DiscordDMChannelImpl extends DiscordMessageChannelImpl implements D
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> deleteMessageById(long id) {
|
||||
return discordSRV.discordAPI().mapExceptions(privateChannel.deleteMessageById(id).submit());
|
||||
public CompletableFuture<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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<ReceivedDiscordMessage> editMessageById(long id, SendableDiscordMessage message) {
|
||||
public @NotNull CompletableFuture<ReceivedDiscordMessage> editMessageById(long id, @NotNull SendableDiscordMessage message) {
|
||||
if (message.isWebhookMessage()) {
|
||||
throw new IllegalArgumentException("Cannot send webhook messages to DMChannels");
|
||||
}
|
||||
|
||||
CompletableFuture<ReceivedDiscordMessage> future = privateChannel
|
||||
CompletableFuture<ReceivedDiscordMessage> future = channel
|
||||
.editMessageById(id, SendableDiscordMessageUtil.toJDA(message))
|
||||
.submit()
|
||||
.thenApply(msg -> ReceivedDiscordMessageImpl.fromJDA(discordSRV, msg));
|
||||
@ -93,7 +82,7 @@ public class DiscordDMChannelImpl extends DiscordMessageChannelImpl implements D
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageChannel getAsJDAMessageChannel() {
|
||||
return privateChannel;
|
||||
public PrivateChannel getAsJDAPrivateChannel() {
|
||||
return channel;
|
||||
}
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2021 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.discord.api.entity.channel;
|
||||
|
||||
import club.minnced.discord.webhook.WebhookClient;
|
||||
import club.minnced.discord.webhook.receive.ReadonlyMessage;
|
||||
import club.minnced.discord.webhook.send.WebhookMessage;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordGuildMessageChannel;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordThreadChannel;
|
||||
import com.discordsrv.api.discord.api.entity.guild.DiscordGuild;
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessage;
|
||||
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.discord.api.entity.guild.DiscordGuildImpl;
|
||||
import com.discordsrv.common.discord.api.entity.message.ReceivedDiscordMessageImpl;
|
||||
import com.discordsrv.common.discord.api.entity.message.util.SendableDiscordMessageUtil;
|
||||
import net.dv8tion.jda.api.entities.*;
|
||||
import net.dv8tion.jda.api.requests.restaction.MessageAction;
|
||||
import net.dv8tion.jda.api.requests.restaction.ThreadChannelAction;
|
||||
import net.dv8tion.jda.api.requests.restaction.pagination.ThreadChannelPaginationAction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class DiscordGuildMessageChannelImpl<T extends GuildMessageChannel & IThreadContainer>
|
||||
extends DiscordMessageChannelImpl<T>
|
||||
implements DiscordGuildMessageChannel {
|
||||
|
||||
private final DiscordGuild guild;
|
||||
|
||||
public DiscordGuildMessageChannelImpl(DiscordSRV discordSRV, T channel) {
|
||||
super(discordSRV, channel);
|
||||
this.guild = new DiscordGuildImpl(discordSRV, channel.getGuild());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getName() {
|
||||
return channel.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAsMention() {
|
||||
return channel.getAsMention();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull DiscordGuild getGuild() {
|
||||
return guild;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<DiscordThreadChannel> getActiveThreads() {
|
||||
List<ThreadChannel> threads = channel.getThreadChannels();
|
||||
List<DiscordThreadChannel> threadChannels = new ArrayList<>(threads.size());
|
||||
for (ThreadChannel thread : threads) {
|
||||
threadChannels.add(new DiscordThreadChannelImpl(discordSRV, thread));
|
||||
}
|
||||
return threadChannels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<DiscordThreadChannel>> retrieveArchivedPrivateThreads() {
|
||||
return threads(IThreadContainer::retrieveArchivedPrivateThreadChannels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<DiscordThreadChannel>> retrieveArchivedJoinedPrivateThreads() {
|
||||
return threads(IThreadContainer::retrieveArchivedPrivateJoinedThreadChannels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<DiscordThreadChannel>> retrieveArchivedPublicThreads() {
|
||||
return threads(IThreadContainer::retrieveArchivedPublicThreadChannels);
|
||||
}
|
||||
|
||||
private CompletableFuture<List<DiscordThreadChannel>> threads(Function<IThreadContainer, ThreadChannelPaginationAction> action) {
|
||||
return discordSRV.discordAPI().mapExceptions(() ->
|
||||
action.apply(channel)
|
||||
.submit()
|
||||
.thenApply(channels -> channels.stream()
|
||||
.map(channel -> new DiscordThreadChannelImpl(discordSRV, channel))
|
||||
.collect(Collectors.toList())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<DiscordThreadChannel> createThread(String name, boolean privateThread) {
|
||||
return thread(channel -> channel.createThreadChannel(name, privateThread));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<DiscordThreadChannel> createThread(String name, long messageId) {
|
||||
return thread(channel -> channel.createThreadChannel(name, messageId));
|
||||
}
|
||||
|
||||
private CompletableFuture<DiscordThreadChannel> thread(Function<T, ThreadChannelAction> action) {
|
||||
return discordSRV.discordAPI().mapExceptions(() ->
|
||||
action.apply(channel)
|
||||
.submit()
|
||||
.thenApply(channel -> new DiscordThreadChannelImpl(discordSRV, channel))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<ReceivedDiscordMessage> sendMessage(@NotNull SendableDiscordMessage message) {
|
||||
return message(message, WebhookClient::send, MessageChannel::sendMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<ReceivedDiscordMessage> editMessageById(long id, @NotNull SendableDiscordMessage message) {
|
||||
return message(
|
||||
message,
|
||||
(client, msg) -> client.edit(id, msg),
|
||||
(textChannel, msg) -> textChannel.editMessageById(id, msg)
|
||||
);
|
||||
}
|
||||
|
||||
private CompletableFuture<ReceivedDiscordMessage> message(
|
||||
SendableDiscordMessage message,
|
||||
BiFunction<WebhookClient, WebhookMessage, CompletableFuture<ReadonlyMessage>> webhookFunction,
|
||||
BiFunction<T, Message, MessageAction> jdaFunction) {
|
||||
return discordSRV.discordAPI().mapExceptions(() -> {
|
||||
CompletableFuture<ReceivedDiscordMessage> future;
|
||||
if (message.isWebhookMessage()) {
|
||||
future = discordSRV.discordAPI().queryWebhookClient(getId())
|
||||
.thenCompose(client -> webhookFunction.apply(
|
||||
client, SendableDiscordMessageUtil.toWebhook(message)))
|
||||
.thenApply(msg -> ReceivedDiscordMessageImpl.fromWebhook(discordSRV, msg));
|
||||
} else {
|
||||
future = jdaFunction
|
||||
.apply(channel, SendableDiscordMessageUtil.toJDA(message))
|
||||
.submit()
|
||||
.thenApply(msg -> ReceivedDiscordMessageImpl.fromJDA(discordSRV, msg));
|
||||
}
|
||||
return future;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> deleteMessageById(long id, boolean webhookMessage) {
|
||||
CompletableFuture<Void> future;
|
||||
if (webhookMessage) {
|
||||
future = channel.deleteMessageById(id).submit();
|
||||
} else {
|
||||
future = discordSRV.discordAPI()
|
||||
.queryWebhookClient(channel.getIdLong())
|
||||
.thenCompose(client -> client.delete(id));
|
||||
}
|
||||
return discordSRV.discordAPI().mapExceptions(future);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2021 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.discord.api.entity.channel;
|
||||
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordNewsChannel;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import net.dv8tion.jda.api.entities.NewsChannel;
|
||||
|
||||
public class DiscordNewsChannelImpl
|
||||
extends DiscordGuildMessageChannelImpl<NewsChannel>
|
||||
implements DiscordNewsChannel {
|
||||
|
||||
public DiscordNewsChannelImpl(DiscordSRV discordSRV, NewsChannel channel) {
|
||||
super(discordSRV, channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NewsChannel getAsJDANewsChannel() {
|
||||
return channel;
|
||||
}
|
||||
}
|
@ -16,23 +16,27 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.discord.api.channel;
|
||||
package com.discordsrv.common.discord.api.entity.channel;
|
||||
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordMessageChannel;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordTextChannel;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||
import net.dv8tion.jda.api.entities.PrivateChannel;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public abstract class DiscordMessageChannelImpl implements DiscordMessageChannel {
|
||||
public class DiscordTextChannelImpl extends DiscordGuildMessageChannelImpl<TextChannel> implements DiscordTextChannel {
|
||||
|
||||
public static DiscordMessageChannelImpl get(DiscordSRV discordSRV, MessageChannel messageChannel) {
|
||||
if (messageChannel instanceof TextChannel) {
|
||||
return new DiscordTextChannelImpl(discordSRV, (TextChannel) messageChannel);
|
||||
} else if (messageChannel instanceof PrivateChannel) {
|
||||
return new DiscordDMChannelImpl(discordSRV, (PrivateChannel) messageChannel);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown MessageChannel type");
|
||||
public DiscordTextChannelImpl(DiscordSRV discordSRV, TextChannel textChannel) {
|
||||
super(discordSRV, textChannel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getTopic() {
|
||||
return channel.getTopic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextChannel getAsJDATextChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.discord.api.guild;
|
||||
package com.discordsrv.common.discord.api.entity.guild;
|
||||
|
||||
import com.discordsrv.api.discord.api.entity.guild.DiscordGuild;
|
||||
import com.discordsrv.api.discord.api.entity.guild.DiscordGuildMember;
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.discord.api.guild;
|
||||
package com.discordsrv.common.discord.api.entity.guild;
|
||||
|
||||
import com.discordsrv.api.color.Color;
|
||||
import com.discordsrv.api.discord.api.entity.guild.DiscordGuild;
|
||||
@ -26,7 +26,7 @@ import com.discordsrv.api.placeholder.annotation.Placeholder;
|
||||
import com.discordsrv.api.placeholder.annotation.PlaceholderRemainder;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.component.util.ComponentUtil;
|
||||
import com.discordsrv.common.discord.api.DiscordUserImpl;
|
||||
import com.discordsrv.common.discord.api.entity.DiscordUserImpl;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
@ -73,6 +73,11 @@ public class DiscordGuildMemberImpl extends DiscordUserImpl implements DiscordGu
|
||||
return roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEffectiveServerAvatarUrl() {
|
||||
return member.getEffectiveAvatarUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getColor() {
|
||||
return color;
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.discord.api.guild;
|
||||
package com.discordsrv.common.discord.api.entity.guild;
|
||||
|
||||
import com.discordsrv.api.color.Color;
|
||||
import com.discordsrv.api.discord.api.entity.guild.DiscordRole;
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.discord.api.message;
|
||||
package com.discordsrv.common.discord.api.entity.message;
|
||||
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessage;
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster;
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.discord.api.message;
|
||||
package com.discordsrv.common.discord.api.entity.message;
|
||||
|
||||
import club.minnced.discord.webhook.WebhookClient;
|
||||
import club.minnced.discord.webhook.receive.ReadonlyAttachment;
|
||||
@ -40,9 +40,9 @@ import com.discordsrv.api.placeholder.annotation.PlaceholderRemainder;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.component.util.ComponentUtil;
|
||||
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
|
||||
import com.discordsrv.common.discord.api.DiscordUserImpl;
|
||||
import com.discordsrv.common.discord.api.channel.DiscordMessageChannelImpl;
|
||||
import com.discordsrv.common.discord.api.guild.DiscordGuildMemberImpl;
|
||||
import com.discordsrv.common.discord.api.entity.DiscordUserImpl;
|
||||
import com.discordsrv.common.discord.api.entity.channel.DiscordMessageChannelImpl;
|
||||
import com.discordsrv.common.discord.api.entity.guild.DiscordGuildMemberImpl;
|
||||
import com.discordsrv.common.function.OrDefault;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
@ -265,7 +265,7 @@ public class ReceivedDiscordMessageImpl extends SendableDiscordMessageImpl imple
|
||||
return future;
|
||||
}
|
||||
|
||||
return textChannel.deleteMessageById(getId());
|
||||
return textChannel.deleteMessageById(getId(), fromSelf && getWebhookUsername().isPresent());
|
||||
}
|
||||
|
||||
@Override
|
Loading…
Reference in New Issue
Block a user