-
-
Notifications
You must be signed in to change notification settings - Fork 1
Command Interceptors
Command interceptors, like middlewares and afterwares, can be established through two primary approaches:
- Creating an Interceptor Repository.
- Directly Registering Interceptors within the Framework.
Let's start by examining the second approach. Nexus aggregates all interceptors within a global container accessible by name. All interceptors are stored within Nexus.interceptors
. You can add them using the following methods:
// Example One: Reducing code duplication
Nexus.interceptors.middleware("nexus.auth.server") { event -> event.stopIf(event.server.isEmpty) }
// Example Two: Creating quick middlewares (not recommended)
// This uses UUID as a namespace instead of a user-defined one.
Nexus.interceptors.middleware { event -> event.stopIf(event.server.isEmpty) }
Middlewares implement the NexusMiddleware
interface, utilizing the NexusMiddlewareEvent
, which contains more methods compared to the traditional NexusCommandEvent
:
-
next
: Instructs Nexus to proceed to the next middleware. Does not require being called as a middleware's response. -
stop
: Directs Nexus to halt the command's execution, resulting in a "Interaction has failed" outcome in the user's Discord client. -
stop(NexusMessage)
: Halts the command's execution and sends a specified message. -
stopIf(boolean, NexusMessage?)
: Stops command execution if the boolean is true, sending a message if provided. -
stopIf(Predicate, NexusMessage?)
: Similar to the previous method but accepts a predicate.
Nexus introduces two primary methods for deferring responses in middlewares. However, neither method will automatically defer commands. Responsibility for using deferred responses in commands remains with you. Let's explore the two main ways to defer responses in middlewares:
You can manually defer middlewares by utilizing defer
or deferEphemeral
, followed by a response such as stop(NexusMessage)
. Here's an example of a middleware that defers:
Nexus.interceptors.middleware { event ->
event.deferEphemeral().join()
event.stop(NexusMessage.from("I have deferred the response!"))
}
Automatic deferring is a newer Nexus feature where deferring middlewares is automated. To use this, you need to enable it in the configuration:
Nexus.configuration.interceptors.autoDeferMiddlewareResponses = true
Once enabled, middleware responses will automatically defer if their execution time exceeds 2.5 seconds, like this:
Nexus.interceptors.middleware { event ->
Thread.sleep(3000)
event.stop(NexusMessage.from("I have deferred the response!"))
}
You can further configure properties such as whether deferred responses should be ephemeral or when to automatically defer. Adjust these properties:
// Default values
Nexus.configuration.global.autoDeferAfterMilliseconds = 2350
Nexus.configuration.interceptors.autoDeferAsEphemeral = true
Note
As previously mentioned, you need to manually use deferred responses in commands after enabling this feature. Nexus will not automatically defer command responses. Utilize methods like
event.respondLater()
orevent.respondLaterAsEphemeral()
to handle these cases, or you can enable Nexus to auto-defer for you.For more details on auto-deferring responses, refer to Auto-deferring Commands.
An alternative way to establish interceptors is by utilizing a repository approach.
object SampleInterceptorRepository {
val SERVER_ONLY = Nexus.interceptors.middleware("nexus.auth.server") { event -> event.stopIf(event.server.isEmpty) }
}
The recommended use of repositories helps simplify the process of including middleware. Here's an example demonstrating how to immediately include a middleware using the defined variable:
object PingCommand: NexusHandler {
val name: String = "ping"
val description: String = "Ping, Pong!"
val middlewares = NexusCommand.createMiddlewares(SampleInterceptorRepository.SERVER_ONLY)
override fun onEvent(event: NexusCommandEvent) {
val server = event.server.orElseThrow()
event.respondNowWith("Hello ${server.name}!")
}
}
Now, this command is guaranteed to execute only when the server is present. But there's more to interceptors – you can add custom properties to commands that interceptors can access using the @Share
annotation. Here's how you can achieve that:
object PingCommand: NexusHandler {
val name: String = "ping"
val description: String = "Ping, Pong!"
val middlewares = NexusCommand.createMiddlewares(SampleInterceptorRepository.SERVER_ONLY, SampleInterceptorRepository.DEVELOPER_LOCK)
@Share val DEVELOPER_ONLY = false
override fun onEvent(event: NexusCommandEvent) {
val server = event.server.orElseThrow()
event.respondNowWith("Hello ${server.name}!")
}
}
object SampleInterceptorRepository {
val SERVER_ONLY = Nexus.interceptors.middleware("nexus.auth.server") { event -> event.stopIf(event.server.isEmpty) }
val DEVELOPER_LOCK = Nexus.interceptors.middleware("nexus.auth.developer") { event ->
val locked = event.command.get("DEVELOPER_ONLY", Boolean::class.java).orElse(false)
event.stopIf(locked)
}
}
In this way, you can create powerful and flexible command structures that interact seamlessly with interceptors.
You can add interceptors (middleware, afterware) to all commands using the addGlobalMiddlewares
and addGlobalAfterwares
methods in Nexus, for example, if we want to add the SERVER_ONLY
middleware, then we can add the following line:
Nexus.addGlobalMiddlewares(SampleInterceptorRepository.SERVER_ONLY)
Global interceptors are executed first before the local interceptors (the ones added by the command), for example, if we have a command that has the DEVELOPER_ONLY
middleware and a global middleware of SERVER_ONLY
, the execution of the middleware would be as follows: SERVER_ONLY -> DEVELOPER_ONLY
Afterwares, similar to middleware, is an interceptor that is executed at the "end of the command", although, in recent versions, this was changed to run in parallel to the command execution. Afterwares tend to be used for logic such as logging, analytics, and other kind that do not affect the state of the command. An important thing to note is that, in afterwares, the event may or may not have been responded yet.
You create afterwares in a similar manner to middleware:
Nexus.interceptors.addAfterware("nexus.log") { event -> println("Command ${event.command.name} was ran by ${event.user.discriminatedName}") }
You can then use them in a similar manner to middleware:
object PingCommand: NexusHandler {
val name: String = "ping"
val description: String = "Ping, Pong!"
val afterwares = NexusCommand.createAfterwares("nexus.log")
override fun onEvent(event: NexusCommandEvent) {
val server = event.server.orElseThrow()
event.respondNowWith("Hello ${server.name}!")
}
}
Note that the above only works with successful dispatches. To listen to when a command failed to dispatch (e.g. when a middleware rejected the execution of the command), you can override the onFailedDispatch
method:
object Log: NexusAfterware {
override fun onAfterCommandExecution(event: NexusCommandEvent) {
println("Command dispatched.")
}
override fun onFailedDispatch(event: NexusCommandEvent) {
println("Command failed to dispatch.")
}
}
You can also identify which middleware blocked the dispatching of the command:
object Log: NexusAfterware {
override fun onAfterCommandExecution(event: NexusCommandEvent) {
println("Command dispatched.")
}
override fun onFailedDispatch(event: NexusCommandEvent) {
val middleware = event[NexusAfterware.BLOCKING_MIDDLEWARE_KEY] as String
println("Command failed to dispatch because of $middleware")
}
}
All information in this wiki was written during v1.2.0
, we recommend updating to that version if you are below, or creating an issue in GitHub, updating the wiki if the current information is missing, outdated or lacking.
To get started with Nexus, we recommend reading the following in chronological:
- Installation & Preparing Nexus
- Designing Commands
- Command Interceptors
- Additional Features (Subcommand Router, Option Validation)
- Context Menus
- Command Synchronization
You may want to read a specific part of handling command and middleware responses:
You can also read about additional features of Nexus:
- Subcommand Routing
- Option Validation
- Express Way (shard management)
- Inheritance
- Feather Pagination
- Nexus.R
You can read about synchronizing commands to Discord:
For more additional performance:
Additional configurations: