From 035b86920ade2c9916684484ec9d231717e018dc Mon Sep 17 00:00:00 2001
From: Rainnny7
Date: Sat, 6 Apr 2024 16:11:03 -0400
Subject: [PATCH] Add req/res transaction logging
---
.../java/me/braydon/mc/common/IPUtils.java | 44 ++++++++++
.../mc/controller/PlayerController.java | 2 +-
.../me/braydon/mc/log/TransactionLogger.java | 84 +++++++++++++++++++
src/main/java/me/braydon/mc/model/Skin.java | 7 ++
.../me/braydon/mc/service/MojangService.java | 19 +++--
5 files changed, 148 insertions(+), 8 deletions(-)
create mode 100644 src/main/java/me/braydon/mc/common/IPUtils.java
create mode 100644 src/main/java/me/braydon/mc/log/TransactionLogger.java
create mode 100644 src/main/java/me/braydon/mc/model/Skin.java
diff --git a/src/main/java/me/braydon/mc/common/IPUtils.java b/src/main/java/me/braydon/mc/common/IPUtils.java
new file mode 100644
index 0000000..a9037c4
--- /dev/null
+++ b/src/main/java/me/braydon/mc/common/IPUtils.java
@@ -0,0 +1,44 @@
+package me.braydon.mc.common;
+
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.NonNull;
+import lombok.experimental.UtilityClass;
+
+/**
+ * @author Braydon
+ */
+@UtilityClass
+public final class IPUtils {
+ private static final String[] IP_HEADERS = new String[] {
+ "CF-Connecting-IP",
+ "X-Forwarded-For"
+ };
+
+ /**
+ * Get the real IP from the given request.
+ *
+ * @param request the request
+ * @return the real IP
+ */
+ @NonNull
+ public static String getRealIp(@NonNull HttpServletRequest request) {
+ String ip = request.getRemoteAddr();
+ for (String headerName : IP_HEADERS) {
+ String header = request.getHeader(headerName);
+ if (header == null) {
+ continue;
+ }
+ if (!header.contains(",")) { // Handle single IP
+ ip = header;
+ break;
+ }
+ // Handle multiple IPs
+ String[] ips = header.split(",");
+ for (String ipHeader : ips) {
+ ip = ipHeader;
+ break;
+ }
+ }
+ return ip;
+ }
+}
diff --git a/src/main/java/me/braydon/mc/controller/PlayerController.java b/src/main/java/me/braydon/mc/controller/PlayerController.java
index 2ab7cf4..c332b10 100644
--- a/src/main/java/me/braydon/mc/controller/PlayerController.java
+++ b/src/main/java/me/braydon/mc/controller/PlayerController.java
@@ -42,6 +42,6 @@ public final class PlayerController {
@GetMapping("/{query}")
@ResponseBody
public ResponseEntity getPlayer(@PathVariable @NonNull String query) throws BadRequestException, ResourceNotFoundException {
- return ResponseEntity.ofNullable(mojangService.getPlayer(query));
+ return ResponseEntity.ofNullable(mojangService.getPlayer(query, false));
}
}
\ No newline at end of file
diff --git a/src/main/java/me/braydon/mc/log/TransactionLogger.java b/src/main/java/me/braydon/mc/log/TransactionLogger.java
new file mode 100644
index 0000000..7bd0eb2
--- /dev/null
+++ b/src/main/java/me/braydon/mc/log/TransactionLogger.java
@@ -0,0 +1,84 @@
+package me.braydon.mc.log;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
+import me.braydon.mc.common.IPUtils;
+import org.springframework.core.MethodParameter;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.http.server.ServletServerHttpRequest;
+import org.springframework.http.server.ServletServerHttpResponse;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
+
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * Responsible for logging request and
+ * response transactions to the terminal.
+ *
+ * @author Braydon
+ */
+@ControllerAdvice
+@Slf4j(topic = "Req/Res Transaction")
+public class TransactionLogger implements ResponseBodyAdvice
*
* @param query the query to search for the player by
+ * @param bypassCache should the cache be bypassed?
* @return the player
* @throws BadRequestException if the UUID is malformed
* @throws ResourceNotFoundException if the player is not found
*/
@NonNull
- public CachedPlayer getPlayer(@NonNull String query) throws BadRequestException, ResourceNotFoundException {
+ public CachedPlayer getPlayer(@NonNull String query, boolean bypassCache) throws BadRequestException, ResourceNotFoundException {
log.info("Requesting player with query: {}", query);
UUID uuid; // The player UUID to lookup
@@ -84,10 +85,12 @@ public final class MojangService {
}
// Check the cache for the player
- Optional cached = playerCache.findById(uuid);
- if (cached.isPresent()) { // Respond with the cache if present
- log.info("Found player in cache: {}", uuid);
- return cached.get();
+ if (!bypassCache) {
+ Optional cached = playerCache.findById(uuid);
+ if (cached.isPresent()) { // Respond with the cache if present
+ log.info("Found player in cache: {}", uuid);
+ return cached.get();
+ }
}
// Send a request to Mojang requesting
@@ -105,8 +108,10 @@ public final class MojangService {
profileActions.length == 0 ? null : profileActions,
System.currentTimeMillis()
);
- playerCache.save(player);
- log.info("Cached player: {}", uuid);
+ if (!bypassCache) { // Store in the cache
+ playerCache.save(player);
+ log.info("Cached player: {}", uuid);
+ }
player.setCached(-1L); // Set to -1 to indicate it's not cached in the response
return player;