Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ or in your IDE (press `CTRL` twice in IntelliJ to open the command bar).
If you wish to contribute to the link server, you can instead run the main method of `LinkServer` from your IDE,
and *then* start MkDocs with `mkdocs serve`.

### Special macros

- `{{ wiki_stub }}` creates an admonition about wiki stubs, which are here for feature discovery, but have little to no content

#### Documentation macros
- `[[ClassRef]]` creates a link to the documentation of the referenced class
- `[[ClassRef#functionRef]]` creates a link to the documentation of the referenced function
- `[[ClassRef#propertyRef]]` creates a link to the documentation of the referenced property
- `[[functionRef]]` creates a link to the documentation of the referenced top-level function (extension functions are top level)
- `[[propertyRef]]` creates a link to the documentation of the referenced top-level property (extension properties are top level)

Class references use simple names (only the class's name, no package)
Member references only use the member's name (such as `BotCommands#create`)

## Running the wiki bot

### Additional requirements
Expand All @@ -23,4 +37,4 @@ and *then* start MkDocs with `mkdocs serve`.
Duplicate the `config-template` folder as `dev-config`,
and edit the `config.json`, with your bot token, prefixes, owner ID and the database details.

You can then run the `Main` class.
You can then run the `Main` class.
216 changes: 216 additions & 0 deletions docs/setup/getting-started-spring-boot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# Starting from scratch - Spring Boot

!!! note

This assumes you know how to use Spring Boot.

Start by creating a regular Spring Boot project, no modules are required.

## Adding the dependencies

The only strictly necessary dependencies are the framework, the Spring support module, and, JDA:

[![](https://img.shields.io/maven-central/v/io.github.freya022/BotCommands?versionPrefix=3&label=BotCommands)](https://mvnrepository.com/artifact/io.github.freya022/BotCommands/latest)
[![](https://img.shields.io/maven-central/v/net.dv8tion/JDA?versionPrefix=5&label=JDA)](https://mvnrepository.com/artifact/net.dv8tion/JDA/latest)

!!! tip ""

Omit the `v` prefix from the version, e.g. `5.0.0-beta.18`.

=== "Maven"

```xml
<dependencies>
...

<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>JDA_VERSION</version>
</dependency>
<dependency>
<groupId>io.github.freya022</groupId>
<artifactId>BotCommands</artifactId>
<version>BC_VERSION</version>
</dependency>
<dependency>
<groupId>io.github.freya022</groupId>
<artifactId>BotCommands-spring</artifactId>
<version>BC_VERSION</version>
</dependency>
</dependencies>
```

=== "Kotlin Gradle"

```kotlin
repositories {
...
mavenCentral()
}

dependencies {
...

implementation("net.dv8tion:JDA:JDA_VERSION")
implementation("io.github.freya022:BotCommands:BC_VERSION")
implementation("io.github.freya022:BotCommands-spring:BC_VERSION")
}
```

!!! tip

You can also use the [Spring developer tools](https://docs.spring.io/spring-boot/reference/using/devtools.html)
to speed up your development cycle.

## Optional - Configure logging

The Spring Boot starter should include logging, you can further configure it, in most cases this is in `logback.xml`,
see [Spring Boot logging docs](https://docs.spring.io/spring-boot/reference/features/logging.html#features.logging.custom-log-configuration).

For example, you can set the log level for the framework to `debug` by adding `<logger name="io.github.freya022.botcommands" level="debug"/>`.

## Configuring your token

After getting your token from your bot's dashboard, you can put it in your Spring environment,
this can be an [environment variable](https://docs.spring.io/spring-boot/reference/features/external-config.html#features.external-config.files.env-variables) or an **untracked** `application.yaml` in the current directory, or a `config/` subdirectory,
see [Spring Boot external config docs](https://docs.spring.io/spring-boot/reference/features/external-config.html#features.external-config.files).

## Creating the main class

Add the package(s) of your application to the `scanBasePackages` value of your `#!java @SpringBootApplication`.

## Optional - Configuring the framework

Configuration of the framework is then done either by using application properties (with the prefix being either `botcommands` or `jda`),
or by implementing configurers, see the [`BConfigurer` inheritors][[BConfigurer]].

??? tip "Kotlin - Using a custom `CoroutineEventManager`"

I recommend creating a custom `CoroutineEventManager`,
that way you can configure the amount of threads or their names,
which may be convenient in logs.

You can do so by implementing a `ICoroutineEventManagerSupplier` service,
with the help of `namedDefaultScope`:
```kotlin
--8<-- "wiki/CoroutineEventManagerSupplier.kt:coroutine_event_manager_supplier-kotlin"
```

## Creating a `JDAService`

Now if you try to start your bot, you will see an error about requesting a `JDAService` instance,
this is a service which is responsible for providing (part of) the configuration of your bot,
you must also start your JDA instance in `createJDA`, let's implement it!

??? info "What is it useful for?"

- For the framework to receive all the events, useful for command updates, uploading [application emojis](../using-botcommands/app-emojis.md) and more
- To start the bot when everything is ready
- To check if event listeners have the required gateway intents/cache flags for them to be fired

!!! note

The Spring support module will also check that the gateway intents and cache flags match those configured in `JDAService`,
so, you must put them in your environment, you will then be able to set your gateway intents and cache flags using the values provided by [[JDAConfiguration]].

=== "Kotlin"

```kotlin
--8<-- "wiki/SpringBot.kt:jdaservice-kotlin"
```

=== "Java"

```java
--8<-- "wiki/java/SpringBot.java:jdaservice-java"
```

You can now run your bot! You should be able to run the help command, by mentioning your bot `@YourBot help`.

## Optional - Add `stacktrace-decoroutinator`

I recommend adding [`stacktrace-decoroutinator`](https://github.com/Anamorphosee/stacktrace-decoroutinator),
which will help you get clearer stacktrace when using Kotlin coroutines.

!!! note

Java users also benefit from it as it may help debug framework issues.

[![](https://img.shields.io/maven-central/v/dev.reformator.stacktracedecoroutinator/stacktrace-decoroutinator-jvm?label=stacktrace-decoroutinator)](https://mvnrepository.com/artifact/dev.reformator.stacktracedecoroutinator/stacktrace-decoroutinator-jvm/latest)

=== "Maven"

```xml
<dependencies>
...

<dependency>
<groupId>dev.reformator.stacktracedecoroutinator</groupId>
<artifactId>stacktrace-decoroutinator-jvm</artifactId>
<version>SD_VERSION</version>
</dependency>
</dependencies>
```

=== "Kotlin Gradle"

```kotlin
repositories {
...
mavenCentral()
}

dependencies {
...

implementation("dev.reformator.stacktracedecoroutinator:stacktrace-decoroutinator-jvm:SD_VERSION")
}
```

Finally, load it on the first lines of your main program:

=== "Kotlin"

```kotlin
// stacktrace-decoroutinator has issues when reloading with hotswap agent
if ("-XX:+AllowEnhancedClassRedefinition" in ManagementFactory.getRuntimeMXBean().inputArguments) {
logger.info { "Skipping stacktrace-decoroutinator as enhanced hotswap is active" }
} else if ("--no-decoroutinator" in args) {
logger.info { "Skipping stacktrace-decoroutinator as --no-decoroutinator is specified" }
} else {
DecoroutinatorRuntime.load()
}
```

!!! warning

`stacktrace-decoroutinator` must be loaded before any coroutine code is loaded,
including suspending main functions `suspend fun main() { ... }`.

=== "Java"

```java
// stacktrace-decoroutinator has issues when reloading with hotswap agent
if (ManagementFactory.getRuntimeMXBean().getInputArguments().contains("-XX:+AllowEnhancedClassRedefinition")) {
logger.info("Skipping stacktrace-decoroutinator as enhanced hotswap is active");
} else if (Arrays.asList(args).contains("--no-decoroutinator")) {
logger.info("Skipping stacktrace-decoroutinator as --no-decoroutinator is specified");
} else {
DecoroutinatorRuntime.INSTANCE.load();
}
```

## Other resources

Take a look at other wiki pages, such as [Dependency injection](../using-botcommands/dependency-injection/index.md),
[Creating slash command](../using-commands/application-commands/writing-slash-commands.md)
and [Using components](../using-components.md).

### Examples

You can find examples covering parts of the framework [here](https://github.com/freya022/BotCommands/tree/3.X/src/examples).

### Getting help

Don't hesitate to join [the support server](https://discord.gg/frpCcQfvTz) if you have any question!
119 changes: 43 additions & 76 deletions docs/setup/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,64 +108,45 @@ this will be useful when running your bot.
As we've used a singleton pattern for your `Config` class, we can get the same instance anywhere,
and still be able to get it as a service.

=== "Built-in DI"
All you need to do to start the framework is `BotCommands#create`:

All you need to do to start the framework is `BotCommands#create`:

=== "Kotlin"

```kotlin title="Main.kt - Main function"
val config = Config.instance

BotCommands.create {
// Optionally set the owner IDs if they differ from the owners in the Discord dashboard
// addPredefinedOwners(config.ownerIds)

// Add the base package of the application
// All services and commands inside will be loaded
addSearchPath("io.github.name.bot")

textCommands {
usePingAsPrefix = true // The bot will respond to his mention/ping
}
}
```

=== "Java"

```java title="Main.java - Main method"
final var config = Config.getInstance();

BotCommands.create(builder -> {
// Optionally set the owner IDs if they differ from the owners in the Discord dashboard
// builder.addPredefinedOwners(config.getOwnerIds());

// Add the base package of the application
// All services and commands inside will be loaded
builder.addSearchPath("io.github.name.bot");

builder.textCommands(textCommands -> {
textCommands.usePingAsPrefix(true);
});
});
```
=== "Kotlin"

=== "Spring IoC"

The framework also supports Spring IoC, add the library,
add the package of your application with the `scanBasePackages` value of your `#!java @SpringBootApplication`,
and voilà.
```kotlin title="Main.kt - Main function"
val config = Config.instance

!!! note
You can always disable it by adding `BotCommandsAutoConfiguration` to the `exclude` value of your `#!java @SpringBootApplication`.
BotCommands.create {
// Optionally set the owner IDs if they differ from the owners in the Discord dashboard
// addPredefinedOwners(config.ownerIds)

Configuration of the framework is then done either by using application properties (with the prefix being either `botcommands` or `jda`),
or by implementing configurers, see the [`BConfigurer` inheritors][[BConfigurer]].
// Add the base package of the application
// All services and commands inside will be loaded
addSearchPath("io.github.name.bot")

!!! tip

You can also use the [Spring developer tools](https://docs.spring.io/spring-boot/reference/using/devtools.html)
to speed up your development cycle, a few options can be configured with `jda.devtools.*` properties.
textCommands {
usePingAsPrefix = true // The bot will respond to his mention/ping
}
}
```

=== "Java"

```java title="Main.java - Main method"
final var config = Config.getInstance();

BotCommands.create(builder -> {
// Optionally set the owner IDs if they differ from the owners in the Discord dashboard
// builder.addPredefinedOwners(config.getOwnerIds());

// Add the base package of the application
// All services and commands inside will be loaded
builder.addSearchPath("io.github.name.bot");

builder.textCommands(textCommands -> {
textCommands.usePingAsPrefix(true);
});
});
```

??? tip "Kotlin - Using a custom `CoroutineEventManager`"

Expand All @@ -179,24 +160,17 @@ and still be able to get it as a service.
--8<-- "wiki/CoroutineEventManagerSupplier.kt:coroutine_event_manager_supplier-kotlin"
```

!!! warning

JDA must be created **after** the framework is built,
as the framework listens to JDA events and must not skip any of these,
you will need to make a service extending `JDAService`.

## Creating a `JDAService`

Now you've been able to start the framework, all your services (such as `Config` for the moment) should be loaded,
but you must now have a way to start JDA, implementing `JDAService` will let you start the bot in a convenient place.

Implementing `JDAService` guarantees that your bot will connect at the right time,
and provides a way for the framework to check missing intents and missing cache flags before your bot even starts.
Now if you try to start your bot, you will see an error about requesting a `JDAService` instance,
this is a service which is responsible for providing (part of) the configuration of your bot,
you must also start your JDA instance in `createJDA`, let's implement it!

!!! warning "Spring properties"
??? info "What is it useful for?"

If you use Spring, you will need to put gateway intents and cache flags in your environment.
You will then be able to set your gateway intents and cache flags using the values provided by [[JDAConfiguration]].
- For the framework to receive all the events, useful for command updates, uploading [application emojis](../using-botcommands/app-emojis.md) and more
- To start the bot when everything is ready
- To check if event listeners have the required gateway intents/cache flags for them to be fired

=== "Kotlin"

Expand All @@ -210,14 +184,7 @@ and provides a way for the framework to check missing intents and missing cache
--8<-- "wiki/java/Bot.java:jdaservice-java"
```

You can now run your bot!
Assuming you have done your config class and provided at least the token and owner IDs,
you should be able to run the help command, by mentioning your bot `@YourBot help`.

!!! tip

If necessary, you can retrieve a `JDA` instance once `createJDA` has been called,
I recommend listening to `InjectedJDAEvent`, but you can also get one later, using `BContext#jda`.
You can now run your bot! You should be able to run the help command, by mentioning your bot `@YourBot help`.

## Optional - Add `stacktrace-decoroutinator`

Expand Down Expand Up @@ -367,4 +334,4 @@ You can find examples covering parts of the framework [here](https://github.com/

### Getting help

Don't hesitate to join [the support server](https://discord.gg/frpCcQfvTz) if you have any question!
Don't hesitate to join [the support server](https://discord.gg/frpCcQfvTz) if you have any question!
Loading