Add `getUUID()` and `getUsername()` to MojangUtils (#2024)

* Add MojangUtils#getUUID() and MojangUtils#getUsername()

* Remove invalid UUID test as Java's UUID will not allow an invalid UUID

* Add `@Blocking` and some JavaDoc comments

* Override `MojangUtils#fromUuid(String)` with `MojangUtils#fromUuid(UUID)` and add a test

* Switch to IOException over custom ones
This commit is contained in:
Zax71 2024-03-18 03:25:35 +00:00 committed by GitHub
parent ed257aea18
commit 40ebd2b67f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 122 additions and 23 deletions

View File

@ -11,6 +11,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
@ -24,36 +25,107 @@ public final class MojangUtils {
.softValues()
.build();
/**
* Gets a player's UUID from their username
* @param username The players username
* @return The {@link UUID}
* @throws IOException with text detailing the exception
*/
@Blocking
public static @NotNull UUID getUUID(String username) throws IOException {
// Thanks stackoverflow: https://stackoverflow.com/a/19399768/13247146
return UUID.fromString(
retrieve(String.format(FROM_USERNAME_URL, username)).get("id")
.getAsString()
.replaceFirst(
"(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)",
"$1-$2-$3-$4-$5"
)
);
}
/**
* Gets a player's username from their UUID
* @param playerUUID The {@link UUID} of the player
* @return The player's username
* @throws IOException with text detailing the exception
*/
@Blocking
public static @NotNull String getUsername(UUID playerUUID) throws IOException {
return retrieve(String.format(FROM_UUID_URL, playerUUID)).get("name").getAsString();
}
/**
* Gets a {@link JsonObject} with the response from the mojang API
* @param uuid The UUID as a {@link UUID}
* @return The {@link JsonObject} or {@code null} if the mojang API is down or the UUID is invalid
*/
@Blocking
public static @Nullable JsonObject fromUuid(@NotNull UUID uuid) {
return fromUuid(uuid.toString());
}
/**
* Gets a {@link JsonObject} with the response from the mojang API
* @param uuid The UUID as a {@link String}
* @return The {@link JsonObject} or {@code null} if the mojang API is down or the UUID is invalid
*/
@Blocking
public static @Nullable JsonObject fromUuid(@NotNull String uuid) {
return retrieve(String.format(FROM_UUID_URL, uuid));
try {
return retrieve(String.format(FROM_UUID_URL, uuid));
} catch (IOException e) {
return null;
}
}
/**
* Gets a {@link JsonObject} with the response from the mojang API
* @param username The username as a {@link String}
* @return The {@link JsonObject} or {@code null} if the mojang API is down or the username is invalid
*/
@Blocking
public static @Nullable JsonObject fromUsername(@NotNull String username) {
return retrieve(String.format(FROM_USERNAME_URL, username));
try {
return retrieve(String.format(FROM_USERNAME_URL, username));
} catch (IOException e) {
return null;
}
}
private static @Nullable JsonObject retrieve(@NotNull String url) {
return URL_CACHE.get(url, s -> {
try {
// Retrieve from the rate-limited Mojang API
final String response = URLUtils.getText(url);
// If our response is "", that means the url did not get a proper object from the url
// So the username or UUID was invalid, and therefore we return null
if (response.isEmpty()) {
return null;
}
/**
* Gets the JsonObject from a URL, expects a mojang player URL so the errors might not make sense if it is not
* @param url The url to retrieve
* @return The {@link JsonObject} of the result
* @throws IOException with the text detailing the exception
*/
private static @NotNull JsonObject retrieve(@NotNull String url) throws IOException {
@Nullable final var cacheResult = URL_CACHE.getIfPresent(url);
JsonObject jsonObject = JsonParser.parseString(response).getAsJsonObject();
if (jsonObject.has("errorMessage")) {
return null;
}
return jsonObject;
} catch (IOException e) {
MinecraftServer.getExceptionManager().handleException(e);
throw new RuntimeException(e);
}
});
if (cacheResult != null) {
return cacheResult;
}
final String response;
try {
// Retrieve from the rate-limited Mojang API
response = URLUtils.getText(url);
} catch (IOException e) {
MinecraftServer.getExceptionManager().handleException(e);
throw new RuntimeException(e);
}
// If our response is "", that means the url did not get a proper object from the url
// So the username or UUID was invalid, and therefore we return null
if (response.isEmpty()) {
throw new IOException("The Mojang API is down");
}
JsonObject jsonObject = JsonParser.parseString(response).getAsJsonObject();
if (jsonObject.has("errorMessage")) {
throw new IOException(jsonObject.get("errorMessage").getAsString());
}
URL_CACHE.put(url, jsonObject);
return jsonObject;
}
}

View File

@ -3,9 +3,13 @@ package net.minestom.server.utils;
import net.minestom.server.utils.mojang.MojangUtils;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*;
public class TestMojangUtils {
private final UUID JEB_UUID = UUID.fromString("853c80ef-3c37-49fd-aa49-938b674adae6");
@Test
public void testValidNameWorks() {
var result = MojangUtils.fromUsername("jeb_");
@ -21,7 +25,7 @@ public class TestMojangUtils {
@Test
public void testValidUuidWorks() {
var result = MojangUtils.fromUuid("853c80ef3c3749fdaa49938b674adae6");
var result = MojangUtils.fromUuid(JEB_UUID.toString());
assertNotNull(result);
assertEquals("jeb_", result.get("name").getAsString());
assertEquals("853c80ef3c3749fdaa49938b674adae6", result.get("id").getAsString());
@ -38,4 +42,27 @@ public class TestMojangUtils {
var result = MojangUtils.fromUuid("00000000-0000-0000-0000-000000000000");
assertNull(result);
}
@Test
public void testValidUUIDWorks() {
var result = MojangUtils.fromUuid(JEB_UUID);
assertNotNull(result);
assertEquals("jeb_", result.get("name").getAsString());
assertEquals("853c80ef3c3749fdaa49938b674adae6", result.get("id").getAsString());
}
@Test
public void testGetValidNameWorks() throws IOException {
assertEquals(JEB_UUID, MojangUtils.getUUID("jeb_"));
}
@Test
public void testGetValidUUIDWorks() throws IOException {
assertEquals("jeb_", MojangUtils.getUsername(JEB_UUID));
}
@Test
public void testGetInvalidNameThrows() {
assertThrows(IOException.class, () -> MojangUtils.getUUID("a")); // Too short
}
}