Skip to content

Commit

Permalink
Add rate-limiter customization (#2307)
Browse files Browse the repository at this point in the history
* Add RestConfig
* Move Route into api package
* Remove some unused routes
* Move URI encoding into compile and withQueryParams
* Add docs for Route
* Expose major parameter names as list constant
* Remove unused client only fields in SelfUser
* Handle global rate-limit bypass
* Split buckets into 2 types
* Improve handling of global rate-limits
* Call cleanup on shutdown
  • Loading branch information
MinnDevelopment committed Mar 24, 2023
1 parent 42a040d commit cec8035
Show file tree
Hide file tree
Showing 107 changed files with 1,997 additions and 1,022 deletions.
2 changes: 1 addition & 1 deletion src/main/java/net/dv8tion/jda/api/JDA.java
Expand Up @@ -33,6 +33,7 @@
import net.dv8tion.jda.api.managers.Presence;
import net.dv8tion.jda.api.requests.GatewayIntent;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.Route;
import net.dv8tion.jda.api.requests.restaction.*;
import net.dv8tion.jda.api.sharding.ShardManager;
import net.dv8tion.jda.api.utils.MiscUtil;
Expand All @@ -42,7 +43,6 @@
import net.dv8tion.jda.internal.interactions.CommandDataImpl;
import net.dv8tion.jda.internal.requests.CompletedRestAction;
import net.dv8tion.jda.internal.requests.RestActionImpl;
import net.dv8tion.jda.internal.requests.Route;
import net.dv8tion.jda.internal.utils.Checks;
import net.dv8tion.jda.internal.utils.EntityString;
import net.dv8tion.jda.internal.utils.Helpers;
Expand Down
33 changes: 29 additions & 4 deletions src/main/java/net/dv8tion/jda/api/JDABuilder.java
Expand Up @@ -16,15 +16,18 @@
package net.dv8tion.jda.api;

import com.neovisionaries.ws.client.WebSocketFactory;
import net.dv8tion.jda.annotations.ForRemoval;
import net.dv8tion.jda.annotations.ReplaceWith;
import net.dv8tion.jda.api.audio.factory.IAudioSendFactory;
import net.dv8tion.jda.api.entities.Activity;
import net.dv8tion.jda.api.events.Event;
import net.dv8tion.jda.api.exceptions.InvalidTokenException;
import net.dv8tion.jda.api.events.session.ReadyEvent;
import net.dv8tion.jda.api.exceptions.InvalidTokenException;
import net.dv8tion.jda.api.hooks.IEventManager;
import net.dv8tion.jda.api.hooks.VoiceDispatchInterceptor;
import net.dv8tion.jda.api.requests.GatewayIntent;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.RestConfig;
import net.dv8tion.jda.api.utils.*;
import net.dv8tion.jda.api.utils.cache.CacheFlag;
import net.dv8tion.jda.internal.JDAImpl;
Expand Down Expand Up @@ -93,6 +96,7 @@ public class JDABuilder
protected ChunkingFilter chunkingFilter = ChunkingFilter.ALL;
protected MemberCachePolicy memberCachePolicy = MemberCachePolicy.ALL;
protected GatewayEncoding encoding = GatewayEncoding.JSON;
protected RestConfig restConfig = new RestConfig();

private JDABuilder(@Nullable String token, int intents)
{
Expand Down Expand Up @@ -557,15 +561,36 @@ public JDABuilder setEventPassthrough(boolean enable)
* True, if the relative {@code X-RateLimit-Reset-After} header should be used.
*
* @return The JDABuilder instance. Useful for chaining.
*
* @since 4.1.0
*/
@Nonnull
@Deprecated
@ForRemoval(deadline = "5.1.0")
@ReplaceWith("setRestConfig(new RestConfig().setRelativeRateLimit(enable))")
public JDABuilder setRelativeRateLimit(boolean enable)
{
return setFlag(ConfigFlag.USE_RELATIVE_RATELIMIT, enable);
}

/**
* Custom {@link RestConfig} to use for this JDA instance.
* <br>This can be used to customize how rate-limits are handled and configure a custom http proxy.
*
* @param config
* The {@link RestConfig} to use
*
* @throws IllegalArgumentException
* If null is provided
*
* @return The JDABuilder instance. Useful for chaining.
*/
@Nonnull
public JDABuilder setRestConfig(@Nonnull RestConfig config)
{
Checks.notNull(config, "RestConfig");
this.restConfig = config;
return this;
}

/**
* Enable specific cache flags.
* <br>This will not disable any currently set cache flags.
Expand Down Expand Up @@ -1778,7 +1803,7 @@ public JDA build()
SessionConfig sessionConfig = new SessionConfig(controller, httpClient, wsFactory, voiceDispatchInterceptor, flags, maxReconnectDelay, largeThreshold);
MetaConfig metaConfig = new MetaConfig(maxBufferSize, contextMap, cacheFlags, flags);

JDAImpl jda = new JDAImpl(authConfig, sessionConfig, threadingConfig, metaConfig);
JDAImpl jda = new JDAImpl(authConfig, sessionConfig, threadingConfig, metaConfig, restConfig);
jda.setMemberCachePolicy(memberCachePolicy);
// We can only do member chunking with the GUILD_MEMBERS intent
if ((intents & GatewayIntent.GUILD_MEMBERS.getRawValue()) == 0)
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/net/dv8tion/jda/api/entities/Message.java
Expand Up @@ -42,6 +42,7 @@
import net.dv8tion.jda.api.interactions.components.LayoutComponent;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.RestConfig;
import net.dv8tion.jda.api.requests.restaction.AuditableRestAction;
import net.dv8tion.jda.api.requests.restaction.MessageCreateAction;
import net.dv8tion.jda.api.requests.restaction.MessageEditAction;
Expand All @@ -57,7 +58,6 @@
import net.dv8tion.jda.internal.JDAImpl;
import net.dv8tion.jda.internal.entities.ReceivedMessage;
import net.dv8tion.jda.internal.requests.FunctionalCallback;
import net.dv8tion.jda.internal.requests.Requester;
import net.dv8tion.jda.internal.utils.Checks;
import net.dv8tion.jda.internal.utils.IOUtil;
import okhttp3.MultipartBody;
Expand Down Expand Up @@ -2608,7 +2608,7 @@ protected Request getRequest()
{
return new Request.Builder()
.url(getUrl())
.addHeader("user-agent", Requester.USER_AGENT)
.addHeader("user-agent", RestConfig.USER_AGENT)
.addHeader("accept-encoding", "gzip, deflate")
.build();
}
Expand Down
Expand Up @@ -25,14 +25,14 @@
import net.dv8tion.jda.api.requests.Request;
import net.dv8tion.jda.api.requests.Response;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.Route;
import net.dv8tion.jda.api.utils.MiscUtil;
import net.dv8tion.jda.api.utils.TimeUtil;
import net.dv8tion.jda.api.utils.data.DataArray;
import net.dv8tion.jda.api.utils.data.DataObject;
import net.dv8tion.jda.internal.JDAImpl;
import net.dv8tion.jda.internal.entities.EntityBuilder;
import net.dv8tion.jda.internal.requests.RestActionImpl;
import net.dv8tion.jda.internal.requests.Route;
import net.dv8tion.jda.internal.utils.Checks;
import net.dv8tion.jda.internal.utils.JDALogger;
import org.apache.commons.collections4.map.ListOrderedMap;
Expand Down
Expand Up @@ -30,12 +30,11 @@
import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
import net.dv8tion.jda.api.exceptions.PermissionException;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.Route;
import net.dv8tion.jda.api.requests.restaction.pagination.ReactionPaginationAction;
import net.dv8tion.jda.internal.requests.RestActionImpl;
import net.dv8tion.jda.internal.requests.Route;
import net.dv8tion.jda.internal.requests.restaction.pagination.ReactionPaginationActionImpl;
import net.dv8tion.jda.internal.utils.Checks;
import net.dv8tion.jda.internal.utils.EncodingUtil;
import net.dv8tion.jda.internal.utils.EntityString;

import javax.annotation.CheckReturnValue;
Expand Down Expand Up @@ -340,7 +339,7 @@ public RestAction<Void> removeReaction(@Nonnull User user)
throw new InsufficientPermissionException(guildChannel, Permission.MESSAGE_MANAGE);
}

String code = EncodingUtil.encodeReaction(emoji.getAsReactionCode());
String code = emoji.getAsReactionCode();
String target = self ? "@me" : user.getId();
Route.CompiledRoute route = Route.Messages.REMOVE_REACTION.compile(channel.getId(), getMessageId(), code, target);
return new RestActionImpl<>(getJDA(), route);
Expand Down
Expand Up @@ -23,10 +23,10 @@
import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion;
import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.Route;
import net.dv8tion.jda.internal.JDAImpl;
import net.dv8tion.jda.internal.requests.CompletedRestAction;
import net.dv8tion.jda.internal.requests.RestActionImpl;
import net.dv8tion.jda.internal.requests.Route;
import net.dv8tion.jda.internal.utils.Checks;

import javax.annotation.Nonnull;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/net/dv8tion/jda/api/entities/Webhook.java
Expand Up @@ -22,9 +22,9 @@
import net.dv8tion.jda.api.entities.channel.unions.IWebhookContainerUnion;
import net.dv8tion.jda.api.managers.WebhookManager;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.Route;
import net.dv8tion.jda.api.requests.restaction.AuditableRestAction;
import net.dv8tion.jda.internal.requests.RestActionImpl;
import net.dv8tion.jda.internal.requests.Route;

import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnull;
Expand Down
Expand Up @@ -23,9 +23,9 @@
import net.dv8tion.jda.api.exceptions.MissingAccessException;
import net.dv8tion.jda.api.managers.channel.concrete.NewsChannelManager;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.Route;
import net.dv8tion.jda.api.requests.restaction.ChannelAction;
import net.dv8tion.jda.internal.requests.RestActionImpl;
import net.dv8tion.jda.internal.requests.Route;
import net.dv8tion.jda.internal.utils.Checks;

import javax.annotation.CheckReturnValue;
Expand Down
Expand Up @@ -31,6 +31,7 @@
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.interactions.components.selections.SelectMenu;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.Route;
import net.dv8tion.jda.api.requests.restaction.AuditableRestAction;
import net.dv8tion.jda.api.requests.restaction.MessageCreateAction;
import net.dv8tion.jda.api.requests.restaction.MessageEditAction;
Expand All @@ -46,14 +47,12 @@
import net.dv8tion.jda.internal.JDAImpl;
import net.dv8tion.jda.internal.entities.EntityBuilder;
import net.dv8tion.jda.internal.requests.RestActionImpl;
import net.dv8tion.jda.internal.requests.Route;
import net.dv8tion.jda.internal.requests.restaction.AuditableRestActionImpl;
import net.dv8tion.jda.internal.requests.restaction.MessageCreateActionImpl;
import net.dv8tion.jda.internal.requests.restaction.MessageEditActionImpl;
import net.dv8tion.jda.internal.requests.restaction.pagination.MessagePaginationActionImpl;
import net.dv8tion.jda.internal.requests.restaction.pagination.ReactionPaginationActionImpl;
import net.dv8tion.jda.internal.utils.Checks;
import net.dv8tion.jda.internal.utils.EncodingUtil;

import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnull;
Expand Down Expand Up @@ -1672,8 +1671,7 @@ default RestAction<Void> addReactionById(@Nonnull String messageId, @Nonnull Emo
Checks.isSnowflake(messageId, "Message ID");
Checks.notNull(emoji, "Emoji");

String encoded = EncodingUtil.encodeReaction(emoji.getAsReactionCode());
Route.CompiledRoute route = Route.Messages.ADD_REACTION.compile(getId(), messageId, encoded, "@me");
Route.CompiledRoute route = Route.Messages.ADD_REACTION.compile(getId(), messageId, emoji.getAsReactionCode(), "@me");
return new RestActionImpl<>(getJDA(), route);
}

Expand Down Expand Up @@ -1782,8 +1780,7 @@ default RestAction<Void> removeReactionById(@Nonnull String messageId, @Nonnull
Checks.isSnowflake(messageId, "Message ID");
Checks.notNull(emoji, "Emoji");

String encoded = EncodingUtil.encodeReaction(emoji.getAsReactionCode());
Route.CompiledRoute route = Route.Messages.REMOVE_REACTION.compile(getId(), messageId, encoded, "@me");
Route.CompiledRoute route = Route.Messages.REMOVE_REACTION.compile(getId(), messageId, emoji.getAsReactionCode(), "@me");
return new RestActionImpl<>(getJDA(), route);
}

Expand Down Expand Up @@ -1882,7 +1879,7 @@ default ReactionPaginationAction retrieveReactionUsersById(@Nonnull String messa
Checks.isSnowflake(messageId, "Message ID");
Checks.notNull(emoji, "Emoji");

return new ReactionPaginationActionImpl(this, messageId, EncodingUtil.encodeReaction(emoji.getAsReactionCode()));
return new ReactionPaginationActionImpl(this, messageId, emoji.getAsReactionCode());
}

/**
Expand Down
Expand Up @@ -22,10 +22,10 @@
import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
import net.dv8tion.jda.api.managers.TemplateManager;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.Route;
import net.dv8tion.jda.internal.JDAImpl;
import net.dv8tion.jda.internal.managers.TemplateManagerImpl;
import net.dv8tion.jda.internal.requests.RestActionImpl;
import net.dv8tion.jda.internal.requests.Route;
import net.dv8tion.jda.internal.utils.Checks;
import net.dv8tion.jda.internal.utils.EntityString;

Expand Down
Expand Up @@ -20,9 +20,9 @@
import net.dv8tion.jda.api.requests.Request;
import net.dv8tion.jda.api.requests.Response;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.Route.CompiledRoute;
import net.dv8tion.jda.api.utils.data.DataArray;
import net.dv8tion.jda.api.utils.data.DataObject;
import net.dv8tion.jda.internal.requests.Route.CompiledRoute;
import okhttp3.Headers;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
Expand Down
Expand Up @@ -14,8 +14,18 @@
* limitations under the License.
*/

package net.dv8tion.jda.api.exceptions;

import net.dv8tion.jda.api.interactions.InteractionHook;

/**
* Implementations of {@link net.dv8tion.jda.internal.requests.RateLimiter RateLimiter}
* that handle the rate limit responses for the {@link net.dv8tion.jda.internal.requests.Requester Requester}!
* Indicates that an interaction has expired and can no longer be responded to.
* <br>This is used for follow-up requests sent via {@link InteractionHook}, which expire after 15 minutes.
*/
package net.dv8tion.jda.internal.requests.ratelimit;
public class InteractionExpiredException extends RuntimeException
{
public InteractionExpiredException()
{
super("The interaction has expired and can no longer be responded to!");
}
}
Expand Up @@ -16,7 +16,7 @@

package net.dv8tion.jda.api.exceptions;

import net.dv8tion.jda.internal.requests.Route;
import net.dv8tion.jda.api.requests.Route;
import net.dv8tion.jda.internal.utils.Helpers;

/**
Expand Down
Expand Up @@ -14,8 +14,11 @@
* limitations under the License.
*/

package net.dv8tion.jda.internal.requests;
package net.dv8tion.jda.api.requests;

/**
* Enum used to specify the HTTP method to use for a request.
*/
public enum Method
{
DELETE,
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/net/dv8tion/jda/api/requests/Request.java
Expand Up @@ -25,7 +25,6 @@
import net.dv8tion.jda.internal.JDAImpl;
import net.dv8tion.jda.internal.requests.CallbackContext;
import net.dv8tion.jda.internal.requests.RestActionImpl;
import net.dv8tion.jda.internal.requests.Route;
import net.dv8tion.jda.internal.utils.IOUtil;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
Expand Down Expand Up @@ -269,6 +268,8 @@ public boolean shouldQueue()

public void cancel()
{
if (!this.isCancelled)
onCancelled();
this.isCancelled = true;
}

Expand Down

0 comments on commit cec8035

Please sign in to comment.