diff --git a/.github/workflows/wiki.yml b/.github/workflows/wiki.yml index 46f3a757..11df61c2 100644 --- a/.github/workflows/wiki.yml +++ b/.github/workflows/wiki.yml @@ -11,7 +11,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: 3.x - - run: pip install mkdocs-material + - run: pip install -r requirements.txt - run: mkdocs build - name: Deploy Wiki uses: JamesIves/github-pages-deploy-action@v4 diff --git a/docs/assets/cookie-clicker.gif b/docs/assets/cookie-clicker.gif new file mode 100644 index 00000000..48f06b19 Binary files /dev/null and b/docs/assets/cookie-clicker.gif differ diff --git a/docs/assets/plugin.png b/docs/assets/plugin.png new file mode 100644 index 00000000..938eac6b Binary files /dev/null and b/docs/assets/plugin.png differ diff --git a/docs/assets/runtime.png b/docs/assets/runtime.png new file mode 100644 index 00000000..5b9433cf Binary files /dev/null and b/docs/assets/runtime.png differ diff --git a/docs/index.md b/docs/index.md index 89d11eee..da20bd00 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,27 +3,37 @@ A declarative, annotation driven interaction framework for JDA. Our goal is to remove any boilerplate code, so you can focus solely on the business logic of your bot - writing bots has never been easier: -## Example -```java -@Interaction -public class CookieClicker { +=== "Code" + ```java + @Interaction + public class CookieClicker { + + private int counter;//(1)! + + @SlashCommand(value = "cookie clicker", desc = "Play cookie clicker") + public void onClicker(CommandEvent event) { + event.with().components("onCookie").reply("You've got %s cookie(s)!", counter); + } + + @Button(value = "Collect", emoji = "🍪", style = ButtonStyle.SUCCESS) + public void onCookie(ComponentEvent event) { + event.reply("You've got %s cookie(s)!", ++counter);//(2)! + } + } + ``` - private int count; + 1. Yes, that's right! We can store the `counter` as a class variable. JDA-Commands will create a new instance of + `CookieClicker` for every command execution, so you don't need to worry about state. You can read more about + it [here](./start/runtime.md). + 2. This will edit the original message and will also keep the `🍪 Collect` button attached. You can find find more + about building replies [here](./interactions/reply.md). - @SlashCommand(value = "cookie clicker", desc = "Play cookie clicker") - public void onClicker(CommandEvent event) { - event.with().components("onCookie").reply("You've got %s cookie(s)!", count); - } +=== "Execution" + ![Cookie Clicker](./assets/cookie-clicker.gif) - @Button(value = "Collect", emoji = "🍪", style = ButtonStyle.SUCCESS) - public void onCookie(ComponentEvent event) { - event.reply("You've got %s cookie(s)!", ++count); - } -} -``` -## Dependency +## Adding to your Project === "Maven" - ```xml + ```xml title="pom.xml" io.github.kaktushose jda-commands @@ -31,7 +41,7 @@ public class CookieClicker { ``` === "Gradle (Kotlin DSL)" - ```kotlin + ```kotlin title="build.gradle.kts" repositories { mavenCentral() } @@ -40,7 +50,7 @@ public class CookieClicker { } ``` === "Gradle (Groovy DSL)" - ```groovy + ```groovy title="build.gradle" repositories { mavenCentral() } @@ -49,7 +59,7 @@ public class CookieClicker { } ``` -## Resources +## Additional Resources You might also find the following resources helpful: diff --git a/docs/start/installation.md b/docs/start/installation.md index fbe0ce97..c758acb8 100644 --- a/docs/start/installation.md +++ b/docs/start/installation.md @@ -4,14 +4,14 @@ - Java 23 or later - [JDA 5.x](https://github.com/discord-jda/JDA) -- SLF4J Implementation _(not mandatory, but recommended)_ +- [SLF4J Implementation](https://jda.wiki/setup/logging/) _(not mandatory, but recommended)_ ## Configuration -JDA-Commands is distributed through Maven Central, or alternately you can download the latest version -[here](https://github.com/Kaktushose/jda-commands/releases/latest) +JDA-Commands is distributed through Maven Central. Alternatively you can download the latest version +[here](https://github.com/Kaktushose/jda-commands/releases/latest). === "Maven" - ```xml + ```xml title="pom.xml" io.github.kaktushose jda-commands @@ -19,7 +19,7 @@ JDA-Commands is distributed through Maven Central, or alternately you can downlo ``` === "Gradle (Kotlin DSL)" - ```kotlin + ```kotlin title="build.gradle.kts" repositories { mavenCentral() } @@ -28,11 +28,19 @@ JDA-Commands is distributed through Maven Central, or alternately you can downlo } ``` === "Gradle (Groovy DSL)" - ```groovy + ```groovy title="build.gradle" repositories { mavenCentral() } dependencies { implementation 'io.github.kaktushose:jda-commands:v4.0.0-beta.4"' } - ``` \ No newline at end of file + ``` + +## IntelliJ Plugin + +We also provide an IntelliJ Plugin that performs some Code Inspection. It validates method references, which are +commonly used in jda-commands. You can find it [here](https://plugins.jetbrains.com/plugin/25977-jda-commands-inspection). + +![Plugin Example](../assets/plugin.png) + diff --git a/docs/start/quick-start.md b/docs/start/quick-start.md index fde1285a..41525ccc 100644 --- a/docs/start/quick-start.md +++ b/docs/start/quick-start.md @@ -5,7 +5,7 @@ public class Main { public static void main(String[] args) { JDA jda = yourJDABuilding(); - JDACommands jdaCommands = JDACommands.start(jda, Main.class); + JDACommands.start(jda, Main.class); } } ``` diff --git a/docs/start/runtime.md b/docs/start/runtime.md new file mode 100644 index 00000000..98d78801 --- /dev/null +++ b/docs/start/runtime.md @@ -0,0 +1,101 @@ +# Runtime Concept + +## Overview + +One of the core concepts in JDA-Commands is the so-called `Runtime`. It will be mentioned frequently here and in the +[Javadocs](https://kaktushose.github.io/jda-commands/javadocs/latest/). A `Runtime` delegates the JDA events to their +corresponding `EventHandlers` and manages the used virtual threads. + +A new `Runtime` is created each time a: + +- [`SlashCommandInteractionEvent`](https://javadoc.io/doc/net.dv8tion/JDA/latest/net/dv8tion/jda/api/events/interaction/command/SlashCommandInteractionEvent.html) +- [`GenericContextInteractionEvent`](https://javadoc.io/doc/net.dv8tion/JDA/latest/net/dv8tion/jda/api/events/interaction/command/GenericContextInteractionEvent.html) +- [`CommandAutoCompleteInteractionEvent`](https://javadoc.io/doc/net.dv8tion/JDA/latest/net/dv8tion/jda/api/events/interaction/command/CommandAutoCompleteInteractionEvent.html) + +is provided by JDA or if an interaction is marked as [*independent*](#components). + +Runtimes are executed in parallel, but events are processed sequentially by each `Runtime`. +Every `EventHandler` called by a `Runtime` is executed in its own virtual thread, isolated from the runtime one. + +See [`Lifetime`](#Lifetime) for +details when a `Runtime` will close. + +## Threading Model + +JDA-Commands will listen for incoming events on the `JDA MainWS-ReadThread`. It will then create a new `Runtime` +or use an existing one, depending on the type of event _(see the flowchart below for details)._ The incoming event is +then passed to the corresponding `Runtime`. + +Each `Runtime` will run in its own virtual thread, called `JDAC Runtime-Thread `. The `Runtime` will wait for new +incoming events and then delegate them to the correct `EventHandler`. For instance, a +[`SlashCommandInteractionEvent`](https://javadoc.io/doc/net.dv8tion/JDA/latest/net/dv8tion/jda/api/events/interaction/command/SlashCommandInteractionEvent.html) +will be passed to the `SlashCommandHandler`. + +The `EventHandler` will _again_ run in its own virtual thread, named `JDAC EventHandler-Thread `, isolated from +the runtime one. Other incoming events are only executed when the previous one has finished. + +!!! tip "Blocking Methods" + Because each event has its own virtual thread, you can call blocking methods like JDAs `RestAction#complete` safely + without blocking the `JDA MainWS-ReadThread`. + +![Runtime Flowchart](../assets/runtime.png) + +## Lifetime + +By default, JDA-Commands will handle the lifetime of Runtimes for you. Every `Runtime` will be closed **15 minutes** +after its creation. This time span is oriented towards the lifespan of the +[`InteractionHook`](https://javadoc.io/doc/net.dv8tion/JDA/latest/net/dv8tion/jda/api/interactions/InteractionHook.html). + +### Explicit + +You can disable the default behaviour by setting the +[`ExpirationStrategy`](https://kaktushose.github.io/jda-commands/javadocs/latest/jda.commands/com/github/kaktushose/jda/commands/dispatching/expiration/ExpirationStrategy.html) to +[`EXPLICIT`](https://kaktushose.github.io/jda-commands/javadocs/latest/jda.commands/com/github/kaktushose/jda/commands/dispatching/expiration/ExpirationStrategy.Explicit.html). + + +```java title="Main.java" +JDACommands.builder(jda, Main.class) + .expirationStrategy(ExpirationStrategy.EXPLICIT) + .start(); +``` + +This will prevent any `Runtime` from closing until [`closeRuntime`](https://kaktushose.github.io/jda-commands/javadocs/latest/jda.commands/com/github/kaktushose/jda/commands/dispatching/events/Event.html#closeRuntime()) +is explicitly called. + +!!! example + ```java title="GreetCommand.java" hl_lines="4" + @SlashCommand("greet") + public void onCommand(CommandEvent event) { + event.reply("Hello World!"); + event.closeRuntime(); + } + ``` + +### Inactivity +You can also adjust the time frame until a `Runtime` gets closed. + +!!! example + ```java title="Main.java" hl_lines="2" + JDACommands.builder(jda, Main.class) + .expirationStrategy(new ExpirationStrategy.Inactivity(20))//(1)! + .start(); + ``` + + 1. Note: the duration is always passed as minutes. + +## Components and Modals + +### Runtime-bound + +By default, Buttons, SelectMenus and Modals are `runtime-bound`. This means that any incoming event will use the same +`Runtime` as the interaction that replied with them. + +However, this also means that they cannot be executed anymore after the `Runtime` is closed. JDA-Commands will handle +that case and remove the component in question. It will also send an ephemeral reply to the user, saying that the +component is no longer available. + + +### Independent + +!!! info + Modals cannot be independent because they always need a parent interaction that triggers them! \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 7f6df10c..016efc09 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -43,6 +43,9 @@ extra: copyright: Copyright © 2025 Kaktushose +plugins: + - open-in-new-tab + markdown_extensions: - admonition - pymdownx.details @@ -67,7 +70,8 @@ nav: - Getting Started: - Installation: start/installation.md - Quick Start Guide: start/quick-start.md - - Interactions: interactions.d + - Runtime Concept: start/runtime.md + - Interactions: interactions.md - Middlewares: middlewares.md - Dependency Injection: di.md - Misc: misc.md diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..95bdfdbd --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +mkdocs-material +mkdocs-open-in-new-tab \ No newline at end of file