-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'filtered/2.0.0-dev'
- Loading branch information
Showing
22 changed files
with
2,115 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
plugins { | ||
id("cloud.base-conventions") | ||
id("cloud.publishing-conventions") | ||
} | ||
|
||
dependencies { | ||
api(projects.cloudCore) | ||
implementation(libs.javacord) | ||
} |
86 changes: 86 additions & 0 deletions
86
...discord/cloud-javacord/src/main/java/cloud/commandframework/javacord/JavacordCommand.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// | ||
// MIT License | ||
// | ||
// Copyright (c) 2024 Incendo | ||
// | ||
// 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 cloud.commandframework.javacord; | ||
|
||
import cloud.commandframework.CommandComponent; | ||
import cloud.commandframework.javacord.sender.JavacordCommandSender; | ||
import cloud.commandframework.javacord.sender.JavacordPrivateSender; | ||
import cloud.commandframework.javacord.sender.JavacordServerSender; | ||
import java.util.Locale; | ||
import org.checkerframework.checker.nullness.qual.NonNull; | ||
import org.javacord.api.entity.message.MessageAuthor; | ||
import org.javacord.api.event.message.MessageCreateEvent; | ||
import org.javacord.api.listener.message.MessageCreateListener; | ||
|
||
public class JavacordCommand<C> implements MessageCreateListener { | ||
|
||
private final JavacordCommandManager<C> manager; | ||
private final CommandComponent<C> command; | ||
|
||
JavacordCommand( | ||
final @NonNull CommandComponent<C> command, | ||
final @NonNull JavacordCommandManager<C> manager | ||
) { | ||
this.command = command; | ||
this.manager = manager; | ||
} | ||
|
||
@Override | ||
public final void onMessageCreate(final @NonNull MessageCreateEvent event) { | ||
MessageAuthor messageAuthor = event.getMessageAuthor(); | ||
|
||
if (messageAuthor.isWebhook() || !messageAuthor.isRegularUser()) { | ||
return; | ||
} | ||
|
||
JavacordCommandSender commandSender; | ||
if (event.getMessage().isServerMessage()) { | ||
commandSender = new JavacordServerSender(event); | ||
} else if (event.getMessage().isPrivateMessage()) { | ||
commandSender = new JavacordPrivateSender(event); | ||
} else { | ||
commandSender = new JavacordCommandSender(event); | ||
} | ||
|
||
C sender = this.manager.commandSenderMapper().apply(commandSender); | ||
|
||
String messageContent = event.getMessageContent(); | ||
String commandPrefix = this.manager.getCommandPrefix(sender); | ||
if (!messageContent.startsWith(commandPrefix)) { | ||
return; | ||
} | ||
messageContent = messageContent.substring(commandPrefix.length()); | ||
|
||
final String finalContent = messageContent; | ||
if (this.command.aliases() | ||
.stream() | ||
.map(s -> s.toLowerCase(Locale.ROOT)) | ||
.noneMatch(commandAlias -> finalContent.toLowerCase(Locale.ROOT).startsWith(commandAlias))) { | ||
return; | ||
} | ||
|
||
this.manager.commandExecutor().executeCommand(sender, finalContent, ctx -> | ||
ctx.store(JavacordCommandManager.JAVACORD_COMMAND_SENDER_KEY, commandSender)); | ||
} | ||
} |
192 changes: 192 additions & 0 deletions
192
.../cloud-javacord/src/main/java/cloud/commandframework/javacord/JavacordCommandManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
// | ||
// MIT License | ||
// | ||
// Copyright (c) 2024 Incendo | ||
// | ||
// 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 cloud.commandframework.javacord; | ||
|
||
import cloud.commandframework.CloudCapability; | ||
import cloud.commandframework.CommandManager; | ||
import cloud.commandframework.exceptions.ArgumentParseException; | ||
import cloud.commandframework.exceptions.CommandExecutionException; | ||
import cloud.commandframework.exceptions.InvalidCommandSenderException; | ||
import cloud.commandframework.exceptions.InvalidSyntaxException; | ||
import cloud.commandframework.exceptions.NoPermissionException; | ||
import cloud.commandframework.exceptions.handling.ExceptionContext; | ||
import cloud.commandframework.exceptions.handling.ExceptionHandler; | ||
import cloud.commandframework.execution.ExecutionCoordinator; | ||
import cloud.commandframework.javacord.sender.JavacordCommandSender; | ||
import cloud.commandframework.javacord.sender.JavacordServerSender; | ||
import cloud.commandframework.keys.CloudKey; | ||
import java.util.Optional; | ||
import java.util.function.BiFunction; | ||
import java.util.function.Function; | ||
import org.checkerframework.checker.nullness.qual.NonNull; | ||
import org.checkerframework.checker.nullness.qual.Nullable; | ||
import org.javacord.api.DiscordApi; | ||
import org.javacord.api.entity.permission.PermissionType; | ||
import org.javacord.api.entity.user.User; | ||
|
||
public class JavacordCommandManager<C> extends CommandManager<C> { | ||
|
||
private static final String MESSAGE_INTERNAL_ERROR = "An internal error occurred while attempting to perform this command."; | ||
private static final String MESSAGE_NO_PERMS = "I'm sorry, but you do not have the permission to do this :/"; | ||
|
||
public static final CloudKey<JavacordCommandSender> JAVACORD_COMMAND_SENDER_KEY = CloudKey.of( | ||
"__internal_javacord_sender__", | ||
JavacordCommandSender.class | ||
); | ||
|
||
private final DiscordApi discordApi; | ||
private final Function<@NonNull JavacordCommandSender, @NonNull C> commandSenderMapper; | ||
private final Function<@NonNull C, @NonNull JavacordCommandSender> backwardsCommandSenderMapper; | ||
|
||
private final Function<@NonNull C, @NonNull String> commandPrefixMapper; | ||
private final BiFunction<@NonNull C, @NonNull String, @NonNull Boolean> commandPermissionMapper; | ||
|
||
/** | ||
* Construct a new Javacord command manager | ||
* | ||
* @param discordApi Instance of {@link DiscordApi} used to register listeners | ||
* @param commandExecutionCoordinator Coordinator provider | ||
* @param commandSenderMapper Function that maps {@link Object} to the command sender type | ||
* @param backwardsCommandSenderMapper Function that maps the command sender type to {@link Object} | ||
* @param commandPrefixMapper Function that maps the command sender type to the command prefix | ||
* @param commandPermissionMapper Function used to check if a command sender has the permission to execute a command | ||
*/ | ||
@SuppressWarnings("unchecked") | ||
public JavacordCommandManager( | ||
final @NonNull DiscordApi discordApi, | ||
final @NonNull ExecutionCoordinator<C> commandExecutionCoordinator, | ||
final @NonNull Function<@NonNull JavacordCommandSender, @NonNull C> commandSenderMapper, | ||
final @NonNull Function<@NonNull C, | ||
@NonNull JavacordCommandSender> backwardsCommandSenderMapper, | ||
final @NonNull Function<@NonNull C, @NonNull String> commandPrefixMapper, | ||
final @Nullable BiFunction<@NonNull C, | ||
@NonNull String, @NonNull Boolean> commandPermissionMapper | ||
) { | ||
super(commandExecutionCoordinator, new JavacordRegistrationHandler<>()); | ||
((JavacordRegistrationHandler<C>) this.commandRegistrationHandler()).initialize(this); | ||
this.discordApi = discordApi; | ||
this.commandSenderMapper = commandSenderMapper; | ||
this.backwardsCommandSenderMapper = backwardsCommandSenderMapper; | ||
|
||
this.commandPrefixMapper = commandPrefixMapper; | ||
this.commandPermissionMapper = commandPermissionMapper; | ||
|
||
this.registerCapability(CloudCapability.StandardCapabilities.ROOT_COMMAND_DELETION); | ||
this.registerDefaultExceptionHandlers(); | ||
} | ||
|
||
@Override | ||
public final boolean hasPermission( | ||
final @NonNull C sender, final @NonNull String permission | ||
) { | ||
if (permission.isEmpty()) { | ||
return true; | ||
} | ||
|
||
if (this.commandPermissionMapper != null) { | ||
return this.commandPermissionMapper.apply(sender, permission); | ||
} | ||
|
||
final JavacordCommandSender commandSender = this.backwardsCommandSenderMapper.apply(sender); | ||
if (!(commandSender instanceof JavacordServerSender)) { | ||
return false; | ||
} | ||
|
||
final Optional<User> authorOptional = commandSender.getAuthor().asUser(); | ||
if (!authorOptional.isPresent()) { | ||
return false; | ||
} | ||
|
||
final JavacordServerSender serverSender = (JavacordServerSender) commandSender; | ||
return serverSender.getServer().hasPermission(authorOptional.get(), PermissionType.valueOf(permission)); | ||
} | ||
|
||
final @NonNull Function<@NonNull JavacordCommandSender, @NonNull C> commandSenderMapper() { | ||
return this.commandSenderMapper; | ||
} | ||
|
||
/** | ||
* Gets the current command prefix | ||
* | ||
* @param sender Sender used to get the prefix (probably won't used anyways) | ||
* @return the command prefix | ||
*/ | ||
public @NonNull String getCommandPrefix(final @NonNull C sender) { | ||
return this.commandPrefixMapper.apply(sender); | ||
} | ||
|
||
/** | ||
* Returns the DiscordApi instance. | ||
* | ||
* @return current DiscordApi instance | ||
*/ | ||
public @NonNull DiscordApi discordApi() { | ||
return this.discordApi; | ||
} | ||
|
||
private void registerDefaultExceptionHandlers() { | ||
this.registerHandler(Throwable.class, (commandSender, throwable) -> { | ||
commandSender.sendErrorMessage(throwable.getMessage()); | ||
throwable.printStackTrace(); | ||
}); | ||
this.registerHandler(CommandExecutionException.class, (commandSender, throwable) -> { | ||
commandSender.sendErrorMessage(MESSAGE_INTERNAL_ERROR); | ||
throwable.getCause().printStackTrace(); | ||
}); | ||
this.registerHandler(ArgumentParseException.class, (commandSender, throwable) -> | ||
commandSender.sendErrorMessage("Invalid Command Argument: `" + throwable.getCause().getMessage() + "`") | ||
); | ||
this.registerHandler(NoPermissionException.class, (commandSender, throwable) -> | ||
commandSender.sendErrorMessage(MESSAGE_NO_PERMS) | ||
); | ||
this.registerHandler(InvalidCommandSenderException.class, (commandSender, throwable) -> | ||
commandSender.sendErrorMessage(throwable.getMessage()) | ||
); | ||
this.registerHandler(InvalidSyntaxException.class, (commandSender, throwable) -> | ||
commandSender.sendErrorMessage("Invalid Command Syntax. Correct command syntax is: `" | ||
+ throwable.correctSyntax() + "`") | ||
); | ||
} | ||
|
||
private <T extends Throwable> void registerHandler( | ||
final @NonNull Class<T> exceptionClass, | ||
final @NonNull JavacordExceptionHandler<C, T> handler | ||
) { | ||
this.exceptionController().registerHandler(exceptionClass, handler); | ||
} | ||
|
||
|
||
@FunctionalInterface | ||
@SuppressWarnings("FunctionalInterfaceMethodChanged") | ||
private interface JavacordExceptionHandler<C, T extends Throwable> extends ExceptionHandler<C, T> { | ||
|
||
@Override | ||
default void handle(@NonNull ExceptionContext<C, T> context) throws Throwable { | ||
final JavacordCommandSender commandSender = context.context().get(JAVACORD_COMMAND_SENDER_KEY); | ||
this.handle(commandSender, context.exception()); | ||
} | ||
|
||
void handle(@NonNull JavacordCommandSender commandSender, @NonNull T throwable) throws Throwable; | ||
} | ||
} |
74 changes: 74 additions & 0 deletions
74
...d-javacord/src/main/java/cloud/commandframework/javacord/JavacordRegistrationHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// | ||
// MIT License | ||
// | ||
// Copyright (c) 2024 Incendo | ||
// | ||
// 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 cloud.commandframework.javacord; | ||
|
||
import cloud.commandframework.Command; | ||
import cloud.commandframework.CommandComponent; | ||
import cloud.commandframework.internal.CommandRegistrationHandler; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import org.checkerframework.checker.nullness.qual.NonNull; | ||
import org.javacord.api.listener.message.MessageCreateListener; | ||
|
||
final class JavacordRegistrationHandler<C> implements CommandRegistrationHandler<C> { | ||
|
||
private final Map<CommandComponent<C>, JavacordCommand<C>> registeredCommands = new HashMap<>(); | ||
|
||
private JavacordCommandManager<C> javacordCommandManager; | ||
|
||
JavacordRegistrationHandler() { | ||
} | ||
|
||
void initialize(final @NonNull JavacordCommandManager<C> javacordCommandManager) { | ||
this.javacordCommandManager = javacordCommandManager; | ||
} | ||
|
||
@Override | ||
public boolean registerCommand(final @NonNull Command<C> command) { | ||
/* We only care about the root command argument */ | ||
final CommandComponent<C> component = command.rootComponent(); | ||
if (this.registeredCommands.containsKey(component)) { | ||
return false; | ||
} | ||
@SuppressWarnings("unchecked") final JavacordCommand<C> javacordCommand = new JavacordCommand<>( | ||
component, | ||
this.javacordCommandManager | ||
); | ||
this.registeredCommands.put(component, javacordCommand); | ||
this.javacordCommandManager.discordApi().addMessageCreateListener(javacordCommand); | ||
return true; | ||
} | ||
|
||
@Override | ||
public void unregisterRootCommand( | ||
final @NonNull CommandComponent<C> rootCommand | ||
) { | ||
final JavacordCommand<C> command = this.registeredCommands.get(rootCommand); | ||
if (command == null) { | ||
return; | ||
} | ||
|
||
this.javacordCommandManager.discordApi().removeListener(MessageCreateListener.class, command); | ||
} | ||
} |
4 changes: 4 additions & 0 deletions
4
cloud-discord/cloud-javacord/src/main/java/cloud/commandframework/javacord/package-info.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/** | ||
* cloud implementation for Javacord | ||
*/ | ||
package cloud.commandframework.javacord; |
Oops, something went wrong.