v4.1.1 | Avoid callback hell and rate limits
A lot of people use nested callbacks for things like sending private messages or adding reactions:
@Override
public void onMessageReceived(MessageReceivedEvent event) {
if (event.getMessage().getContentRaw().equals("!hello")) {
user.openPrivateChannel().queue(
channel -> channel.sendMessage("Hello Friend").queue(null,
error -> event.getChannel().sendMessage("Failed to send message!").queue()));
}
}
This gets very hard to read and maintain. Instead you can use something like submit()
which returns a CompletableFuture
to allow using continuations such as thenCompose
and similar. This is great and all but that API is rather bad as it will swallow any errors by default and the error handling methods are not very nice.
We added a few new operators for common actions on RestAction:
map
Convert the result of theRestAction
to a different valueflatMap
Chain anotherRestAction
on the resultdelay
Delay the element of the previous step
Let's look at the same example using the new flatMap
operator:
@Override
public void onMessageReceived(MessageReceivedEvent event) {
if (event.getMessage().getContentRaw().equals("!hello")) {
user.openPrivateChannel()
.flatMap(channel -> channel.sendMessage("Hello Friend"))
.queue(null, error -> event.getChannel().sendMessage("Failed to send message!").queue()));
}
}
This can be expanded to even more complicated chains:
@Override
public void onMessageReceived(MessageReceivedEvent event) {
if (event.getMessage().getContentRaw().equals("!hello")) {
event.getChannel().sendMessage("I'll contact you in 10 seconds") // MessageAction
.delay(Duration.ofSeconds(10)) // delay next flatMap by 10 seconds
.flatMap(m -> user.openPrivateChannel()) // RestAction<PrivateChannel>
.flatMap(channel -> channel.sendMessage("Hello Friend, this will self destruct in 30 seconds")) // RestAction<Message>
.delay(Duration.ofSeconds(30)) // delay next flatMap by 30 seconds
.flatMap(Message::delete) // RestAction<Void>
.queue(null, error -> event.getChannel().sendMessage("Failed to send message!").queue()));
}
}
You can imagine how this would look with just queue/queueAfter:
@Override
public void onMessageReceived(MessageReceivedEvent event) {
if (event.getMessage().getContentRaw().equals("!hello")) {
event.getChannel().sendMessage("I'll contact you in 10 seconds").queue(m ->
user.openPrivateChannel().queueAfter(10, TimeUnit.SECONDS, channel ->
channel.sendMessage("Hello Friend, this will self descruct in 30 seconds").queueAfter(30, TimeUnit.SECONDS,
message -> message.delete().queue(),
error -> event.getChannel().sendMessage("Failed to send message!").queue()
)
)
);
}
}
We also changed the implementation for the Rate Limiter in JDA which will now properly keep track of the "new" X-RateLimit-Bucket
header to track which endpoints share the same rate-limit. This also means that JDA will now allow multiple requests to the same path while they follow different HTTP methods. For the user this just means, JDA now has a better understanding of how discord will limit your requests.
The new rate-limiter also has improved logging. You can now see which routes have what rate-limit by setting the logging level of net.dv8tion.jda.internal.requests.RateLimiter
to trace. This will log messages such as this:
Updated bucket 80c17d2f203122d936070c88c8d10f33:guild_id:125227483518861312:webhook_id to (4/5, 4408)
The numbers at the end have this meaning (remaining requests/allowed requests in the reset time, milliseconds until reset)
.
The long bucket id is composed of the hash
and the major parameters
of the request. You can figure out which hash is for which bucket fairly quickly by looking for the corresponding cache log:
Caching bucket hash POST/channels/{channel_id}/messages -> 80c17d2f203122d936070c88c8d10f33
New Features
- RestAction operators (flatMap, map, delay)
- JDABuilder#setMaxBufferSize (same for shard manager)
- Message#suppressEmbeds and Message#getFlags
Deprecation
Detailed javadoc can be found in the deprecated tab of the docs
Installation
The release version is: 4.1.1_101
The latest version is:
Gradle
repositories {
jcenter()
}
dependencies {
compile "net.dv8tion:JDA:4.1.1_101"
}
Maven
The jcenter repository now only works with https! Please change your URL from http to https
<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>4.1.1_101</version>
</dependency>
<repository>
<id>jcenter</id>
<name>jcenter-bintray</name>
<url>https://jcenter.bintray.com</url>
</repository>
Pull Requests
You can view the 4.1.1 Milestone for a list of accepted pull requests for this release. Thank you to everyone who contributed!