More progress on the first party api parts

This commit is contained in:
Vankka 2021-07-30 02:53:17 +03:00
parent b149acb36f
commit 1707074410
No known key found for this signature in database
GPG Key ID: 6E50CB7A29B96AD0
24 changed files with 863 additions and 202 deletions

View File

@ -23,7 +23,12 @@
package com.discordsrv.api.discord.api;
import com.discordsrv.api.discord.api.channel.DiscordTextChannel;
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.user.DiscordUser;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
/**
* A basic Discord API wrapper for a limited amount of functions, with a minimal amount of breaking changes.
@ -35,5 +40,19 @@ public interface DiscordAPI {
* @param id the id for the text channel
* @return the text channel
*/
DiscordTextChannel getTextChannelById(String id);
Optional<DiscordTextChannel> getTextChannelById(@NotNull String id);
/**
* Gets a Discord server by id.
* @param id the id for the Discord server
* @return the Discord server
*/
Optional<DiscordGuild> getGuildById(@NotNull String id);
/**
* Gets a Discord user by id.
* @param id the id for the Discord user
* @return the Discord user
*/
Optional<DiscordUser> getUserById(@NotNull String id);
}

View File

@ -0,0 +1,16 @@
package com.discordsrv.api.discord.api.entity;
import org.jetbrains.annotations.NotNull;
/**
* A snowflake identifier.
*/
public interface Snowflake {
/**
* Gets the id of this entity.
* @return the id of this entity
*/
@NotNull
String getId();
}

View File

@ -0,0 +1,34 @@
package com.discordsrv.api.discord.api.entity.channel;
import com.discordsrv.api.discord.api.entity.Snowflake;
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessage;
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CompletableFuture;
/**
* A Discord channel that can send/receive messages.
*/
public interface DiscordMessageChannel extends Snowflake {
/**
* Sends the provided message to the channel.
* @param message the channel to send to the channel
* @return a future returning the message after being sent
* @throws com.discordsrv.api.discord.api.exception.NotReadyException if DiscordSRV is not ready, {@link com.discordsrv.api.DiscordSRVApi#isReady()}
*/
@NotNull
CompletableFuture<ReceivedDiscordMessage> sendMessage(SendableDiscordMessage message);
/**
* Edits the message identified by the id.
* @param id the id of the message to edit
* @param message the new message content
* @return a future returning the message after being edited
* @throws com.discordsrv.api.discord.api.exception.NotReadyException if DiscordSRV is not ready, {@link com.discordsrv.api.DiscordSRVApi#isReady()}
*/
@NotNull
CompletableFuture<ReceivedDiscordMessage> editMessageById(String id, SendableDiscordMessage message);
}

View File

@ -0,0 +1,28 @@
package com.discordsrv.api.discord.api.entity.guild;
import java.util.Optional;
/**
* A Discord server.
*/
public interface DiscordGuild {
/**
* Gets the id of this Discord guild.
* @return the guild's id
*/
String getId();
/**
* Gets the member count of the guild.
* @return the guild's member count
*/
int getMemberCount();
/**
* Gets a Discord guild member by id from the cache.
* @param id the id for the Discord guild member
* @return the Discord guild member from the cache
*/
Optional<DiscordGuildMember> getMemberById(String id);
}

View File

@ -0,0 +1,28 @@
package com.discordsrv.api.discord.api.entity.guild;
import com.discordsrv.api.discord.api.entity.user.DiscordUser;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
/**
* A Discord server member.
*/
public interface DiscordGuildMember extends DiscordUser {
/**
* Gets the nickname of the Discord server member.
* @return the nickname server member
*/
@NotNull
Optional<String> getNickname();
/**
* Gets the effective name of this Discord server member.
* @return the Discord server member's effective name
*/
default String getEffectiveName() {
return getNickname().orElseGet(this::getUsername);
}
}

View File

@ -0,0 +1,17 @@
package com.discordsrv.api.discord.api.entity.guild;
import com.discordsrv.api.discord.api.entity.Snowflake;
import org.jetbrains.annotations.NotNull;
/**
* A Discord server role.
*/
public interface DiscordRole extends Snowflake {
/**
* Gets the name of the Discord role.
* @return the role name
*/
@NotNull
String getName();
}

View File

