add rate limit handler
All checks were successful
Deploy to Dokku / docker (ubuntu-latest) (push) Successful in 34s
All checks were successful
Deploy to Dokku / docker (ubuntu-latest) (push) Successful in 34s
This commit is contained in:
parent
6b11a608bd
commit
49e223a8b9
90
src/main/java/cc/fascinated/common/Request.java
Normal file
90
src/main/java/cc/fascinated/common/Request.java
Normal file
@ -0,0 +1,90 @@
|
||||
package cc.fascinated.common;
|
||||
|
||||
import kong.unirest.core.Headers;
|
||||
import kong.unirest.core.HttpResponse;
|
||||
import kong.unirest.core.Unirest;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Log4j2(topic = "Request")
|
||||
public class Request {
|
||||
/**
|
||||
* The rate limit headers.
|
||||
*/
|
||||
private static final List<String> rateLimitHeaders = List.of(
|
||||
"X-RateLimit-Remaining",
|
||||
"RateLimit-Remaining"
|
||||
);
|
||||
|
||||
/**
|
||||
* The rate limit reset headers.
|
||||
*/
|
||||
private static final List<String> rateLimitResetHeaders = List.of(
|
||||
"X-RateLimit-Reset",
|
||||
"RateLimit-Reset"
|
||||
);
|
||||
|
||||
/**
|
||||
* Sends a GET request to a URL.
|
||||
*
|
||||
* @param url the URL to send the request to
|
||||
* @param clazz the class to parse the response to
|
||||
* @param <T> the type of the response
|
||||
* @return the response
|
||||
*/
|
||||
public static <T> HttpResponse<T> get(String url, Class<T> clazz) {
|
||||
HttpResponse<T> response = Unirest.get(url).asObject(clazz);
|
||||
int rateLimitRemaining = getRateLimitRemaining(response);
|
||||
if (rateLimitRemaining == 0) {
|
||||
long rateLimitReset = getRateLimitReset(response);
|
||||
long timeLeft = rateLimitReset - System.currentTimeMillis();
|
||||
try {
|
||||
Thread.sleep(timeLeft);
|
||||
} catch (InterruptedException e) {
|
||||
log.error("Failed to sleep for rate limit reset", e);
|
||||
}
|
||||
response = Unirest.get(url).asObject(clazz);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rate limit remaining.
|
||||
*
|
||||
* @param response the response to get the rate limit remaining from
|
||||
* @return the rate limit remaining
|
||||
*/
|
||||
public static int getRateLimitRemaining(HttpResponse<?> response) {
|
||||
Headers headers = response.getHeaders();
|
||||
for (String rateLimitHeader : rateLimitHeaders) {
|
||||
if (headers.containsKey(rateLimitHeader)) {
|
||||
return Integer.parseInt(headers.getFirst(rateLimitHeader));
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rate limit reset absolute time.
|
||||
*
|
||||
* @param response the response to get the rate limit reset time from
|
||||
* @return the rate limit reset time
|
||||
*/
|
||||
public static long getRateLimitReset(HttpResponse<?> response) {
|
||||
Headers headers = response.getHeaders();
|
||||
for (String rateLimitResetHeader : rateLimitResetHeaders) {
|
||||
if (headers.containsKey(rateLimitResetHeader)) {
|
||||
long reset = Long.parseLong(headers.getFirst(rateLimitResetHeader));
|
||||
if (reset < 86400) {// Assume it's in seconds left
|
||||
return System.currentTimeMillis() + reset * 1000;
|
||||
}
|
||||
return reset * 1000; // Assume it's in seconds
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
@ -30,7 +30,7 @@ public class ScoreSaberPlatform extends Platform {
|
||||
/**
|
||||
* Delay in ms for requests per minute.
|
||||
*/
|
||||
private static final long UPDATE_DELAY = 1000L / 250L; // 250 requests per minute
|
||||
private static final long UPDATE_DELAY = 1000L / 150L; // 150 requests per minute
|
||||
|
||||
/**
|
||||
* The base multiplier for stars.
|
||||
|
@ -1,5 +1,6 @@
|
||||
package cc.fascinated.services;
|
||||
|
||||
import cc.fascinated.common.Request;
|
||||
import cc.fascinated.exception.impl.BadRequestException;
|
||||
import cc.fascinated.model.token.ScoreSaberAccountToken;
|
||||
import cc.fascinated.model.token.ScoreSaberLeaderboardToken;
|
||||
@ -45,8 +46,7 @@ public class ScoreSaberService {
|
||||
throw new BadRequestException("%s does not have a linked ScoreSaber account".formatted(user.getUsername()));
|
||||
}
|
||||
|
||||
HttpResponse<ScoreSaberAccountToken> response = Unirest.get(GET_PLAYER_ENDPOINT.formatted(user.getSteamId()))
|
||||
.asObject(ScoreSaberAccountToken.class);
|
||||
HttpResponse<ScoreSaberAccountToken> response = Request.get(GET_PLAYER_ENDPOINT.formatted(user.getSteamId()), ScoreSaberAccountToken.class);
|
||||
if (response.getParsingError().isPresent()) { // Failed to parse the response
|
||||
throw new BadRequestException("Failed to parse ScoreSaber account for '%s'".formatted(user.getUsername()));
|
||||
}
|
||||
@ -69,8 +69,7 @@ public class ScoreSaberService {
|
||||
return leaderboardOptional.get();
|
||||
}
|
||||
|
||||
HttpResponse<ScoreSaberLeaderboardToken> response = Unirest.get(GET_LEADERBOARD_ENDPOINT.formatted(leaderboardId))
|
||||
.asObject(ScoreSaberLeaderboardToken.class);
|
||||
HttpResponse<ScoreSaberLeaderboardToken> response = Request.get(GET_LEADERBOARD_ENDPOINT.formatted(leaderboardId), ScoreSaberLeaderboardToken.class);
|
||||
if (response.getParsingError().isPresent()) { // Failed to parse the response
|
||||
throw new BadRequestException("Failed to parse ScoreSaber leaderboard for '%s'".formatted(leaderboardId));
|
||||
}
|
||||
|
Reference in New Issue
Block a user