Skip to content

Commit

Permalink
add common ErrorContext for error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
Kaktushose committed Jan 5, 2025
1 parent 5da6f49 commit df9794e
Show file tree
Hide file tree
Showing 11 changed files with 94 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public void onGenericInteractionCreate(@NotNull GenericInteractionCreateEvent jd
componentEvent.deferEdit().setComponents().queue();
componentEvent.getHook()
.setEphemeral(true)
.sendMessage(context.implementationRegistry().getErrorMessageFactory().getTimedOutComponentMessage())
.sendMessage(context.implementationRegistry().getErrorMessageFactory().getTimedOutComponentMessage(jdaEvent))
.queue();
} else {
log.debug("Received unknown event: {}", jdaEvent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import com.github.kaktushose.jda.commands.definitions.features.internal.Invokable;
import com.github.kaktushose.jda.commands.definitions.interactions.InteractionDefinition;
import com.github.kaktushose.jda.commands.dispatching.reply.MessageReply;
import com.github.kaktushose.jda.commands.embeds.error.ErrorMessageFactory.ErrorContext;
import net.dv8tion.jda.api.events.interaction.GenericInteractionCreateEvent;
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
import org.jetbrains.annotations.NotNull;

import java.util.SequencedCollection;

Expand All @@ -16,16 +18,16 @@
/// @param arguments the arguments used to call the final user defined method via [Invokable#invoke(java.lang.Object, com.github.kaktushose.jda.commands.dispatching.context.InvocationContext)]
/// @param definition the [InteractionDefinition] defining this interaction (referring to the user defined method)
public record InvocationContext<T extends GenericInteractionCreateEvent>(
T event,
KeyValueStore keyValueStore,
InteractionDefinition definition,
SequencedCollection<Object> arguments
) {
@NotNull T event,
@NotNull KeyValueStore keyValueStore,
@NotNull InteractionDefinition definition,
@NotNull SequencedCollection<Object> arguments
) implements ErrorContext {
/// Stops further execution of this invocation at the next suitable moment.
///
/// @param errorMessage the error message that should be sent to the user as a reply
/// @implNote This will interrupt the current event thread
public void cancel(MessageCreateData errorMessage) {
public void cancel(@NotNull MessageCreateData errorMessage) {
new MessageReply(event, definition, new InteractionDefinition.ReplyConfig()).reply(errorMessage);

Thread.currentThread().interrupt();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ private void invoke(@NotNull InvocationContext<T> invocation, @NotNull Runtime r
log.error("Interaction execution failed!", exception);
// this unwraps the underlying error in case of an exception inside the command class
Throwable throwable = exception instanceof InvocationTargetException ? exception.getCause() : exception;
invocation.cancel(implementationRegistry.getErrorMessageFactory().getCommandExecutionFailedMessage(invocation.event(), throwable));
invocation.cancel(implementationRegistry.getErrorMessageFactory().getCommandExecutionFailedMessage(invocation, throwable));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.github.kaktushose.jda.commands.dispatching.handling.EventHandler;
import com.github.kaktushose.jda.commands.dispatching.reply.MessageReply;
import com.github.kaktushose.jda.commands.embeds.error.ErrorMessageFactory;
import com.github.kaktushose.jda.commands.internal.Helpers;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -94,7 +95,7 @@ private Optional<List<Object>> parseArguments(SlashCommandDefinition command, Sl
if (parsed.isEmpty()) {
log.debug("Type adapting failed!");
new MessageReply(event, command).reply(
messageFactory.getTypeAdaptingFailedMessage(event, command, Arrays.asList(input))
messageFactory.getTypeAdaptingFailedMessage(Helpers.errorContext(event, command), Arrays.asList(input))
);
return Optional.empty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public void accept(@NotNull InvocationContext<?> context) {
context.cancel(
implementationRegistry
.getErrorMessageFactory()
.getConstraintFailedMessage(constraint)
.getConstraintFailedMessage(context, constraint)
);
log.debug("Constraint failed!");
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public void accept(@NotNull InvocationContext<?> context) {
if (remaining <= 0) {
activeCooldowns.get(id).remove(entry);
} else {
context.cancel(implementationRegistry.getErrorMessageFactory().getCooldownMessage(remaining));
context.cancel(implementationRegistry.getErrorMessageFactory().getCooldownMessage(context, remaining));
log.debug("Command has a remaining cooldown of {} ms!", remaining);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public void accept(@NotNull InvocationContext<?> context) {
hasPerms = provider.hasPermission(event.getUser(), context);
}
if (!hasPerms) {
context.cancel(implementationRegistry.getErrorMessageFactory().getInsufficientPermissionsMessage(context.definition()));
context.cancel(implementationRegistry.getErrorMessageFactory().getInsufficientPermissionsMessage(context));
log.debug("Insufficient permissions!");
return;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.github.kaktushose.jda.commands.embeds.error;

import com.github.kaktushose.jda.commands.definitions.interactions.InteractionDefinition;
import com.github.kaktushose.jda.commands.definitions.interactions.command.ParameterDefinition;
import com.github.kaktushose.jda.commands.definitions.interactions.command.SlashCommandDefinition;
import com.github.kaktushose.jda.commands.dispatching.events.interactions.CommandEvent;
Expand All @@ -23,11 +22,9 @@ public class DefaultErrorMessageFactory implements ErrorMessageFactory {

@NotNull
@Override
public MessageCreateData getTypeAdaptingFailedMessage(@NotNull GenericInteractionCreateEvent event,
@NotNull InteractionDefinition definition,
@NotNull List<String> userInput) {
public MessageCreateData getTypeAdaptingFailedMessage(@NotNull ErrorContext context, @NotNull List<String> userInput) {
StringBuilder sbExpected = new StringBuilder();
SlashCommandDefinition command = (SlashCommandDefinition) definition;
SlashCommandDefinition command = (SlashCommandDefinition) context.definition();

command.commandParameters().forEach(parameter -> {
if (CommandEvent.class.isAssignableFrom(parameter.type())) {
Expand Down Expand Up @@ -58,15 +55,15 @@ public MessageCreateData getTypeAdaptingFailedMessage(@NotNull GenericInteractio

@NotNull
@Override
public MessageCreateData getInsufficientPermissionsMessage(@NotNull InteractionDefinition interaction) {
public MessageCreateData getInsufficientPermissionsMessage(@NotNull ErrorContext context) {
StringBuilder sbPermissions = new StringBuilder();
interaction.permissions().forEach(permission -> sbPermissions.append(permission).append(", "));
context.definition().permissions().forEach(permission -> sbPermissions.append(permission).append(", "));
String permissions = sbPermissions.toString().isEmpty() ? "N/A" : sbPermissions.substring(0, sbPermissions.length() - 2);
MessageEmbed embed = new EmbedBuilder()
.setColor(Color.RED)
.setTitle("Insufficient Permissions")
.setDescription(String.format("`%s` requires specific permissions to be executed",
interaction.displayName()))
context.definition().displayName()))
.addField("Permissions:",
String.format("`%s`", permissions), false
).build();
Expand All @@ -75,7 +72,7 @@ public MessageCreateData getInsufficientPermissionsMessage(@NotNull InteractionD

@NotNull
@Override
public MessageCreateData getConstraintFailedMessage(@NotNull ParameterDefinition.ConstraintDefinition constraint) {
public MessageCreateData getConstraintFailedMessage(@NotNull ErrorContext context, @NotNull ParameterDefinition.ConstraintDefinition constraint) {
return new MessageCreateBuilder().setEmbeds(new EmbedBuilder()
.setColor(Color.ORANGE)
.setTitle("Parameter Error")
Expand All @@ -86,7 +83,7 @@ public MessageCreateData getConstraintFailedMessage(@NotNull ParameterDefinition

@NotNull
@Override
public MessageCreateData getCooldownMessage(long ms) {
public MessageCreateData getCooldownMessage(@NotNull ErrorContext context, long ms) {
long secs = TimeUnit.MILLISECONDS.toSeconds(ms);
long seconds = secs % 60;
long minutes = (secs / 60) % 60;
Expand Down Expand Up @@ -118,7 +115,7 @@ public MessageCreateData getCooldownMessage(long ms) {

@NotNull
@Override
public MessageCreateData getWrongChannelTypeMessage() {
public MessageCreateData getWrongChannelTypeMessage(@NotNull ErrorContext context) {
return new MessageCreateBuilder().setEmbeds(new EmbedBuilder()
.setColor(Color.RED)
.setTitle("Wrong Channel Type")
Expand All @@ -129,14 +126,14 @@ public MessageCreateData getWrongChannelTypeMessage() {

@NotNull
@Override
public MessageCreateData getCommandExecutionFailedMessage(@NotNull GenericInteractionCreateEvent event, @NotNull Throwable exception) {
public MessageCreateData getCommandExecutionFailedMessage(@NotNull ErrorContext context, @NotNull Throwable exception) {
String error;

error = String.format("```The user \"%s\" attempted to execute an \"%s\" interaction at %s, " +
"but a \"%s\" occurred. " +
"Please refer to the logs for further information.```",
event.getUser(),
event.getInteraction().getType(),
context.event().getUser(),
context.event().getInteraction().getType(),
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis()),
exception.getClass().getName()
);
Expand All @@ -152,7 +149,7 @@ public MessageCreateData getCommandExecutionFailedMessage(@NotNull GenericIntera

@NotNull
@Override
public MessageCreateData getTimedOutComponentMessage() {
public MessageCreateData getTimedOutComponentMessage(@NotNull GenericInteractionCreateEvent context) {
return new MessageCreateBuilder().setEmbeds(new EmbedBuilder()
.setColor(Color.RED)
.setTitle("Unknown Interaction")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,54 +18,68 @@ public interface ErrorMessageFactory {

/// Gets a [MessageCreateData] to send when type adapting of the user input failed.
///
/// @param event the [GenericInteractionCreateEvent] that was attempted to type adapt
/// @param definition the underlying [InteractionDefinition]
/// @param userInput the input the user provided
/// @param context the [ErrorContext]
/// @param userInput the input the user provided
/// @return a [MessageCreateData] to send when type adapting failed
@NotNull
MessageCreateData getTypeAdaptingFailedMessage(@NotNull GenericInteractionCreateEvent event,
@NotNull InteractionDefinition definition,
@NotNull List<String> userInput);
MessageCreateData getTypeAdaptingFailedMessage(@NotNull ErrorContext context, @NotNull List<String> userInput);

/// Gets a [MessageCreateData] to send when a user is missing permissions.
///
/// @param definition the corresponding [InteractionDefinition]
/// @param context the [ErrorContext]
/// @return a [MessageCreateData] to send when a user is missing permissions
@NotNull
MessageCreateData getInsufficientPermissionsMessage(@NotNull InteractionDefinition definition);
MessageCreateData getInsufficientPermissionsMessage(@NotNull ErrorContext context);

/// Gets a [MessageCreateData] to send when a parameter constraint fails.
///
/// @param context the [ErrorContext]
/// @param constraint the corresponding [ConstraintDefinition] that failed
/// @return a [MessageCreateData] to send when a parameter constraint fails
@NotNull
MessageCreateData getConstraintFailedMessage(@NotNull ConstraintDefinition constraint);
MessageCreateData getConstraintFailedMessage(@NotNull ErrorContext context, @NotNull ConstraintDefinition constraint);

/// Gets a [Message] to send when a command still has a cooldown.
///
/// @param ms the remaining cooldown in milliseconds
/// @param context the [ErrorContext]
/// @param ms the remaining cooldown in milliseconds
/// @return a [MessageCreateData] to send when a command still has a cooldown
@NotNull
MessageCreateData getCooldownMessage(long ms);
MessageCreateData getCooldownMessage(@NotNull ErrorContext context, long ms);

/// Gets a [MessageCreateData] to send when the channel type isn't suitable for the command.
///
/// @param context the [ErrorContext]
/// @return a [MessageCreateData] to send when the channel type isn't suitable for the command
@NotNull
MessageCreateData getWrongChannelTypeMessage();
MessageCreateData getWrongChannelTypeMessage(@NotNull ErrorContext context);

/// Gets a [MessageCreateData] to send when the command execution failed.
///
/// @param event the corresponding [GenericInteractionCreateEvent]
/// @param context the [ErrorContext]
/// @param exception the [Throwable] that made the command execution fail
/// @return a [MessageCreateData] to send when the command execution failed
@NotNull
MessageCreateData getCommandExecutionFailedMessage(@NotNull GenericInteractionCreateEvent event, @NotNull Throwable exception);
MessageCreateData getCommandExecutionFailedMessage(@NotNull ErrorContext context, @NotNull Throwable exception);

/// Gets a [MessageCreateData] to send when an incoming component interaction already timed out.
///
/// @param event the [GenericInteractionCreateEvent] mo runtime was found for
/// @return a [MessageCreateData] to send when an incoming component interaction already timed out
@NotNull
MessageCreateData getTimedOutComponentMessage();
MessageCreateData getTimedOutComponentMessage(@NotNull GenericInteractionCreateEvent event);

/// Holds the respective [GenericInteractionCreateEvent] and [InteractionDefinition] of an error.
interface ErrorContext {

/// The [GenericInteractionCreateEvent] in whose execution the error occurred.
@NotNull
GenericInteractionCreateEvent event();

/// The [InteractionDefinition] that models the interaction of the [#event].
@NotNull
InteractionDefinition definition();

}

}
Loading

0 comments on commit df9794e

Please sign in to comment.