@ -21,24 +21,49 @@
* SOFTWARE.
*/
package com.discordsrv.api.discord.api.message;
package com.discordsrv.api.discord.api.entity.message;
import net.dv8tion.jda.api.entities.Message;
/**
* An allowed mention that can be used with {@link com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage.Builder#addAllowedMention(AllowedMention)}.
*/
@SuppressWarnings("unused") // API
public interface AllowedMention {
/**
* Permits the @everyone and @here mentions.
*/
AllowedMention EVERYONE = Standard.EVERYONE;
/**
* Permits all role mentions, unless at least one specific role is specified.
*/
AllowedMention ALL_ROLES = Standard.ROLE;
/**
* Permits all user mentions, unless at least one specific user is specified.
*/
AllowedMention ALL_USERS = Standard.USER;
static AllowedMention user(String id) {
return new Snowflake(id, true);
}
/**
* Permits the role identified by the id to be mentioned.
* @param id the id of the role
* @return a {@link AllowedMention} object
*/
static AllowedMention role(String id) {
return new Snowflake(id, false);
}
/**
* Permits the user identified by the id to be mentioned.
* @param id the id of the user
* @return a {@link AllowedMention} object
*/
static AllowedMention user(String id) {
return new Snowflake(id, true);
}
enum Standard implements AllowedMention {
EVERYONE(Message.MentionType.EVERYONE),

View File

@ -21,7 +21,7 @@
* SOFTWARE.
*/
package com.discordsrv.api.discord.api.message;
package com.discordsrv.api.discord.api.entity.message;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.MessageEmbed;
@ -33,9 +33,16 @@ import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
/**
* A Discord embed.
*/
@SuppressWarnings("unused") // API
public class DiscordMessageEmbed {
/**
* Create a new builder for {@link DiscordMessageEmbed}s.
* @return a new builder
*/
public static Builder builder() {
return new Builder();
}

View File

@ -21,34 +21,35 @@
* SOFTWARE.
*/
package com.discordsrv.api.discord.api.message;
package com.discordsrv.api.discord.api.entity.message;
import com.discordsrv.api.discord.api.entity.Snowflake;
import com.discordsrv.api.discord.api.entity.channel.DiscordTextChannel;
import com.discordsrv.api.discord.api.entity.guild.DiscordGuild;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CompletableFuture;
public interface ReceivedDiscordMessage extends SendableDiscordMessage {
/**
* A message received from Discord.
*/
public interface ReceivedDiscordMessage extends SendableDiscordMessage, Snowflake {
/**
* Gets the ID for this message.
* @return the id from Discord for this message
* Gets the channel that the message was sent in.
* @return the channel the message was sent in
*/
String getId();
// TODO: Author
@Override
String getContent();
@NotNull
DiscordTextChannel getChannel();
/**
* Gets the content displayed on Discord, without markdown or other formatting.
* @return the displayed content of the message
* Gets the Discord server the message was posted in.
* @return the Discord server the message was posted in
*/
String getDisplayedContent();
/**
* Gets the raw content with markdown characters stripped from it.
* @return the stripped content of the message
*/
String getStrippedContent();
@NotNull
default DiscordGuild getGuild() {
return getChannel().getGuild();
}
/**
* Edits this message to the provided message, the webhook username and avatar url will be ignored.
@ -56,5 +57,6 @@ public interface ReceivedDiscordMessage extends SendableDiscordMessage {
* @param message the new message
* @return the future for the message edit
*/
@NotNull
CompletableFuture<ReceivedDiscordMessage> edit(SendableDiscordMessage message);
}

View File

@ -21,16 +21,26 @@
* SOFTWARE.
*/
package com.discordsrv.api.discord.api.message;
package com.discordsrv.api.discord.api.entity.message;
import com.discordsrv.api.discord.api.message.impl.SendableDiscordMessageImpl;
import com.discordsrv.api.discord.api.entity.message.impl.SendableDiscordMessageImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Set;
/**
* A message that can be sent to Discord.
*/
@SuppressWarnings("unused") // API
public interface SendableDiscordMessage {
/**
* Creates a new builder for {@link SendableDiscordMessage}.
* @return a new builder
*/
@NotNull
static Builder builder() {
return new SendableDiscordMessageImpl.BuilderImpl();
}
@ -39,30 +49,35 @@ public interface SendableDiscordMessage {
* The raw content of the message.
* @return the unmodified content of the message
*/
@Nullable
String getContent();
/**
* Gets the embeds of the message.
* @return the unmodifiable list of embeds in this message
*/
@NotNull
List<DiscordMessageEmbed> getEmbeds();
/**
* Gets the allowed mentions of the message.
* @return the allowed mentions in this message
*/
@Nullable
Set<AllowedMention> getAllowedMentions();
/**
* Gets the webhook username.
* @return the webhook username or {@code null} if this isn't a webhook message
*/
@Nullable
String getWebhookUsername();
/**
* Gets the webhook avatar url.
* @return the webhook avatar url or {@code null} if no webhook avatar url is specified
*/
@Nullable
String getWebhookAvatarUrl();
/**
@ -79,6 +94,7 @@ public interface SendableDiscordMessage {
* Gets the current content of this message in this builder.
* @return the content
*/
@Nullable
String getContent();
/**
@ -86,12 +102,14 @@ public interface SendableDiscordMessage {
* @param content the new content
* @return the builder, useful for chaining
*/
@NotNull
Builder setContent(String content);
/**
* Gets the embeds that are currently in this builder.
* @return this builder's current embeds
*/
@NotNull
List<DiscordMessageEmbed> getEmbeds();
/**
@ -99,6 +117,7 @@ public interface SendableDiscordMessage {
* @param embed the embed to add
* @return the builder, useful for chaining
*/
@NotNull
Builder addEmbed(DiscordMessageEmbed embed);
/**
@ -106,12 +125,14 @@ public interface SendableDiscordMessage {
* @param embed the embed to remove
* @return the builder, useful for chaining
*/
@NotNull
Builder removeEmbed(DiscordMessageEmbed embed);
/**
* Gets the allowed mentions in this builder.
* @return the builder's current allowed mentions
*/
@Nullable
Set<AllowedMention> getAllowedMentions();
/**
@ -119,6 +140,7 @@ public interface SendableDiscordMessage {
* @param allowedMention the allowed mention to add
* @return the builder, useful for chaining
*/
@NotNull
Builder addAllowedMention(AllowedMention allowedMention);
/**
@ -126,12 +148,14 @@ public interface SendableDiscordMessage {
* @param allowedMention the allowed mention to remove
* @return the builder, useful for chaining
*/
@NotNull
Builder removeAllowedMention(AllowedMention allowedMention);
/**
* Gets the webhook username for this builder or {@code null} if webhooks are not being used.
* @return the webhook username
*/
@Nullable
String getWebhookUsername();
/**
@ -139,12 +163,14 @@ public interface SendableDiscordMessage {
* @param webhookUsername the new webhook username
* @return the builder, useful for chaining
*/
@NotNull
Builder setWebhookUsername(String webhookUsername);
/**
* Gets the webhook avatar url for this builder.
* @return the webhook avatar url
*/
@Nullable
String getWebhookAvatarUrl();
/**
@ -153,12 +179,14 @@ public interface SendableDiscordMessage {
* @throws IllegalStateException if there is no webhook username set
* @return the builder, useful for chaining
*/
@NotNull
Builder setWebhookAvatarUrl(String webhookAvatarUrl);
/**
* Builds a {@link SendableDiscordMessage} from this builder.
* @return the new {@link SendableDiscordMessage}
*/
@NotNull
SendableDiscordMessage build();
}

View File

@ -21,11 +21,12 @@
* SOFTWARE.
*/
package com.discordsrv.api.discord.api.message.impl;
package com.discordsrv.api.discord.api.entity.message.impl;
import com.discordsrv.api.discord.api.message.AllowedMention;
import com.discordsrv.api.discord.api.message.DiscordMessageEmbed;
import com.discordsrv.api.discord.api.message.SendableDiscordMessage;
import com.discordsrv.api.discord.api.entity.message.AllowedMention;
import com.discordsrv.api.discord.api.entity.message.DiscordMessageEmbed;
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashSet;
@ -40,7 +41,7 @@ public class SendableDiscordMessageImpl implements SendableDiscordMessage {
private final String webhookUsername;
private final String webhookAvatarUrl;
public SendableDiscordMessageImpl(String content,
protected SendableDiscordMessageImpl(String content,
List<DiscordMessageEmbed> embeds,
Set<AllowedMention> allowedMentions,
String webhookUsername,
@ -58,7 +59,7 @@ public class SendableDiscordMessageImpl implements SendableDiscordMessage {
}
@Override
public List<DiscordMessageEmbed> getEmbeds() {
public @NotNull List<DiscordMessageEmbed> getEmbeds() {
return embeds;
}
@ -91,24 +92,24 @@ public class SendableDiscordMessageImpl implements SendableDiscordMessage {
}
@Override
public BuilderImpl setContent(String content) {
public @NotNull BuilderImpl setContent(String content) {
this.content = content;
return this;
}
@Override
public List<DiscordMessageEmbed> getEmbeds() {
public @NotNull List<DiscordMessageEmbed> getEmbeds() {
return embeds;
}
@Override
public Builder addEmbed(DiscordMessageEmbed embed) {
public @NotNull Builder addEmbed(DiscordMessageEmbed embed) {
this.embeds.add(embed);
return this;
}
@Override
public Builder removeEmbed(DiscordMessageEmbed embed) {
public @NotNull Builder removeEmbed(DiscordMessageEmbed embed) {
this.embeds.remove(embed);
return this;
}
@ -119,13 +120,13 @@ public class SendableDiscordMessageImpl implements SendableDiscordMessage {
}
@Override
public Builder addAllowedMention(AllowedMention allowedMention) {
public @NotNull Builder addAllowedMention(AllowedMention allowedMention) {
this.allowedMentions.add(allowedMention);
return this;
}
@Override
public Builder removeAllowedMention(AllowedMention allowedMention) {
public @NotNull Builder removeAllowedMention(AllowedMention allowedMention) {
this.allowedMentions.remove(allowedMention);
return this;
}
@ -136,7 +137,7 @@ public class SendableDiscordMessageImpl implements SendableDiscordMessage {
}
@Override
public BuilderImpl setWebhookUsername(String webhookUsername) {
public @NotNull BuilderImpl setWebhookUsername(String webhookUsername) {
this.webhookUsername = webhookUsername;
return this;
}
@ -147,13 +148,13 @@ public class SendableDiscordMessageImpl implements SendableDiscordMessage {
}
@Override
public BuilderImpl setWebhookAvatarUrl(String webhookAvatarUrl) {
public @NotNull BuilderImpl setWebhookAvatarUrl(String webhookAvatarUrl) {
this.webhookAvatarUrl = webhookAvatarUrl;
return this;
}
@Override
public SendableDiscordMessage build() {
public @NotNull SendableDiscordMessage build() {
return new SendableDiscordMessageImpl(content, embeds, allowedMentions, webhookUsername, webhookAvatarUrl);
}
}

View File

@ -0,0 +1,25 @@
package com.discordsrv.api.discord.api.entity.user;
import com.discordsrv.api.discord.api.entity.Snowflake;
import org.jetbrains.annotations.NotNull;
/**
* A Discord user.
*/
public interface DiscordUser extends Snowflake {
/**
* Gets the username of the Discord user.
* @return the user's username
*/
@NotNull
String getUsername();
/**
* Gets the Discord user's discriminator.
* @return the user's discriminator
*/
@NotNull
String getDiscriminator();
}

View File

@ -0,0 +1,26 @@
/*
* 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.exception;
public class NotReadyException extends RuntimeException {}

View File

@ -21,22 +21,18 @@
* SOFTWARE.
*/
package com.discordsrv.api.discord.api.channel;
package com.discordsrv.api.discord.api.exception;
import com.discordsrv.api.discord.api.message.ReceivedDiscordMessage;
import com.discordsrv.api.discord.api.message.SendableDiscordMessage;
public class RestErrorResponseException extends RuntimeException {
import java.util.concurrent.CompletableFuture;
private final int errorCode;
public interface DiscordTextChannel {
String getId();
String getName();
String getTopic();
CompletableFuture<ReceivedDiscordMessage> sendMessage(SendableDiscordMessage message);
CompletableFuture<ReceivedDiscordMessage> editMessageById(String id, SendableDiscordMessage message);
public RestErrorResponseException(int errorCode, Throwable cause) {
super(cause);
this.errorCode = errorCode;
}
public int getErrorCode() {
return errorCode;
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.exception;
public class UnknownChannelException extends RuntimeException {
public UnknownChannelException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.exception;
public class UnknownMessageException extends RuntimeException {
public UnknownMessageException(Throwable cause) {
super(cause);
}
}

View File

@ -19,56 +19,184 @@
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.channel.DiscordTextChannel;
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.user.DiscordUser;
import com.discordsrv.api.discord.api.exception.NotReadyException;
import com.discordsrv.api.discord.api.exception.UnknownChannelException;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.main.channels.BaseChannelConfig;
import com.discordsrv.common.config.main.channels.ChannelConfig;
import com.discordsrv.common.config.main.channels.ChannelConfigHolder;
import com.discordsrv.common.discord.api.channel.DiscordTextChannelImpl;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.RemovalListener;
import com.discordsrv.common.discord.api.guild.DiscordGuildImpl;
import com.discordsrv.common.discord.api.user.DiscordUserImpl;
import com.github.benmanes.caffeine.cache.*;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.entities.Webhook;
import org.checkerframework.checker.index.qual.NonNegative;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
public class DiscordAPIImpl implements DiscordAPI {
private final DiscordSRV discordSRV;
private final Map<String, WebhookClient> configuredClients = new HashMap<>();
private final Cache<String, WebhookClient> cachedClients = Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.expireAfterAccess(5, TimeUnit.MINUTES)
private final AsyncLoadingCache<String, WebhookClient> cachedClients = Caffeine.newBuilder()
.removalListener((RemovalListener<String, WebhookClient>) (id, client, cause) -> {
if (client != null) {
client.close();
}
})
.build();
.expireAfter(new CacheExpiry())
.buildAsync(new CacheLoader());
public DiscordAPIImpl(DiscordSRV discordSRV) {
this.discordSRV = discordSRV;
}
public WebhookClient getWebhookClient(String channelId) {
WebhookClient client = configuredClients.get(channelId);
if (client != null) {
return client;
}
return cachedClients.getIfPresent(channelId);
}
@Override
public DiscordTextChannel getTextChannelById(String id) {
JDA jda = discordSRV.jda();
if (jda == null) {
CompletableFuture<WebhookClient> clientFuture = cachedClients.getIfPresent(channelId);
if (clientFuture == null) {
return null;
}
TextChannel textChannel = jda.getTextChannelById(id);
return textChannel != null ? new DiscordTextChannelImpl(discordSRV, textChannel) : null;
return clientFuture.join();
}
public CompletableFuture<WebhookClient> queryWebhookClient(String channelId) {
return cachedClients.get(channelId);
}
@Override
public Optional<DiscordTextChannel> getTextChannelById(@NotNull String id) {
JDA jda = discordSRV.jda();
if (jda == null) {
return Optional.empty();
}
TextChannel textChannel = jda.getTextChannelById(id);
return textChannel != null
? Optional.of(new DiscordTextChannelImpl(discordSRV, textChannel))
: Optional.empty();
}
@Override
public Optional<DiscordGuild> getGuildById(@NotNull String id) {
JDA jda = discordSRV.jda();
if (jda == null) {
return Optional.empty();
}
Guild guild = jda.getGuildById(id);
return guild != null
? Optional.of(new DiscordGuildImpl(discordSRV, guild))
: Optional.empty();
}
@Override
public Optional<DiscordUser> getUserById(@NotNull String id) {
JDA jda = discordSRV.jda();
if (jda == null) {
return Optional.empty();
}
User user = jda.getUserById(id);
return user != null
? Optional.of(new DiscordUserImpl(user))
: Optional.empty();
}
private class CacheLoader implements AsyncCacheLoader<String, WebhookClient> {
@Override
public @NonNull CompletableFuture<WebhookClient> asyncLoad(@NonNull String channelId, @NonNull Executor executor) {
CompletableFuture<WebhookClient> future = new CompletableFuture<>();
JDA jda = discordSRV.jda();
if (jda == null) {
future.completeExceptionally(new NotReadyException());
return future;
}
TextChannel textChannel = jda.getTextChannelById(channelId);
if (textChannel == null) {
future.completeExceptionally(new UnknownChannelException(null));
return future;
}
return textChannel.retrieveWebhooks().submit().thenApply(webhooks -> {
Webhook hook = null;
for (Webhook webhook : webhooks) {
User user = webhook.getOwnerAsUser();
if (user == null
|| !user.getId().equals(jda.getSelfUser().getId())
|| !webhook.getName().equals("DiscordSRV")) {
continue;
}
hook = webhook;
break;
}
return hook;
}).thenCompose(webhook -> {
if (webhook != null) {
CompletableFuture<Webhook> completableFuture = new CompletableFuture<>();
completableFuture.complete(webhook);
return completableFuture;
}
return textChannel.createWebhook("DiscordSRV").submit();
}).thenApply(webhook ->
WebhookClientBuilder.fromJDA(webhook)
.setHttpClient(jda.getHttpClient())
.setExecutorService(discordSRV.scheduler().executor())
.build()
);
}
}
private class CacheExpiry implements Expiry<String, WebhookClient> {
private boolean isConfiguredChannel(String channelId) {
for (ChannelConfigHolder value : discordSRV.config().channels.values()) {
BaseChannelConfig config = value.get();
if (config instanceof ChannelConfig
&& ((ChannelConfig) config).channelIds.contains(channelId)) {
return true;
}
}
return false;
}
private long expireAfterWrite(String channelId) {
return isConfiguredChannel(channelId) ? Long.MAX_VALUE : TimeUnit.MINUTES.toNanos(15);
}
@Override
public long expireAfterCreate(@NonNull String channelId, @NonNull WebhookClient webhookClient, long currentTime) {
return expireAfterWrite(channelId);
}
@Override
public long expireAfterUpdate(@NonNull String channelId, @NonNull WebhookClient webhookClient, long currentTime, @NonNegative long currentDuration) {
return expireAfterWrite(channelId);
}
@Override
public long expireAfterRead(@NonNull String channelId, @NonNull WebhookClient webhookClient, long currentTime, @NonNegative long currentDuration) {
return isConfiguredChannel(channelId) ? Long.MAX_VALUE : TimeUnit.MINUTES.toNanos(10);
}
}
}

View File

@ -18,58 +18,128 @@
package com.discordsrv.common.discord.api.channel;
import com.discordsrv.api.discord.api.channel.DiscordTextChannel;
import com.discordsrv.api.discord.api.message.ReceivedDiscordMessage;
import com.discordsrv.api.discord.api.message.SendableDiscordMessage;
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.exception.NotReadyException;
import com.discordsrv.api.discord.api.exception.RestErrorResponseException;
import com.discordsrv.api.discord.api.exception.UnknownChannelException;
import com.discordsrv.api.discord.api.exception.UnknownMessageException;
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.JDA;
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.exceptions.ErrorResponseException;
import net.dv8tion.jda.api.requests.ErrorResponse;
import net.dv8tion.jda.api.requests.restaction.MessageAction;
import net.dv8tion.jda.api.utils.MiscUtil;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
public class DiscordTextChannelImpl implements DiscordTextChannel {
private final DiscordSRV discordSRV;
private final TextChannel textChannel;
private final String id;
private final String name;
private final String topic;
private final DiscordGuild guild;
public DiscordTextChannelImpl(DiscordSRV discordSRV, TextChannel textChannel) {
this.discordSRV = discordSRV;
this.textChannel = textChannel;
this.id = textChannel.getId();
this.name = textChannel.getName();
this.topic = textChannel.getTopic();
this.guild = new DiscordGuildImpl(discordSRV, textChannel.getGuild());
}
@Override
public String getId() {
return textChannel.getId();
public @NotNull String getId() {
return id;
}
@Override
public String getName() {
return textChannel.getName();
public @NotNull String getName() {
return name;
}
@Override
public String getTopic() {
return textChannel.getTopic();
public @NotNull String getTopic() {
return topic;
}
@Override
public CompletableFuture<ReceivedDiscordMessage> sendMessage(SendableDiscordMessage message) {
// TODO
public @NotNull DiscordGuild getGuild() {
return guild;
}
@Override
public @NotNull CompletableFuture<ReceivedDiscordMessage> sendMessage(SendableDiscordMessage message) {
return message(message, WebhookClient::send, MessageChannel::sendMessage);
}
@Override
public @NotNull CompletableFuture<ReceivedDiscordMessage> editMessageById(String id, SendableDiscordMessage message) {
return message(
message,
(client, msg) -> client.edit(MiscUtil.parseLong(id), msg),
(textChannel, msg) -> textChannel.editMessageById(id, msg)
);
}
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 {
JDA jda = discordSRV.jda();
if (jda == null) {
throw new NotReadyException();
}
TextChannel textChannel = jda.getTextChannelById(getId());
if (textChannel == null) {
future = new CompletableFuture<>();
future.completeExceptionally(new UnknownChannelException(null));
return future;
}
future = jdaFunction
.apply(textChannel, SendableDiscordMessageUtil.toJDA(message))
.submit()
.thenApply(msg -> ReceivedDiscordMessageImpl.fromJDA(discordSRV, msg));
}
return null;
}
@Override
public CompletableFuture<ReceivedDiscordMessage> editMessageById(String id, SendableDiscordMessage message) {
// TODO
if (message.isWebhookMessage()) {
} else {
}
return null;
return future.handle((msg, t) -> {
if (t instanceof ErrorResponseException) {
ErrorResponse errorResponse = ((ErrorResponseException) t).getErrorResponse();
if (errorResponse != null) {
if (errorResponse == ErrorResponse.UNKNOWN_MESSAGE) {
throw new UnknownMessageException(t);
} else if (errorResponse == ErrorResponse.UNKNOWN_CHANNEL) {
throw new UnknownChannelException(t);
}
}
throw new RestErrorResponseException(((ErrorResponseException) t).getErrorCode(), t);
} else if (t != null) {
throw (RuntimeException) t;
}
return msg;
});
}
}

View File

@ -0,0 +1,51 @@
package com.discordsrv.common.discord.api.guild;
import com.discordsrv.api.discord.api.entity.guild.DiscordGuild;
import com.discordsrv.api.discord.api.entity.guild.DiscordGuildMember;
import com.discordsrv.common.DiscordSRV;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import java.util.Optional;
public class DiscordGuildImpl implements DiscordGuild {
private final DiscordSRV discordSRV;
private final String id;
private final int memberCount;
public DiscordGuildImpl(DiscordSRV discordSRV, Guild guild) {
this.discordSRV = discordSRV;
this.id = guild.getId();
this.memberCount = guild.getMemberCount();
}
@Override
public String getId() {
return id;
}
@Override
public int getMemberCount() {
return memberCount;
}
@Override
public Optional<DiscordGuildMember> getMemberById(String id) {
JDA jda = discordSRV.jda();
if (jda == null) {
return Optional.empty();
}
Guild guild = jda.getGuildById(this.id);
if (guild == null) {
return Optional.empty();
}
Member member = guild.getMemberById(id);
return member != null
? Optional.of(new DiscordGuildMemberImpl(member))
: Optional.empty();
}
}

View File

@ -0,0 +1,23 @@
package com.discordsrv.common.discord.api.guild;
import com.discordsrv.api.discord.api.entity.guild.DiscordGuildMember;
import com.discordsrv.common.discord.api.user.DiscordUserImpl;
import net.dv8tion.jda.api.entities.Member;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
public class DiscordGuildMemberImpl extends DiscordUserImpl implements DiscordGuildMember {
private final String nickname;
public DiscordGuildMemberImpl(Member member) {
super(member.getUser());
this.nickname = member.getNickname();
}
@Override
public @NotNull Optional<String> getNickname() {
return Optional.ofNullable(nickname);
}
}

View File

@ -18,97 +18,147 @@
package com.discordsrv.common.discord.api.message;
import com.discordsrv.api.discord.api.channel.DiscordTextChannel;
import com.discordsrv.api.discord.api.message.AllowedMention;
import com.discordsrv.api.discord.api.message.DiscordMessageEmbed;
import com.discordsrv.api.discord.api.message.ReceivedDiscordMessage;
import com.discordsrv.api.discord.api.message.SendableDiscordMessage;
import com.discordsrv.api.discord.api.message.impl.SendableDiscordMessageImpl;
import club.minnced.discord.webhook.receive.ReadonlyEmbed;
import club.minnced.discord.webhook.receive.ReadonlyMessage;
import club.minnced.discord.webhook.receive.ReadonlyUser;
import club.minnced.discord.webhook.send.WebhookEmbed;
import com.discordsrv.api.discord.api.entity.channel.DiscordTextChannel;
import com.discordsrv.api.discord.api.exception.UnknownChannelException;
import com.discordsrv.api.discord.api.entity.message.DiscordMessageEmbed;
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessage;
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
import com.discordsrv.api.discord.api.entity.message.impl.SendableDiscordMessageImpl;
import com.discordsrv.common.DiscordSRV;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.entities.User;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
public class ReceivedDiscordMessageImpl extends SendableDiscordMessageImpl implements ReceivedDiscordMessage {
private static List<DiscordMessageEmbed> mapEmbeds(List<MessageEmbed> embeds) {
public static ReceivedDiscordMessage fromJDA(DiscordSRV discordSRV, Message message) {
List<DiscordMessageEmbed> mappedEmbeds = new ArrayList<>();
for (MessageEmbed embed : embeds) {
for (MessageEmbed embed : message.getEmbeds()) {
mappedEmbeds.add(new DiscordMessageEmbed(embed));
}
return mappedEmbeds;
boolean webhookMessage = message.isWebhookMessage();
String webhookUsername = webhookMessage ? message.getAuthor().getName() : null;
String webhookAvatarUrl = webhookMessage ? message.getAuthor().getEffectiveAvatarUrl() : null;
DiscordTextChannel textChannel = discordSRV.discordAPI().getTextChannelById(message.getChannel().getId())
.orElse(null);
return new ReceivedDiscordMessageImpl(
discordSRV,
textChannel,
message.getChannel().getId(),
message.getId(),
message.getContentRaw(),
mappedEmbeds,
webhookUsername,
webhookAvatarUrl
);
}
private static Set<AllowedMention> allowedMentions(Message message) {
Set<AllowedMention> allowedMentions = new HashSet<>();
if (message.mentionsEveryone()) {
allowedMentions.add(AllowedMention.EVERYONE);
}
for (User user : message.getMentionedUsers()) {
allowedMentions.add(AllowedMention.user(user.getId()));
}
for (Role role : message.getMentionedRoles()) {
allowedMentions.add(AllowedMention.role(role.getId()));
}
return allowedMentions;
}
public static ReceivedDiscordMessage fromWebhook(DiscordSRV discordSRV, ReadonlyMessage webhookMessage) {
List<DiscordMessageEmbed> mappedEmbeds = new ArrayList<>();
for (ReadonlyEmbed embed : webhookMessage.getEmbeds()) {
List<DiscordMessageEmbed.Field> fields = new ArrayList<>();
for (WebhookEmbed.EmbedField field : embed.getFields()) {
fields.add(new DiscordMessageEmbed.Field(field.getName(), field.getValue(), field.isInline()));
}
private static String webhookUsername(Message message) {
if (!message.isWebhookMessage()) {
return null;
Integer color = embed.getColor();
WebhookEmbed.EmbedAuthor author = embed.getAuthor();
WebhookEmbed.EmbedTitle title = embed.getTitle();
ReadonlyEmbed.EmbedImage thumbnail = embed.getThumbnail();
ReadonlyEmbed.EmbedImage image = embed.getImage();
WebhookEmbed.EmbedFooter footer = embed.getFooter();
mappedEmbeds.add(new DiscordMessageEmbed(
color != null ? color : Role.DEFAULT_COLOR_RAW,
author != null ? author.getName() : null,
author != null ? author.getUrl() : null,
author != null ? author.getIconUrl() : null,
title != null ? title.getText() : null,
title != null ? title.getUrl() : null,
embed.getDescription(),
fields,
thumbnail != null ? thumbnail.getUrl() : null,
image != null ? image.getUrl() : null,
embed.getTimestamp(),
footer != null ? footer.getText() : null,
footer != null ? footer.getIconUrl() : null
));
}
return message.getAuthor().getName();
}
ReadonlyUser author = webhookMessage.getAuthor();
String authorId = Long.toUnsignedString(author.getId());
String avatarId = author.getAvatarId();
String avatarUrl = avatarId != null
? String.format(User.AVATAR_URL, authorId, avatarId, avatarId.startsWith("a_") ? "gif" : "png")
: String.format(User.DEFAULT_AVATAR_URL, Integer.parseInt(author.getDiscriminator()) % 5);
private static String webhookAvatarUrl(Message message) {
if (!message.isWebhookMessage()) {
return null;
}
return message.getAuthor().getEffectiveAvatarUrl();
DiscordTextChannel textChannel = discordSRV.discordAPI().getTextChannelById(
Long.toUnsignedString(webhookMessage.getChannelId())).orElse(null);
return new ReceivedDiscordMessageImpl(
discordSRV,
textChannel,
Long.toUnsignedString(webhookMessage.getChannelId()),
Long.toUnsignedString(webhookMessage.getId()),
webhookMessage.getContent(),
mappedEmbeds,
author.getName(),
avatarUrl
);
}
private final DiscordSRV discordSRV;
private final Message message;
private final DiscordTextChannel textChannel;
private final String channelId;
private final String id;
public ReceivedDiscordMessageImpl(DiscordSRV discordSRV, Message message) {
super(
message.getContentRaw(),
mapEmbeds(message.getEmbeds()),
allowedMentions(message),
webhookUsername(message),
webhookAvatarUrl(message)
);
private ReceivedDiscordMessageImpl(
DiscordSRV discordSRV,
DiscordTextChannel textChannel,
String channelId,
String id,
String content,
List<DiscordMessageEmbed> embeds,
String webhookUsername,
String webhookAvatarUrl
) {
super(content, embeds, null, webhookUsername, webhookAvatarUrl);
this.discordSRV = discordSRV;
this.message = message;
this.textChannel = textChannel;
this.channelId = channelId;
this.id = id;
}
@Override
public String getId() {
return message.getId();
public @NotNull String getId() {
return id;
}
@Override
public String getDisplayedContent() {
return message.getContentDisplay();
public @NotNull DiscordTextChannel getChannel() {
return textChannel;
}
@Override
public String getStrippedContent() {
return message.getContentStripped();
}
public @NotNull CompletableFuture<ReceivedDiscordMessage> edit(SendableDiscordMessage message) {
DiscordTextChannel textChannel = discordSRV.discordAPI().getTextChannelById(channelId).orElse(null);
if (textChannel == null) {
CompletableFuture<ReceivedDiscordMessage> future = new CompletableFuture<>();
future.completeExceptionally(new UnknownChannelException(null));
return future;
}
@Override
public CompletableFuture<ReceivedDiscordMessage> edit(SendableDiscordMessage message) {
DiscordTextChannel textChannel = discordSRV.discordAPI().getTextChannelById(this.message.getChannel().getId());
return textChannel.editMessageById(textChannel.getId(), message);
}
}

View File

@ -20,35 +20,40 @@ package com.discordsrv.common.discord.api.message.util;
import club.minnced.discord.webhook.send.WebhookMessage;
import club.minnced.discord.webhook.send.WebhookMessageBuilder;
import com.discordsrv.api.discord.api.message.AllowedMention;
import com.discordsrv.api.discord.api.message.DiscordMessageEmbed;
import com.discordsrv.api.discord.api.message.SendableDiscordMessage;
import com.discordsrv.api.discord.api.entity.message.AllowedMention;
import com.discordsrv.api.discord.api.entity.message.DiscordMessageEmbed;
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public final class SendableDiscordMessageUtil {
private SendableDiscordMessageUtil() {}
public static Message toJDA(SendableDiscordMessage message) {
public static Message toJDA(@NotNull SendableDiscordMessage message) {
List<Message.MentionType> allowedTypes = new ArrayList<>();
List<String> allowedUsers = new ArrayList<>();
List<String> allowedRoles = new ArrayList<>();
for (AllowedMention allowedMention : message.getAllowedMentions()) {
if (allowedMention instanceof AllowedMention.Snowflake) {
String id = ((AllowedMention.Snowflake) allowedMention).getId();
if (((AllowedMention.Snowflake) allowedMention).isUser()) {
allowedUsers.add(id);
} else {
allowedRoles.add(id);
Set<AllowedMention> allowedMentions = message.getAllowedMentions();
if (allowedMentions != null) {
for (AllowedMention allowedMention : allowedMentions) {
if (allowedMention instanceof AllowedMention.Snowflake) {
String id = ((AllowedMention.Snowflake) allowedMention).getId();
if (((AllowedMention.Snowflake) allowedMention).isUser()) {
allowedUsers.add(id);
} else {
allowedRoles.add(id);
}
} else if (allowedMention instanceof AllowedMention.Standard) {
allowedTypes.add(((AllowedMention.Standard) allowedMention).getMentionType());
}
} else if (allowedMention instanceof AllowedMention.Standard) {
allowedTypes.add(((AllowedMention.Standard) allowedMention).getMentionType());
}
}
@ -66,7 +71,7 @@ public final class SendableDiscordMessageUtil {
.build();
}
public static WebhookMessage toWebhook(SendableDiscordMessage message) {
public static WebhookMessage toWebhook(@NotNull SendableDiscordMessage message) {
return WebhookMessageBuilder.fromJDA(toJDA(message))
.setUsername(message.getWebhookUsername())
.setAvatarUrl(message.getWebhookAvatarUrl())

View File

@ -0,0 +1,33 @@
package com.discordsrv.common.discord.api.user;
import com.discordsrv.api.discord.api.entity.user.DiscordUser;
import net.dv8tion.jda.api.entities.User;
import org.jetbrains.annotations.NotNull;
public class DiscordUserImpl implements DiscordUser {
private final String id;
private final String username;
private final String discriminator;
public DiscordUserImpl(User user) {
this.id = user.getId();
this.username = user.getName();
this.discriminator = user.getDiscriminator();
}
@Override
public @NotNull String getId() {
return id;
}
@Override
public @NotNull String getUsername() {
return username;
}
@Override
public @NotNull String getDiscriminator() {
return discriminator;
}
}

View File

@ -18,10 +18,8 @@
package com.discordsrv.common.listener;
import club.minnced.discord.webhook.WebhookClientBuilder;
import club.minnced.discord.webhook.send.WebhookMessage;
import club.minnced.discord.webhook.send.WebhookMessageBuilder;
import com.discordsrv.api.channel.GameChannel;
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
import com.discordsrv.api.event.bus.EventPriority;
import com.discordsrv.api.event.bus.Subscribe;
import com.discordsrv.api.event.events.message.receive.game.ChatMessageReceiveEvent;
@ -35,9 +33,6 @@ import com.discordsrv.common.player.util.PlayerUtil;
import com.discordsrv.common.string.util.Placeholders;
import dev.vankka.enhancedlegacytext.EnhancedLegacyText;
import dev.vankka.mcdiscordreserializer.discord.DiscordSerializer;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.Webhook;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
@ -82,12 +77,7 @@ public class DefaultChatListener extends AbstractListener {
@Subscribe(priority = EventPriority.LAST)
public void onChatSend(ChatMessageSendEvent event) {
if (checkProcessor(event) || checkCancellation(event)) {
return;
}
JDA jda = discordSRV.jda();
if (jda == null) {
if (checkProcessor(event) || checkCancellation(event) || !discordSRV.isReady()) {
return;
}
@ -99,19 +89,14 @@ public class DefaultChatListener extends AbstractListener {
}
for (String channelId : channelIds) {
TextChannel textChannel = jda.getTextChannelById(channelId);
if (textChannel == null) {
continue;
}
textChannel.retrieveWebhooks().queue(webhooks -> {
Webhook webhook = webhooks.get(0);
WebhookMessage webhookMessage = new WebhookMessageBuilder()
.setUsername(event.getDiscordUsername())
.setContent(event.getDiscordMessage())
.build();
WebhookClientBuilder.fromJDA(webhook).buildJDA().send(webhookMessage);
});
discordSRV.discordAPI().getTextChannelById(channelId).ifPresent(textChannel ->
textChannel.sendMessage(
SendableDiscordMessage.builder()
.setWebhookUsername(event.getDiscordUsername())
.setContent(event.getDiscordMessage())
.build()
)
);
}
}
}