diff --git a/api/src/main/java/com/javadiscord/jdi/RateLimit.java b/api/src/main/java/com/javadiscord/jdi/RateLimit.java new file mode 100644 index 00000000..11ac692a --- /dev/null +++ b/api/src/main/java/com/javadiscord/jdi/RateLimit.java @@ -0,0 +1,60 @@ +package com.javadiscord.jdi; + +public class RateLimit { + private String bucket; + private int limit; + private int remaining; + private long reset; + private int resetAfter; + private boolean globalRateLimit; + + public RateLimit() {} + + public String getBucket() { + return bucket; + } + + public void setBucket(String bucket) { + this.bucket = bucket; + } + + public int getLimit() { + return limit; + } + + public void setLimit(int limit) { + this.limit = limit; + } + + public int getRemaining() { + return remaining; + } + + public void setRemaining(int remaining) { + this.remaining = remaining; + } + + public long getReset() { + return reset; + } + + public void setReset(long reset) { + this.reset = reset; + } + + public int getResetAfter() { + return resetAfter; + } + + public void setResetAfter(int resetAfter) { + this.resetAfter = resetAfter; + } + + public boolean isGlobalRateLimit() { + return globalRateLimit; + } + + public void setGlobalRateLimit(boolean globalRateLimit) { + this.globalRateLimit = globalRateLimit; + } +} diff --git a/api/src/main/java/com/javadiscord/jdi/internal/api/DiscordRequestDispatcher.java b/api/src/main/java/com/javadiscord/jdi/internal/api/DiscordRequestDispatcher.java index 3677b791..86d8e622 100644 --- a/api/src/main/java/com/javadiscord/jdi/internal/api/DiscordRequestDispatcher.java +++ b/api/src/main/java/com/javadiscord/jdi/internal/api/DiscordRequestDispatcher.java @@ -2,6 +2,7 @@ import java.net.URI; import java.net.http.HttpClient; +import java.net.http.HttpHeaders; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.util.Map; @@ -10,6 +11,8 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Stream; +import com.javadiscord.jdi.RateLimit; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -27,6 +30,8 @@ public class DiscordRequestDispatcher implements Runnable { private int numberOfRequestsSent; private long timeSinceLastRequest; + private RateLimit rateLimit = new RateLimit(); + public DiscordRequestDispatcher(String botToken) { this.botToken = botToken; this.httpClient = HttpClient.newBuilder().build(); @@ -51,6 +56,14 @@ public void run() { long currentTime = System.currentTimeMillis(); long elapsed = currentTime - timeSinceLastRequest; + if (rateLimit.getRemaining() == 0 && elapsed < rateLimit.getResetAfter()) { + try { + Thread.sleep(rateLimit.getResetAfter() - elapsed); + } catch (InterruptedException e) { + /* Ignore */ + } + } + if (elapsed < 1000 && numberOfRequestsSent >= 50) { try { Thread.sleep(1000 - elapsed); @@ -119,6 +132,17 @@ private void sendRequest(DiscordRequestBuilder discordRequestBuilder) { HttpResponse response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); + HttpHeaders headers = response.headers(); + headers.firstValue("x-ratelimit-bucket").ifPresent(val -> rateLimit.setBucket(val)); + headers.firstValue("x-ratelimit-limit") + .ifPresent(val -> rateLimit.setLimit(Integer.parseInt(val))); + headers.firstValue("x-ratelimit-remaining") + .ifPresent(val -> rateLimit.setRemaining(Integer.parseInt(val))); + headers.firstValue("x-ratelimit-reset") + .ifPresent(val -> rateLimit.setReset(Long.parseLong(val))); + headers.firstValue("x-ratelimit-reset-after") + .ifPresent(val -> rateLimit.setResetAfter(Integer.parseInt(val))); + numberOfRequestsSent++; timeSinceLastRequest = System.currentTimeMillis(); diff --git a/gateway/src/main/java/com/javadiscord/jdi/internal/gateway/Gateway.java b/gateway/src/main/java/com/javadiscord/jdi/internal/gateway/Gateway.java index b1baad35..75493c22 100644 --- a/gateway/src/main/java/com/javadiscord/jdi/internal/gateway/Gateway.java +++ b/gateway/src/main/java/com/javadiscord/jdi/internal/gateway/Gateway.java @@ -5,7 +5,7 @@ @JsonIgnoreProperties(ignoreUnknown = true) public record Gateway( - String url, - int shards, + @JsonProperty("url") String url, + @JsonProperty("shards") int shards, @JsonProperty("session_start_limit") SessionStartLimit sessionStartLimit ) {} diff --git a/gateway/src/main/java/com/javadiscord/jdi/internal/gateway/SessionStartLimit.java b/gateway/src/main/java/com/javadiscord/jdi/internal/gateway/SessionStartLimit.java index 58f3459e..8b06d492 100644 --- a/gateway/src/main/java/com/javadiscord/jdi/internal/gateway/SessionStartLimit.java +++ b/gateway/src/main/java/com/javadiscord/jdi/internal/gateway/SessionStartLimit.java @@ -5,8 +5,8 @@ @JsonIgnoreProperties(ignoreUnknown = true) public record SessionStartLimit( - int total, - int remaining, + @JsonProperty("total") int total, + @JsonProperty("remaining") int remaining, @JsonProperty("reset_after") long resetAfter, @JsonProperty("max_concurrency") int maxConcurrency ) {} diff --git a/gateway/src/main/java/com/javadiscord/jdi/internal/gateway/WebSocketManagerProxy.java b/gateway/src/main/java/com/javadiscord/jdi/internal/gateway/WebSocketManagerProxy.java index 7e0b0791..5a37fa61 100644 --- a/gateway/src/main/java/com/javadiscord/jdi/internal/gateway/WebSocketManagerProxy.java +++ b/gateway/src/main/java/com/javadiscord/jdi/internal/gateway/WebSocketManagerProxy.java @@ -14,7 +14,6 @@ public void start(ConnectionMediator connectionMediator) { } public void restart(ConnectionMediator connectionMediator) { - webSocketManager.restart(connectionMediator); }