diff --git a/src/main/java/me/braydon/mc/model/Player.java b/src/main/java/me/braydon/mc/model/Player.java
index 5bc7425..c538897 100644
--- a/src/main/java/me/braydon/mc/model/Player.java
+++ b/src/main/java/me/braydon/mc/model/Player.java
@@ -2,7 +2,6 @@ package me.braydon.mc.model;
import lombok.*;
import org.springframework.data.annotation.Id;
-import org.springframework.data.redis.core.RedisHash;
import java.util.UUID;
@@ -16,7 +15,6 @@ import java.util.UUID;
@Setter @Getter
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@ToString
-@RedisHash(value = "player", timeToLive = 60L * 60L) // 1 hour (in seconds)
public class Player {
/**
* The unique id of this player.
diff --git a/src/main/java/me/braydon/mc/model/cache/CachedPlayer.java b/src/main/java/me/braydon/mc/model/cache/CachedPlayer.java
index 20538e2..c38ad51 100644
--- a/src/main/java/me/braydon/mc/model/cache/CachedPlayer.java
+++ b/src/main/java/me/braydon/mc/model/cache/CachedPlayer.java
@@ -3,8 +3,10 @@ package me.braydon.mc.model.cache;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
+import lombok.ToString;
import me.braydon.mc.model.Player;
import me.braydon.mc.model.ProfileAction;
+import org.springframework.data.redis.core.RedisHash;
import java.io.Serializable;
import java.util.UUID;
@@ -15,6 +17,8 @@ import java.util.UUID;
* @author Braydon
*/
@Setter @Getter
+@ToString(callSuper = true)
+@RedisHash(value = "player", timeToLive = 60L * 60L) // 1 hour (in seconds)
public final class CachedPlayer extends Player implements Serializable {
/**
* The unix timestamp of when this
diff --git a/src/main/java/me/braydon/mc/model/cache/CachedPlayerName.java b/src/main/java/me/braydon/mc/model/cache/CachedPlayerName.java
new file mode 100644
index 0000000..307a777
--- /dev/null
+++ b/src/main/java/me/braydon/mc/model/cache/CachedPlayerName.java
@@ -0,0 +1,27 @@
+package me.braydon.mc.model.cache;
+
+import lombok.*;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.redis.core.RedisHash;
+
+import java.util.UUID;
+
+/**
+ * @author Braydon
+ */
+@AllArgsConstructor
+@Getter
+@EqualsAndHashCode(onlyExplicitlyIncluded = true)
+@ToString
+@RedisHash(value = "playerName", timeToLive = 60L * 60L) // 1 hour (in seconds)
+public final class CachedPlayerName {
+ /**
+ * The username of the player.
+ */
+ @Id @NonNull private String username;
+
+ /**
+ * The unique id of the player.
+ */
+ @NonNull private UUID uniqueId;
+}
\ No newline at end of file
diff --git a/src/main/java/me/braydon/mc/repository/PlayerNameCacheRepository.java b/src/main/java/me/braydon/mc/repository/PlayerNameCacheRepository.java
new file mode 100644
index 0000000..52c4a2e
--- /dev/null
+++ b/src/main/java/me/braydon/mc/repository/PlayerNameCacheRepository.java
@@ -0,0 +1,15 @@
+package me.braydon.mc.repository;
+
+import me.braydon.mc.model.cache.CachedPlayerName;
+import org.springframework.data.repository.CrudRepository;
+
+/**
+ * A cache repository for player usernames.
+ *
+ * This will allow us to easily lookup a
+ * player's username and get their uuid.
+ *
+ *
+ * @author Braydon
+ */
+public interface PlayerNameCacheRepository extends CrudRepository { }
\ No newline at end of file
diff --git a/src/main/java/me/braydon/mc/service/MojangService.java b/src/main/java/me/braydon/mc/service/MojangService.java
index ac5b500..2bb5525 100644
--- a/src/main/java/me/braydon/mc/service/MojangService.java
+++ b/src/main/java/me/braydon/mc/service/MojangService.java
@@ -10,9 +10,11 @@ import me.braydon.mc.exception.impl.ResourceNotFoundException;
import me.braydon.mc.model.Player;
import me.braydon.mc.model.ProfileAction;
import me.braydon.mc.model.cache.CachedPlayer;
+import me.braydon.mc.model.cache.CachedPlayerName;
import me.braydon.mc.model.token.MojangProfileToken;
import me.braydon.mc.model.token.MojangUsernameToUUIDToken;
import me.braydon.mc.repository.PlayerCacheRepository;
+import me.braydon.mc.repository.PlayerNameCacheRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
@@ -33,14 +35,20 @@ public final class MojangService {
private static final String UUID_TO_PROFILE = SESSION_SERVER_ENDPOINT + "/session/minecraft/profile/%s";
private static final String USERNAME_TO_UUID = API_ENDPOINT + "/users/profiles/minecraft/%s";
+ /**
+ * The cache repository for {@link Player}'s by their username.
+ */
+ @NonNull private final PlayerNameCacheRepository playerNameCache;
+
/**
* The cache repository for {@link Player}'s.
*/
- @NonNull private final PlayerCacheRepository playerCacheRepository;
+ @NonNull private final PlayerCacheRepository playerCache;
@Autowired
- public MojangService(@NonNull PlayerCacheRepository playerCacheRepository) {
- this.playerCacheRepository = playerCacheRepository;
+ public MojangService(@NonNull PlayerNameCacheRepository playerNameCache, @NonNull PlayerCacheRepository playerCache) {
+ this.playerNameCache = playerNameCache;
+ this.playerCache = playerCache;
}
/**
@@ -76,7 +84,7 @@ public final class MojangService {
}
// Check the cache for the player
- Optional cached = playerCacheRepository.findById(uuid);
+ Optional cached = playerCache.findById(uuid);
if (cached.isPresent()) { // Respond with the cache if present
log.info("Found player in cache: {}", uuid);
return cached.get();
@@ -97,7 +105,7 @@ public final class MojangService {
profileActions.length == 0 ? null : profileActions,
System.currentTimeMillis()
);
- playerCacheRepository.save(player);
+ playerCache.save(player);
log.info("Cached player: {}", uuid);
player.setCached(-1L); // Set to -1 to indicate it's not cached in the response
@@ -120,12 +128,26 @@ public final class MojangService {
*/
@NonNull
private UUID usernameToUUID(@NonNull String username) throws ResourceNotFoundException {
+ username = username.toLowerCase(); // Lowercase the username
+
+ // Check the cache for the player's UUID
+ Optional cached = playerNameCache.findById(username);
+ if (cached.isPresent()) { // Respond with the cache if present
+ log.info("Found UUID in cache for username {}: {}", username, cached.get().getUniqueId());
+ return cached.get().getUniqueId();
+ }
+
// Make a request to Mojang requesting the UUID
try {
MojangUsernameToUUIDToken token = JsonWebRequest.makeRequest(
USERNAME_TO_UUID.formatted(username), HttpMethod.GET
).execute(MojangUsernameToUUIDToken.class);
- return UUIDUtils.addDashes(token.getId()); // Return the UUID with dashes
+
+ // Cache the UUID and return it
+ UUID uuid = UUIDUtils.addDashes(token.getId());
+ playerNameCache.save(new CachedPlayerName(username, uuid));
+ log.info("Cached UUID for username {}: {}", username, uuid);
+ return uuid;
} catch (JsonWebException ex) {
if (ex.getStatusCode() == 404) {
throw new ResourceNotFoundException("Player not found with username: %s".formatted(username));