mirror of
https://github.com/DiscordSRV/Ascension.git
synced 2024-10-31 08:32:18 +01:00
Improve docs, change game chat events a bit, add in large errors for certain things going wrong with the Discord connection
This commit is contained in:
parent
ff8385dfda
commit
a8cce7cf8d
@ -37,6 +37,7 @@ 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()}
|
||||
@ -44,8 +45,17 @@ public interface DiscordMessageChannel extends Snowflake {
|
||||
@NotNull
|
||||
CompletableFuture<ReceivedDiscordMessage> sendMessage(SendableDiscordMessage message);
|
||||
|
||||
/**
|
||||
* Deletes the message identified by the id.
|
||||
*
|
||||
* @param id the id of the message to delete
|
||||
* @return a future that will fail if the request fails
|
||||
*/
|
||||
CompletableFuture<Void> deleteMessageById(String id);
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -52,10 +52,19 @@ public interface ReceivedDiscordMessage extends SendableDiscordMessage, Snowflak
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits this message to the provided message, the webhook username and avatar url will be ignored.
|
||||
* Deletes this message.
|
||||
*
|
||||
* @return a future that will fail if the request fails
|
||||
*/
|
||||
CompletableFuture<Void> delete();
|
||||
|
||||
/**
|
||||
* Edits this message to the provided message.
|
||||
*
|
||||
* @param message the new message
|
||||
* @return the future for the message edit
|
||||
* @return a future that will fail if the request fails, otherwise the new message provided by the request response
|
||||
* @throws IllegalArgumentException if the message is not a webhook message,
|
||||
* but the provided {@link SendableDiscordMessage} specifies a webhook username.
|
||||
*/
|
||||
@NotNull
|
||||
CompletableFuture<ReceivedDiscordMessage> edit(SendableDiscordMessage message);
|
||||
|
@ -0,0 +1,30 @@
|
||||
package com.discordsrv.api.discord.api.entity.message;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* A cluster of Discord messages, or just a single message.
|
||||
*/
|
||||
public interface ReceivedDiscordMessageCluster {
|
||||
|
||||
/**
|
||||
* Gets the messages in this cluster.
|
||||
* @return the messages in this cluster
|
||||
*/
|
||||
List<? extends ReceivedDiscordMessage> getMessages();
|
||||
|
||||
/**
|
||||
* Deletes all the messages from this cluster, one request per message.
|
||||
* @return a future that fails if any of the requests fail.
|
||||
*/
|
||||
CompletableFuture<Void> deleteAll();
|
||||
|
||||
/**
|
||||
* Edits all the messages in this cluster, one request per edit.
|
||||
* @param newMessage the new content of the messages
|
||||
* @return a future that fails if any of the requests fail.
|
||||
*/
|
||||
CompletableFuture<ReceivedDiscordMessageCluster> editAll(SendableDiscordMessage newMessage);
|
||||
|
||||
}
|
@ -45,4 +45,11 @@ public interface DiscordUser extends Snowflake {
|
||||
@NotNull
|
||||
String getDiscriminator();
|
||||
|
||||
/**
|
||||
* 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}
|
||||
*/
|
||||
default String getAsTag() {
|
||||
return getUsername() + "#" + getDiscriminator();
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ public interface EventBus {
|
||||
|
||||
/**
|
||||
* Subscribes the provided event listener to this {@link EventBus}.
|
||||
* @param eventListener a event listener with atleast one valid {@link Subscribe} method.
|
||||
* @param eventListener a event listener with at least one valid {@link Subscribe} method.
|
||||
*
|
||||
* @throws IllegalArgumentException if the given listener does not contain any valid listeners
|
||||
*/
|
||||
|
@ -42,7 +42,7 @@ public interface EventListener {
|
||||
String className();
|
||||
|
||||
/**
|
||||
* The name of the method for this event listener
|
||||
* The name of the method for this event listener.
|
||||
* @return the method name for this event listener
|
||||
* @see Method#getName()
|
||||
*/
|
||||
|
@ -33,8 +33,12 @@ public final class EventStateHolder {
|
||||
public static final ThreadLocal<EventListener> CANCELLED = new ThreadLocal<>();
|
||||
public static final ThreadLocal<EventListener> PROCESSED = new ThreadLocal<>();
|
||||
|
||||
public static final EventListener FAKE_LISTENER = new FakeListener();
|
||||
/**
|
||||
* Used to indicate an unknown event listener.
|
||||
*/
|
||||
public static final EventListener UNKNOWN_LISTENER = new FakeListener();
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private static class FakeListener implements EventListener {
|
||||
|
||||
@Override
|
||||
|
@ -61,7 +61,7 @@ public interface Cancellable extends Event {
|
||||
EventListener listener = EventStateHolder.CANCELLED.get();
|
||||
if (listener == null) {
|
||||
throw new IllegalStateException("Event is not cancelled");
|
||||
} else if (listener == EventStateHolder.FAKE_LISTENER) {
|
||||
} else if (listener == EventStateHolder.UNKNOWN_LISTENER) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ public interface Processable extends Event {
|
||||
EventListener listener = EventStateHolder.PROCESSED.get();
|
||||
if (listener == null) {
|
||||
throw new IllegalStateException("Event has not been processed");
|
||||
} else if (listener == EventStateHolder.FAKE_LISTENER) {
|
||||
} else if (listener == EventStateHolder.UNKNOWN_LISTENER) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -23,59 +23,24 @@
|
||||
|
||||
package com.discordsrv.api.event.events.message.send.game;
|
||||
|
||||
import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
||||
import com.discordsrv.api.event.events.Cancellable;
|
||||
import com.discordsrv.api.event.events.Processable;
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster;
|
||||
import com.discordsrv.api.event.events.Event;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class AbstractGameMessageSendEvent implements Cancellable, Processable {
|
||||
public abstract class AbstractGameMessageSentEvent implements Event {
|
||||
|
||||
private SendableDiscordMessage discordMessage;
|
||||
private GameChannel targetChannel;
|
||||
private boolean cancelled;
|
||||
private boolean processed;
|
||||
private final ReceivedDiscordMessageCluster discordMessage;
|
||||
|
||||
public AbstractGameMessageSendEvent(@NotNull SendableDiscordMessage discordMessage, @NotNull GameChannel targetChannel) {
|
||||
public AbstractGameMessageSentEvent(@NotNull ReceivedDiscordMessageCluster discordMessage) {
|
||||
this.discordMessage = discordMessage;
|
||||
this.targetChannel = targetChannel;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public SendableDiscordMessage getDiscordMessage() {
|
||||
/**
|
||||
* Gets the {@link ReceivedDiscordMessageCluster} containing the sent message(s).
|
||||
* @return the message cluster
|
||||
*/
|
||||
public ReceivedDiscordMessageCluster getDiscordMessage() {
|
||||
return discordMessage;
|
||||
}
|
||||
|
||||
public void setDiscordMessage(@NotNull SendableDiscordMessage discordMessage) {
|
||||
this.discordMessage = discordMessage;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public GameChannel getTargetChannel() {
|
||||
return targetChannel;
|
||||
}
|
||||
|
||||
public void setTargetChannel(@NotNull GameChannel targetChannel) {
|
||||
this.targetChannel = targetChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancelled) {
|
||||
this.cancelled = cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProcessed() {
|
||||
return processed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsProcessed() {
|
||||
this.processed = true;
|
||||
}
|
||||
}
|
@ -23,13 +23,12 @@
|
||||
|
||||
package com.discordsrv.api.event.events.message.send.game;
|
||||
|
||||
import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ChatMessageSendEvent extends AbstractGameMessageSendEvent {
|
||||
public class ChatMessageSentEvent extends AbstractGameMessageSentEvent {
|
||||
|
||||
public ChatMessageSendEvent(@NotNull SendableDiscordMessage discordMessage, @NotNull GameChannel targetChannel) {
|
||||
super(discordMessage, targetChannel);
|
||||
public ChatMessageSentEvent(@NotNull ReceivedDiscordMessageCluster discordMessage) {
|
||||
super(discordMessage);
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@ import com.discordsrv.common.discord.details.DiscordConnectionDetailsImpl;
|
||||
import com.discordsrv.common.event.bus.EventBusImpl;
|
||||
import com.discordsrv.common.function.CheckedRunnable;
|
||||
import com.discordsrv.common.listener.DefaultChannelLookupListener;
|
||||
import com.discordsrv.common.listener.DefaultChatListener;
|
||||
import com.discordsrv.common.listener.DefaultGameChatListener;
|
||||
import com.discordsrv.common.logging.DependencyLoggingFilter;
|
||||
import com.discordsrv.common.logging.logger.backend.LoggingBackend;
|
||||
import com.discordsrv.common.placeholder.PlaceholderServiceImpl;
|
||||
@ -249,7 +249,7 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
|
||||
// Register listeners
|
||||
// Chat
|
||||
eventBus().subscribe(new DefaultChannelLookupListener(this));
|
||||
eventBus().subscribe(new DefaultChatListener(this));
|
||||
eventBus().subscribe(new DefaultGameChatListener(this));
|
||||
}
|
||||
|
||||
@OverridingMethodsMustInvokeSuper
|
||||
|
@ -39,8 +39,11 @@ public class ChannelConfig {
|
||||
public ChannelConfig(DiscordSRV discordSRV) {
|
||||
this.discordSRV = discordSRV;
|
||||
this.channels = discordSRV.caffeineBuilder()
|
||||
.expireAfterWrite(30, TimeUnit.SECONDS)
|
||||
.expireAfterWrite(60, TimeUnit.SECONDS)
|
||||
.expireAfterAccess(30, TimeUnit.SECONDS)
|
||||
.refreshAfterWrite(10, TimeUnit.SECONDS)
|
||||
.build(new CacheLoader<String, GameChannel>() {
|
||||
|
||||
@Override
|
||||
public @Nullable GameChannel load(@NonNull String channelName) {
|
||||
GameChannelLookupEvent event = new GameChannelLookupEvent(null, channelName);
|
||||
|
@ -28,5 +28,9 @@ public interface Console extends ICommandSender {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the logging backend for the server/proxy.
|
||||
* @return the {@link LoggingBackend}
|
||||
*/
|
||||
LoggingBackend loggingBackend();
|
||||
}
|
||||
|
@ -0,0 +1,55 @@
|
||||
package com.discordsrv.common.discord.api.message;
|
||||
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessage;
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster;
|
||||
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class ReceivedDiscordMessageClusterImpl implements ReceivedDiscordMessageCluster {
|
||||
|
||||
private final List<ReceivedDiscordMessage> messages;
|
||||
|
||||
public ReceivedDiscordMessageClusterImpl(List<ReceivedDiscordMessage> messages) {
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ReceivedDiscordMessage> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public CompletableFuture<Void> deleteAll() {
|
||||
CompletableFuture<Void>[] futures = new CompletableFuture[messages.size()];
|
||||
for (int i = 0; i < messages.size(); i++) {
|
||||
futures[i] = messages.get(i).delete();
|
||||
}
|
||||
|
||||
return CompletableFuture.allOf(futures);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public CompletableFuture<ReceivedDiscordMessageCluster> editAll(SendableDiscordMessage newMessage) {
|
||||
CompletableFuture<ReceivedDiscordMessage>[] futures = new CompletableFuture[messages.size()];
|
||||
for (int i = 0; i < messages.size(); i++) {
|
||||
futures[i] = messages.get(i).edit(newMessage);
|
||||
}
|
||||
|
||||
return CompletableFuture.allOf(futures)
|
||||
.thenApply(v -> {
|
||||
List<ReceivedDiscordMessage> messages = new ArrayList<>();
|
||||
for (CompletableFuture<ReceivedDiscordMessage> future : futures) {
|
||||
// All the futures are done, so we're just going to get the results from all of them
|
||||
messages.add(
|
||||
future.join());
|
||||
}
|
||||
|
||||
return new ReceivedDiscordMessageClusterImpl(messages);
|
||||
});
|
||||
}
|
||||
}
|
@ -150,6 +150,18 @@ public class ReceivedDiscordMessageImpl extends SendableDiscordMessageImpl imple
|
||||
return textChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> delete() {
|
||||
DiscordTextChannel textChannel = discordSRV.discordAPI().getTextChannelById(channelId).orElse(null);
|
||||
if (textChannel == null) {
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
future.completeExceptionally(new UnknownChannelException());
|
||||
return future;
|
||||
}
|
||||
|
||||
return textChannel.deleteMessageById(getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<ReceivedDiscordMessage> edit(SendableDiscordMessage message) {
|
||||
if (!isWebhookMessage() && message.isWebhookMessage()) {
|
||||
@ -163,6 +175,6 @@ public class ReceivedDiscordMessageImpl extends SendableDiscordMessageImpl imple
|
||||
return future;
|
||||
}
|
||||
|
||||
return textChannel.editMessageById(textChannel.getId(), message);
|
||||
return textChannel.editMessageById(getId(), message);
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
package com.discordsrv.common.discord.connection.jda;
|
||||
|
||||
import com.discordsrv.api.discord.api.entity.user.DiscordUser;
|
||||
import com.discordsrv.api.discord.connection.DiscordConnectionDetails;
|
||||
import com.discordsrv.api.event.bus.EventPriority;
|
||||
import com.discordsrv.api.event.bus.Subscribe;
|
||||
@ -44,7 +45,9 @@ import net.dv8tion.jda.api.entities.*;
|
||||
import net.dv8tion.jda.api.events.DisconnectEvent;
|
||||
import net.dv8tion.jda.api.events.ShutdownEvent;
|
||||
import net.dv8tion.jda.api.events.StatusChangeEvent;
|
||||
import net.dv8tion.jda.api.exceptions.ErrorResponseException;
|
||||
import net.dv8tion.jda.api.requests.CloseCode;
|
||||
import net.dv8tion.jda.api.requests.ErrorResponse;
|
||||
import net.dv8tion.jda.api.requests.GatewayIntent;
|
||||
import net.dv8tion.jda.api.requests.RestAction;
|
||||
import net.dv8tion.jda.api.utils.AllowedMentions;
|
||||
@ -55,13 +58,20 @@ import net.dv8tion.jda.internal.utils.IOUtil;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
import javax.security.auth.login.LoginException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
|
||||
private static final Map<GatewayIntent, String> PRIVILEGED_INTENTS = new HashMap<>();
|
||||
|
||||
static {
|
||||
PRIVILEGED_INTENTS.put(GatewayIntent.GUILD_MEMBERS, "Server Members Intent");
|
||||
PRIVILEGED_INTENTS.put(GatewayIntent.GUILD_PRESENCES, "Presence Intent");
|
||||
}
|
||||
|
||||
private final DiscordSRV discordSRV;
|
||||
private final ScheduledExecutorService gatewayPool;
|
||||
private final ScheduledExecutorService rateLimitPool;
|
||||
@ -70,6 +80,10 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
private JDA instance;
|
||||
private boolean detailsAccepted = true;
|
||||
|
||||
// Bot owner details
|
||||
private final AtomicReference<CompletableFuture<DiscordUser>> botOwnerRequest = new AtomicReference<>();
|
||||
private long botOwnerRetrievalTime;
|
||||
|
||||
public JDAConnectionManager(DiscordSRV discordSRV) {
|
||||
this.discordSRV = discordSRV;
|
||||
this.gatewayPool = new ScheduledThreadPoolExecutor(
|
||||
@ -80,11 +94,58 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
5,
|
||||
new CountingThreadFactory(Scheduler.THREAD_NAME_PREFIX + "JDA RateLimit #%s")
|
||||
);
|
||||
RestAction.setDefaultFailure(t -> discordSRV.logger().error("Callback failed", t));
|
||||
|
||||
// Set default failure handling
|
||||
RestAction.setDefaultFailure(t -> {
|
||||
if (t instanceof ErrorResponseException) {
|
||||
ErrorResponse response = ((ErrorResponseException) t).getErrorResponse();
|
||||
if (response == ErrorResponse.MFA_NOT_ENABLED) {
|
||||
withBotOwner(user -> {
|
||||
discordSRV.logger().error("+----------------------------------------------->");
|
||||
discordSRV.logger().error("| Failed to complete a request:");
|
||||
discordSRV.logger().error("|");
|
||||
discordSRV.logger().error("| The Discord bot's owner needs to enable 2FA");
|
||||
discordSRV.logger().error("| on their Discord account due to a Discord");
|
||||
discordSRV.logger().error("| server requiring 2FA for moderation actions");
|
||||
if (user != null) {
|
||||
discordSRV.logger().error("|");
|
||||
discordSRV.logger().error("| The Discord bot's owner is " + user.getAsTag());
|
||||
}
|
||||
discordSRV.logger().error("|");
|
||||
discordSRV.logger().error("| You can view instructions for enabling 2FA here:");
|
||||
discordSRV.logger().error("| https://support.discord.com/hc/en-us/articles/219576828-Setting-up-Two-Factor-Authentication");
|
||||
discordSRV.logger().error("+----------------------------------------------->");
|
||||
});
|
||||
}
|
||||
}
|
||||
discordSRV.logger().error("Callback failed", t);
|
||||
});
|
||||
|
||||
// Disable all mentions by default for safety
|
||||
AllowedMentions.setDefaultMentions(Collections.emptyList());
|
||||
|
||||
discordSRV.eventBus().subscribe(this);
|
||||
}
|
||||
|
||||
private void withBotOwner(Consumer<DiscordUser> botOwnerConsumer) {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
|
||||
CompletableFuture<DiscordUser> request = botOwnerRequest.get();
|
||||
if (request != null && botOwnerRetrievalTime + TimeUnit.MINUTES.toMillis(5) < currentTime) {
|
||||
request.whenComplete((user, t) -> botOwnerConsumer.accept(t != null ? null : user));
|
||||
return;
|
||||
}
|
||||
|
||||
botOwnerRetrievalTime = currentTime;
|
||||
CompletableFuture<DiscordUser> future = instance.retrieveApplicationInfo()
|
||||
.timeout(10, TimeUnit.SECONDS)
|
||||
.map(applicationInfo -> (DiscordUser) new DiscordUserImpl(applicationInfo.getOwner()))
|
||||
.submit();
|
||||
|
||||
botOwnerRequest.set(future);
|
||||
future.whenComplete((user, t) -> botOwnerConsumer.accept(t != null ? null : user));
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.LATE)
|
||||
public void onDSRVShuttingDown(DiscordSRVShuttingDownEvent event) {
|
||||
// This has a timeout
|
||||
@ -93,6 +154,10 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
|
||||
@Subscribe(priority = EventPriority.EARLIEST)
|
||||
public void onPlaceholderLookup(PlaceholderLookupEvent event) {
|
||||
if (event.isProcessed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<Object> newContext = new HashSet<>();
|
||||
for (Object o : event.getContext()) {
|
||||
Object converted;
|
||||
@ -142,7 +207,8 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
|
||||
@Subscribe
|
||||
public void onDisconnect(DisconnectEvent event) {
|
||||
if (checkCode(event.getCloseCode())) {
|
||||
CloseCode closeCode = event.getCloseCode();
|
||||
if (checkCode(closeCode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -152,19 +218,25 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
throw new IllegalStateException("Could not get the close frame for a disconnect");
|
||||
}
|
||||
|
||||
String message;
|
||||
if (closedByServer) {
|
||||
CloseCode closeCode = event.getCloseCode();
|
||||
String closeReason = frame.getCloseReason();
|
||||
|
||||
discordSRV.logger().debug("[JDA] [Server] Disconnected due to "
|
||||
message = "[JDA] [Server] Disconnected due to "
|
||||
+ frame.getCloseCode() + ": "
|
||||
+ (closeCode != null
|
||||
? closeCode.getMeaning()
|
||||
: (closeReason != null ? closeReason : "(Unknown close reason)")));
|
||||
: (closeReason != null ? closeReason : "(Unknown close reason)"));
|
||||
} else {
|
||||
discordSRV.logger().debug("[JDA] [Client] Disconnected due to "
|
||||
message = "[JDA] [Client] Disconnected due to "
|
||||
+ frame.getCloseCode() + ": "
|
||||
+ frame.getCloseReason());
|
||||
+ frame.getCloseReason();
|
||||
}
|
||||
|
||||
if (closeCode != null && !closeCode.isReconnect()) {
|
||||
discordSRV.logger().error(message);
|
||||
} else {
|
||||
discordSRV.logger().debug(message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,10 +249,32 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
if (closeCode == null) {
|
||||
return false;
|
||||
} else if (closeCode == CloseCode.DISALLOWED_INTENTS) {
|
||||
// TODO
|
||||
Set<GatewayIntent> intents = discordSRV.discordConnectionDetails().getGatewayIntents();
|
||||
discordSRV.logger().error("+-------------------------------------->");
|
||||
discordSRV.logger().error("| Failed to connect to Discord:");
|
||||
discordSRV.logger().error("|");
|
||||
discordSRV.logger().error("| The Discord bot is lacking one or more");
|
||||
discordSRV.logger().error("| privileged intents listed below");
|
||||
discordSRV.logger().error("|");
|
||||
for (GatewayIntent intent : intents) {
|
||||
String displayName = PRIVILEGED_INTENTS.get(intent);
|
||||
if (displayName != null) {
|
||||
discordSRV.logger().error("| " + displayName);
|
||||
}
|
||||
}
|
||||
discordSRV.logger().error("|");
|
||||
discordSRV.logger().error("| Instructions for enabling privileged gateway intents:");
|
||||
discordSRV.logger().error("| 1. Go to https://discord.com/developers/applications");
|
||||
discordSRV.logger().error("| 2. Choose the bot you are using for DiscordSRV");
|
||||
discordSRV.logger().error("| - Keep in mind it will only be visible to the ");
|
||||
discordSRV.logger().error("| Discord user who created the bot");
|
||||
discordSRV.logger().error("| 3. Go to the \"Bot\" tab");
|
||||
discordSRV.logger().error("| 4. Make sure the intents listed above are all enabled");
|
||||
discordSRV.logger().error("| 5. "); // TODO
|
||||
discordSRV.logger().error("+-------------------------------------->");
|
||||
return true;
|
||||
} else if (closeCode.isReconnect()) {
|
||||
// TODO
|
||||
} else if (closeCode == CloseCode.AUTHENTICATION_FAILED) {
|
||||
invalidToken();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -245,12 +339,7 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
instance = jdaBuilder.build();
|
||||
break;
|
||||
} catch (LoginException ignored) {
|
||||
discordSRV.logger().error("+-------------------------------+");
|
||||
discordSRV.logger().error("| Failed to connect to Discord: |");
|
||||
discordSRV.logger().error("| |");
|
||||
discordSRV.logger().error("| The token provided in the |");
|
||||
discordSRV.logger().error("| " + ConnectionConfig.FILE_NAME + " is invalid |");
|
||||
discordSRV.logger().error("+-------------------------------+");
|
||||
invalidToken();
|
||||
break;
|
||||
} catch (Throwable t) {
|
||||
discordSRV.logger().error(t);
|
||||
@ -267,6 +356,20 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void invalidToken() {
|
||||
discordSRV.logger().error("+------------------------------>");
|
||||
discordSRV.logger().error("| Failed to connect to Discord:");
|
||||
discordSRV.logger().error("|");
|
||||
discordSRV.logger().error("| The token provided in the");
|
||||
discordSRV.logger().error("| " + ConnectionConfig.FILE_NAME + " is invalid");
|
||||
discordSRV.logger().error("|");
|
||||
discordSRV.logger().error("| You can get the token for your bot from:");
|
||||
discordSRV.logger().error("| https://discord.com/developers/applications");
|
||||
discordSRV.logger().error("| - Keep in mind the bot is only visible to");
|
||||
discordSRV.logger().error("| the Discord user that created the bot");
|
||||
discordSRV.logger().error("+------------------------------>");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> reconnect() {
|
||||
return CompletableFuture.runAsync(() -> {
|
||||
|
@ -166,8 +166,9 @@ public class EventBusImpl implements EventBus {
|
||||
List<Boolean> states = new ArrayList<>(STATES.size());
|
||||
for (Pair<Function<Object, Boolean>, ThreadLocal<EventListener>> entry : STATES) {
|
||||
if (entry.getKey().apply(event)) {
|
||||
// If the state is already set before listeners, we mark it as being changed by a 'unknown' event listener
|
||||
states.add(true);
|
||||
entry.getValue().set(EventStateHolder.FAKE_LISTENER);
|
||||
entry.getValue().set(EventStateHolder.UNKNOWN_LISTENER);
|
||||
continue;
|
||||
}
|
||||
states.add(false);
|
||||
|
@ -19,32 +19,35 @@
|
||||
package com.discordsrv.common.listener;
|
||||
|
||||
import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessage;
|
||||
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;
|
||||
import com.discordsrv.api.event.events.message.send.game.ChatMessageSendEvent;
|
||||
import com.discordsrv.api.event.events.message.send.game.ChatMessageSentEvent;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.component.util.ComponentUtil;
|
||||
import com.discordsrv.common.config.main.channels.BaseChannelConfig;
|
||||
import com.discordsrv.common.config.main.channels.ChannelConfig;
|
||||
import com.discordsrv.common.config.main.channels.minecraftodiscord.MinecraftToDiscordChatConfig;
|
||||
import com.discordsrv.common.discord.api.message.ReceivedDiscordMessageClusterImpl;
|
||||
import com.discordsrv.common.function.OrDefault;
|
||||
import dev.vankka.mcdiscordreserializer.discord.DiscordSerializer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class DefaultChatListener extends AbstractListener {
|
||||
public class DefaultGameChatListener extends AbstractListener {
|
||||
|
||||
public DefaultChatListener(DiscordSRV discordSRV) {
|
||||
public DefaultGameChatListener(DiscordSRV discordSRV) {
|
||||
super(discordSRV);
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.LAST)
|
||||
public void onChatReceive(ChatMessageReceiveEvent event) {
|
||||
if (checkProcessor(event) || checkCancellation(event)) {
|
||||
if (checkProcessor(event) || checkCancellation(event) || !discordSRV.isReady()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -64,30 +67,33 @@ public class DefaultChatListener extends AbstractListener {
|
||||
.addReplacement("%message%", DiscordSerializer.INSTANCE.serialize(message))
|
||||
.build();
|
||||
|
||||
discordSRV.eventBus().publish(
|
||||
new ChatMessageSendEvent(
|
||||
discordMessage,
|
||||
gameChannel
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.LAST)
|
||||
public void onChatSend(ChatMessageSendEvent event) {
|
||||
if (checkProcessor(event) || checkCancellation(event) || !discordSRV.isReady()) {
|
||||
return;
|
||||
}
|
||||
|
||||
GameChannel channel = event.getTargetChannel();
|
||||
BaseChannelConfig channelConfig = discordSRV.channelConfig().get(channel);
|
||||
List<String> channelIds = channelConfig instanceof ChannelConfig ? ((ChannelConfig) channelConfig).channelIds : Collections.emptyList();
|
||||
if (channelIds.isEmpty()) {
|
||||
List<String> channelIds = channelConfig.get(cfg -> cfg instanceof ChannelConfig ? ((ChannelConfig) cfg).channelIds : null);
|
||||
if (channelIds == null || channelIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<CompletableFuture<ReceivedDiscordMessage>> futures = new ArrayList<>();
|
||||
for (String channelId : channelIds) {
|
||||
discordSRV.discordAPI().getTextChannelById(channelId).ifPresent(textChannel ->
|
||||
textChannel.sendMessage(event.getDiscordMessage()));
|
||||
futures.add(textChannel.sendMessage(discordMessage)));
|
||||
}
|
||||
|
||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
|
||||
.whenComplete((v, t) -> {
|
||||
if (t != null) {
|
||||
discordSRV.logger().error("Failed to deliver message to Discord", t);
|
||||
return;
|
||||
}
|
||||
|
||||
List<ReceivedDiscordMessage> messages = new ArrayList<>();
|
||||
for (CompletableFuture<ReceivedDiscordMessage> future : futures) {
|
||||
messages.add(future.join());
|
||||
}
|
||||
|
||||
discordSRV.eventBus().publish(
|
||||
new ChatMessageSentEvent(
|
||||
new ReceivedDiscordMessageClusterImpl(messages)));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user