jda.wiki
Open in
urlscan Pro
2606:50c0:8003::153
Public Scan
URL:
https://jda.wiki/using-jda/using-restaction/
Submission: On September 23 via api from US — Scanned from CA
Submission: On September 23 via api from US — Scanned from CA
Form analysis
2 forms found in the DOM<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme="default" data-md-color-primary="purple" data-md-color-accent="indigo" aria-label="Switch to dark mode" type="radio" name="__palette"
id="__palette_0">
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="m17.75 4.09-2.53 1.94.91 3.06-2.63-1.81-2.63 1.81.91-3.06-2.53-1.94L12.44 4l1.06-3 1.06 3zm3.5 6.91-1.64 1.25.59 1.98-1.7-1.17-1.7 1.17.59-1.98L15.75 11l2.06-.05L18.5 9l.69 1.95zm-2.28 4.95c.83-.08 1.72 1.1 1.19 1.85-.32.45-.66.87-1.08 1.27C15.17 23 8.84 23 4.94 19.07c-3.91-3.9-3.91-10.24 0-14.14.4-.4.82-.76 1.27-1.08.75-.53 1.93.36 1.85 1.19-.27 2.86.69 5.83 2.89 8.02a9.96 9.96 0 0 0 8.02 2.89m-1.64 2.02a12.08 12.08 0 0 1-7.8-3.47c-2.17-2.19-3.33-5-3.49-7.82-2.81 3.14-2.7 7.96.31 10.98 3.02 3.01 7.84 3.12 10.98.31">
</path>
</svg>
</label>
<input class="md-option" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme="slate" data-md-color-primary="purple" data-md-color-accent="indigo" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_1">
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_0" hidden="">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M12 7a5 5 0 0 1 5 5 5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3m0-7 2.39 3.42C13.65 5.15 12.84 5 12 5s-1.65.15-2.39.42zM3.34 7l4.16-.35A7.2 7.2 0 0 0 5.94 8.5c-.44.74-.69 1.5-.83 2.29zm.02 10 1.76-3.77a7.131 7.131 0 0 0 2.38 4.14zM20.65 7l-1.77 3.79a7.02 7.02 0 0 0-2.38-4.15zm-.01 10-4.14.36c.59-.51 1.12-1.14 1.54-1.86.42-.73.69-1.5.83-2.29zM12 22l-2.41-3.44c.74.27 1.55.44 2.41.44.82 0 1.63-.17 2.37-.44z">
</path>
</svg>
</label>
</form>
Name: search —
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required="">
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"></path>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"></path>
</svg>
</label>
<nav class="md-search__options" aria-label="Search">
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path>
</svg>
</button>
</nav>
</form>
Text Content
Skip to content JDA Wiki Using RestAction Type to start searching JDA * v5.1.1 * 4.3k * 739 * Getting Started * Setup * Using JDA * Contributing * Javadocs JDA Wiki JDA * v5.1.1 * 4.3k * 739 * Getting Started Getting Started * JDA * Using Events * List of Events * FAQ * Migration V3 -> V4 * Migration V4 -> V5 * Setup Setup * IntelliJ IDEA Setup * Eclipse Setup * Netbeans Setup * Logging (SLF4J) * Using JDA Using JDA * Getting Started * Making a Music Bot * Using RestAction Using RestAction Table of contents * AuditLog Reasons * Using queue() * Using submit() * Using complete() * Using completeAfter, submitAfter and queueAfter * Interactions * Paginating Entities * Gateway Intents and Member Cache Policy * Webhooks * Managers and Moderation * Using New Features * Troubleshooting * Contributing Contributing * Contributing * Structure Guide * Repository Structure * Javadocs WHAT IS A RESTACTION?¶ If you understand RestAction you understand JDA. In JDA 3.0 we introduced the new RestAction class which basically is a terminal between the JDA user and the Discord REST API. The RestAction is a step between specifying what the user wants to do and executing it, it allows the user to specify how JDA should deal with their Request. However this only works if you actually tell the RestAction to do something. That is why we recommend checking out whether or not something in JDA returns a RestAction. If that is the case you have to execute it using one of the RestAction execution operations: queue(), queue(Consumer), queue(Consumer, Consumer) These operations are asynchronous and will not execute within the same Thread. This means that you cannot use procedural logic when you use queue(), unless you use the callback Consumers. Only similar requests are internally executed in sequence such as sending messages in the same channel or adding reactions to the same message. submit() Provides request future to cancel tasks later and avoid callback hell. complete() This operation will block the current Thread until the request has been finished and will return the response type. Note We recommend using queue() or submit() when possible as blocking the current Thread can cause downtime and will use more resources. Since 4.1.1 you can use a few RestAction operators to avoid callback hell with queue: * map Convert the result of the RestAction to a different value * flatMap Chain another RestAction on the result * delay Delay the element of the previous step JavaDocs: https://docs.jda.wiki/net/dv8tion/jda/api/requests/RestAction.html AUDITLOG REASONS¶ Some operations return a special RestAction implementation called AuditableRestAction. This extension allows to set a reason field for that action. Example public class ModerationUtil { public static void deleteMessage(Message message, String reason) { message.delete().reason(reason).queue(); } public static void ban(Guild guild, User user, String reason) { guild.ban(user, 7, reason).queue(); } } USING QUEUE()¶ The most common way to execute a RestAction is by simply calling .queue() after the operation: public void sendMessage(MessageChannel channel, String message) { channel.sendMessage(message).queue(); } This will always simply execute the RestAction<Message> which was returned by MessageChannel.sendMessage(String). Note that this might happen after calling sendMessage(MessageChannel, String) because queue() is asynchronous! > You: Why can't I access the Message that was sent with queue()? > Minn: Use the success callback! Is one of the common conversations we had when people started using JDA 3.0. > You: What does that mean? A success callback is what we call the primary Consumer that can be passed to a queue() statement: public void sendAndLog(MessageChannel channel, String message) { channel.sendMessage(message).queue(new Consumer<Message>() { @Override public void accept(Message t) { System.out.printf("Sent Message %s\n", t); } }); } Here we used an inline implementation of Consumer<Message> that handles the response of a REST Request. The method Consumer.accept(Message) is automatically called once the response has been received by the JDA Requester. > Minn: But that looks really ugly... > You: Yeah but it works!! Since JDA requires you to use Java 1.8 we can use one of the new features: Lambda Expressions public void sendAndLog(MessageChannel channel, String message) { // Here we use a lambda expressions which names the callback parameter -response- and uses that as a reference // in the callback body -System.out.printf("Sent Message %s\n", response)- Consumer<Message> callback = (response) -> System.out.printf("Sent Message %s\n", response); channel.sendMessage(message).queue(callback); // ^ calls that } > You: Wow that looks so much better! > Minn: Yes, please learn more about lambda expressions: lambda quickstart Example: Sending a Private Message public void sendPrivateMessage(User user, String content) { // openPrivateChannel provides a RestAction<PrivateChannel> // which means it supplies you with the resulting channel user.openPrivateChannel().queue((channel) -> { // value is a parameter for the `accept(T channel)` method of our callback. // here we implement the body of that method, which will be called later by JDA automatically. channel.sendMessage(content).queue(); // here we access the enclosing scope variable -content- // which was provided to sendPrivateMessage(User, String) as a parameter }); } Since this only calls a single method in the callback you can use the short form: public void sendPrivateMessage(User user, String content) { // notice that we are not placing a semicolon (;) in the callback this time! user.openPrivateChannel().queue( (channel) -> channel.sendMessage(content).queue() ); } USING SUBMIT()¶ Sometimes execution needs to be cancelled if it isn't required anymore. This can be challenging to do if you use queue() or complete(). In submit() JDA will provide a CompletableFuture (aka promise) which allows the cancellation of a request. If you don't need to use the CompletableFuture you may use queue() instead! Example public void setTestingChannel(TextChannel channel) { channel.getManager().setName("testing-channel").queue( (v) -> channel.sendMessage("Update Channel").queue( (m) -> m.delete().queueAfter(30, TimeUnit.SECONDS, (t) -> logChannel.sendMessage("Deleted Response in %s", channel).queue() ) ) ); } // turns into public void setTestingChannel(TextChannel channel) { channel.getManager().setName("testing-channel").submit() // CompletableFuture<Void> .thenCompose((v) -> channel.sendMessage("Update Channel").submit()) // CompletableFuture<Message> .thenCompose((m) -> m.delete().submitAfter(30, TimeUnit.SECONDS)) // CompletableFuture<Void> .thenCompose((v) -> logChannel.sendMessage("Deleted Response in %s", channel).submit()) .whenComplete((s, error) -> { // this will be called for every termination (success/failure) // if the result is successful the error will be null // otherwise you should handle the error here to prevent it from being eaten and never printed if (error != null) error.printStackTrace(); }); } Note You can do the same with RestAction#flatMap in 4.1.1 public class RateLimitListener extends ListenerAdapter { private final long guildId; private final long userId; private final Queue<RequestFuture<Void>> tasks = new LinkedList<>(); public RateLimitListener(Guild guild, User user) { guildId = guild.getIdLong(); userId = user.getIdLong(); // only store IDs as JDA objects can be disposed by cache invalidation //when disposed the entity is not usable anymore, since we only need the id this is good enough } @Override public void onGuildMessageReceived(GuildMessageReceivedEvent event) { if (event.getAuthor().getIdLong() != userId) return; // ignore other users if (event.getGuild().getIdLong() != guildId) return; // ignore other guilds RequestFuture<Void> task = event.getMessage().delete().submit(); tasks.add(task); // add task to cancel queue in case user gets banned task.thenRun(() -> tasks.remove(task)); // remove once completed } @Override public void onGuildBan(GuildBanEvent event) { if (event.getUser().getIdLong() != userId) return; // ignore other users if (event.getGuild().getIdLong() != guildId) return; // ignore other guilds // stop deleting messages for banned user RequestFuture<Void> current; while ((current = tasks.poll()) != null) current.cancel(true); tasks.clear(); // remove this as listener, our task has completed! event.getJDA().removeEventListener(this); } } USING COMPLETE()¶ The complete() operation is simply for your convenience. It will block the Thread that you call it on which means it will not be able to continue with other tasks in the meantime. If you don't use the return value or don't need the request to be completed before continuing with other operations it is recommended to use queue() instead! Example public void setTestingChannel(TextChannel channel) { channel.getManager().setName("testing-channel").queue( (v) -> channel.sendMessage("Update Channel").queue( (m) -> m.delete().queueAfter(30, TimeUnit.SECONDS, (t) -> logChannel.sendMessage("Deleted Response in %s", channel).queue() ) ) ); } public void setTestingChannelBlocking(TextChannel channel) { channel.getManager().setName("testing-channel").complete(); Message m = channel.sendMessage("Update Channel").complete(); m.delete().completeAfter(30, TimeUnit.SECONDS); logChannel.sendMessage("Deleted Response in %s", channel).queue(); // note how we used queue in the end because we don't need it sequenced anymore. } This is called a callback hell public Message sendAndLog(MessageChannel channel, String message) { Message response = channel.sendMessage(message).complete(); System.out.printf("Sent Message %s\n", response); return response; } public PermissionOverride getOverride(Channel channel, Member member) { final PermissionOverride override = channel.getPermissionOverride(member); if (override == null) return channel.createPermissionOverride(member).complete(); return override; } You can do this asynchronously by using a CompletableFuture: public CompletableFuture<PermissionOverride> getOverride(Channel channel, Member member) { final PermissionOverride override = channel.getPermissionOverride(member); if (override == null) return channel.createPermissionOverride(member).submit(); return CompletableFuture.completedFuture(override); } getOverride(channel, member).thenAccept(override -> ...); USING COMPLETEAFTER, SUBMITAFTER AND QUEUEAFTER¶ These three methods are also known under the term of Planned Execution as they use a ScheduledExecutorService to schedule calls to either complete or queue. There are three possible ways to plan a RestAction execution completeAfter(long, TimeUnit) Blocks and executes on the current Thread, similar to complete()! Similar to using Thread.join() this will block until the action has completed. submitAfter(long, TimeUnit), submitAfter(long, TimeUnit, ScheduledExecutorService) Creates a DelayedCompletableFuture<T> which will hold the response type as its generic value. This means using get() on the returned Future will cause the current thread to block and await the execution of the RestAction and receive the response type. queueAfter(long, TimeUnit), queueAfter(long, TimeUnit, Consumer<T>), queueAfter(long, TimeUnit, Consumer<T>, Consumer<Throwable>) Schedules the RestAction execution to be started after the specified delay, this will not block the thread and handle the execution in the background. You can optionally provide a ScheduledExecutorService to any of the queueAfter operations as the last argument. When no ScheduledExecutorService is provided, these operations will use the default internal JDA ScheduledExecutorService that is also used to execute queue callback consumers. Example completeAfter public Message waitForEdit(Message message) { return message.editMessage("5 Minutes are over").completeAfter(5, TimeUnit.MINUTES); } Example queueAfter public void remind(User user, String reminder, long delay, TimeUnit unit) { user.openPrivateChannel().queue( (channel) -> channel.sendMessage(reminder).queueAfter(delay, unit) ); } public void remindAlternate(User user, String reminder, long delay, TimeUnit unit) { user.openPrivateChannel().queueAfter(delay, unit, (channel) -> channel.sendMessage(reminder).queue() ); } Example submitAfter private Map<String, DelayedCompletableFuture<Message>> tasks = new HashMap<>(); public ScheduledFuture<Message> sendWithTask(MessageChannel channel, String message) { DelayedCompletable<Message> task = channel.sendMessage(message).submitAfter(5, TimeUnit.SECONDS); return task; } public void doSomething(MessageChannel channel, String message) throws Exception { tasks.add(channel.getId(), sendWithTask(channel, message)); for (DelayedCompletable<Message> task : tasks.values()) { // non-blocking alternative is `thenAccept` System.out.printf("Task completed: %s\n", task.get()); } } RESOURCES * Javadocs * GitHub (JDA) * GitHub (Wiki) * Discord API Docs COMMUNITY * Discord Server * Open Collective Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and Wiki Contributors