Add caching mechanism and improve error handling for AuthService

Introduced a caching layer to reduce redundant login code requests to the server, improving performance and reducing load. Updated related code to ensure better error logging and clean up unused variables. Adjusted event handling in ProxyPlayerListener for improved execution order and ban message deserialization.
This commit is contained in:
Teriuihi 2025-05-24 00:48:30 +02:00
parent d928ea4b87
commit 6ef20f8fd6
3 changed files with 61 additions and 29 deletions

View File

@ -199,7 +199,7 @@ public final class Config {
YOUR_LOGIN_CODE = getString("messages.your-login-code", YOUR_LOGIN_CODE);
}
public static String LOGIN_CODE_ENDPOINT = "https://alttd.com/auth/get_login_code/<uuid>";
public static String LOGIN_CODE_ENDPOINT = "https://alttd.com/login/requestNewUserLogin/<uuid>";
public static String LOGIN_ENDPOINT = "https://alttd.com/login";
public static String SECRET = "";
private static void site() {
@ -207,7 +207,6 @@ public final class Config {
byte[] randomBytes = new byte[256];
new java.security.SecureRandom().nextBytes(randomBytes);
SECRET = java.util.Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes);
config.getNode("secret").setValue(SECRET);
}
SECRET = getString("secret", SECRET);
LOGIN_ENDPOINT = getString("login-endpoint", LOGIN_ENDPOINT);

View File

@ -2,6 +2,7 @@ package com.alttd.webinterface.listeners;
import com.alttd.webinterface.config.Config;
import com.alttd.webinterface.web_interact.AuthService;
import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.ResultedEvent;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.LoginEvent;
@ -9,6 +10,7 @@ import com.velocitypowered.api.proxy.Player;
import litebans.api.Database;
import litebans.api.Entry;
import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
@ -26,7 +28,7 @@ public class ProxyPlayerListener {
public ProxyPlayerListener() {
}
@Subscribe
@Subscribe(order = PostOrder.FIRST)
public void playerLogin(@NotNull LoginEvent event) {
final Player player = event.getPlayer();
final UUID uuid = player.getUniqueId();
@ -43,18 +45,17 @@ public class ProxyPlayerListener {
String displayMessage = ban.isPermanent() ? Config.PERM_BAN : Config.TEMP_BAN;
try {
miniMessage.deserialize(displayMessage, TagResolver.resolver(
Component displayComponent = miniMessage.deserialize(displayMessage, TagResolver.resolver(
Placeholder.component("base", miniMessage.deserialize(Config.BASE_MESSAGE, resolveBase(ban))),
Placeholder.component("appeal_message", miniMessage.deserialize(Config.APPEAL_MESSAGE,
resolveAppealMessage(uuid))),
Placeholder.unparsed("duration", Instant.ofEpochMilli(ban.getDateEnd()).toString())));
event.setResult(ResultedEvent.ComponentResult.denied(displayComponent));
} catch (IllegalStateException e) {
log.error("Failed to deserialize ban message", e);
event.setResult(ResultedEvent.ComponentResult.denied(miniMessage.deserialize(
"<red>Unable to display punishment and appeal code, please contact us via email at appeal@alttd.com</red>")));
return;
}
event.setResult(ResultedEvent.ComponentResult.denied(miniMessage.deserialize(ban.getReason())));
}
private static @NotNull TagResolver resolveAppealMessage(UUID uuid) {

View File

@ -4,6 +4,7 @@ import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Instant;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@ -12,8 +13,13 @@ import com.alttd.webinterface.config.Config;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Slf4j
public class AuthService {
private static final Map<UUID, CacheEntry> cache = new ConcurrentHashMap<>();
/**
* Asynchronously sends a GET request to the login endpoint with the required authorization header.
@ -23,31 +29,57 @@ public class AuthService {
* or an empty Optional otherwise
*/
public static @NotNull CompletableFuture<Optional<String>> getLoginCodeAsync(UUID uuid) {
String loginUrl = Config.LOGIN_CODE_ENDPOINT.replaceAll("<uuid>", uuid.toString());
try (HttpClient client = HttpClient.newHttpClient()) {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(loginUrl))
.header("Authorization", "SECRET " + Config.SECRET)
.GET()
.build();
return client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(response -> {
if (response.statusCode() == 200) {
String body = response.body();
return Optional.ofNullable(body);
} else {
log.error("Failed to get login code. Status code: {}", response.statusCode());
return Optional.<String>empty();
}
})
.exceptionally(e -> {
log.error("Exception occurred while getting login code", e);
return Optional.empty();
});
Optional<String> cachedCode = getCachedCode(uuid);
if (cachedCode.isPresent()) {
return CompletableFuture.completedFuture(cachedCode);
}
String loginUrl = Config.LOGIN_CODE_ENDPOINT.replaceAll("<uuid>", uuid.toString());
log.info("Contacting server for login code at {}", loginUrl);
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(loginUrl))
.header("Authorization", "SECRET " + Config.SECRET)
.GET()
.build();
log.info("Created request");
return client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(response -> {
log.info("received response");
if (response.statusCode() == 200) {
String body = response.body();
cache.put(uuid, new CacheEntry(body, Instant.now().plusSeconds(TimeUnit.MINUTES.toSeconds(10))));
client.close();
return Optional.ofNullable(body);
} else {
log.error("Failed to get login code. Status code: {}", response.statusCode());
client.close();
return Optional.<String>empty();
}
})
.exceptionally(e -> {
log.error("Exception occurred while getting login code", e);
client.close();
return Optional.empty();
});
}
private static Optional<String> getCachedCode(UUID uuid) {
CacheEntry cachedEntry = cache.get(uuid);
if (cachedEntry != null) {
if (cachedEntry.expiry.isAfter(Instant.now())) {
return Optional.of(cachedEntry.code);
}
if (cachedEntry.expiry.isBefore(Instant.now())) {
cache.remove(uuid);
}
}
return Optional.empty();
}
private record CacheEntry(String code, Instant expiry) { }
}