diff --git a/README.md b/README.md
index 7bd3340..98c0308 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,2 @@
# RESTfulMC
-A simple, yet useful RESTful API for Minecraft!
\ No newline at end of file
+A simple, yet useful RESTful API for Minecraft utilizing Springboot.
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 6ff77ab..b62f60e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,6 +33,15 @@
+
+
+
+
+ jitpack.io
+ https://jitpack.io
+
+
+
@@ -71,6 +80,14 @@
compile
+
+
+ com.github.dnsjava
+ dnsjava
+ v3.5.2
+ compile
+
+
org.springframework.boot
diff --git a/src/main/java/me/braydon/mc/common/DNSUtils.java b/src/main/java/me/braydon/mc/common/DNSUtils.java
new file mode 100644
index 0000000..efb2b45
--- /dev/null
+++ b/src/main/java/me/braydon/mc/common/DNSUtils.java
@@ -0,0 +1,53 @@
+package me.braydon.mc.common;
+
+import lombok.NonNull;
+import lombok.SneakyThrows;
+import lombok.experimental.UtilityClass;
+import org.xbill.DNS.Record;
+import org.xbill.DNS.*;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+
+/**
+ * @author Braydon
+ */
+@UtilityClass
+public final class DNSUtils {
+ private static final String SRV_QUERY_PREFIX = "_minecraft._tcp.%s";
+
+ /**
+ * Resolve the hostname to an {@link InetSocketAddress}.
+ *
+ * @param hostname the hostname to resolve
+ * @return the resolved {@link InetSocketAddress}
+ */
+ @SneakyThrows
+ public static InetSocketAddress resolveSRV(@NonNull String hostname) {
+ Record[] records = new Lookup(SRV_QUERY_PREFIX.formatted(hostname), Type.SRV).run(); // Resolve SRV records
+ if (records == null) { // No records exist
+ return null;
+ }
+ String host = null;
+ int port = -1;
+ for (Record record : records) {
+ SRVRecord srv = (SRVRecord) record;
+ host = srv.getTarget().toString().replaceFirst("\\.$", "");
+ port = srv.getPort();
+ }
+ return host == null ? null : new InetSocketAddress(host, port);
+ }
+
+ @SneakyThrows
+ public static InetAddress resolveA(@NonNull String hostname) {
+ Record[] records = new Lookup(hostname, Type.A).run(); // Resolve A records
+ if (records == null) { // No records exist
+ return null;
+ }
+ InetAddress address = null;
+ for (Record record : records) {
+ address = ((ARecord) record).getAddress();
+ }
+ return address;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/braydon/mc/model/MinecraftServer.java b/src/main/java/me/braydon/mc/model/MinecraftServer.java
index 965e5a6..358542d 100644
--- a/src/main/java/me/braydon/mc/model/MinecraftServer.java
+++ b/src/main/java/me/braydon/mc/model/MinecraftServer.java
@@ -13,9 +13,14 @@ import me.braydon.mc.service.pinger.impl.JavaMinecraftServerPinger;
@AllArgsConstructor @Getter @EqualsAndHashCode(onlyExplicitlyIncluded = true) @ToString
public class MinecraftServer {
/**
- * The IP address of this server.
+ * The hostname of this server.
*/
- @EqualsAndHashCode.Include @NonNull private final String ip;
+ @EqualsAndHashCode.Include @NonNull private final String hostname;
+
+ /**
+ * The IP address of this server, if resolved.
+ */
+ private final String ip;
/**
* The port of this server.
diff --git a/src/main/java/me/braydon/mc/model/server/BedrockMinecraftServer.java b/src/main/java/me/braydon/mc/model/server/BedrockMinecraftServer.java
index 5225f4a..3561e91 100644
--- a/src/main/java/me/braydon/mc/model/server/BedrockMinecraftServer.java
+++ b/src/main/java/me/braydon/mc/model/server/BedrockMinecraftServer.java
@@ -9,7 +9,7 @@ import me.braydon.mc.model.MinecraftServer;
* @author Braydon
*/
public final class BedrockMinecraftServer extends MinecraftServer {
- private BedrockMinecraftServer(@NonNull String ip, int port, @NonNull Version version, @NonNull Players players) {
- super(ip, port, version, players);
+ private BedrockMinecraftServer(@NonNull String hostname, String ip, int port, @NonNull Version version, @NonNull Players players) {
+ super(hostname, ip, port, version, players);
}
}
\ No newline at end of file
diff --git a/src/main/java/me/braydon/mc/model/server/JavaMinecraftServer.java b/src/main/java/me/braydon/mc/model/server/JavaMinecraftServer.java
index f0dc699..1f8f7b8 100644
--- a/src/main/java/me/braydon/mc/model/server/JavaMinecraftServer.java
+++ b/src/main/java/me/braydon/mc/model/server/JavaMinecraftServer.java
@@ -10,11 +10,21 @@ import me.braydon.mc.model.token.JavaServerStatusToken;
* @author Braydon
*/
public final class JavaMinecraftServer extends MinecraftServer {
- private JavaMinecraftServer(@NonNull String ip, int port, @NonNull Version version, @NonNull Players players) {
- super(ip, port, version, players);
+ private JavaMinecraftServer(@NonNull String hostname, String ip, int port, @NonNull Version version, @NonNull Players players) {
+ super(hostname, ip, port, version, players);
}
- public static JavaMinecraftServer create(@NonNull String ip, int port, @NonNull JavaServerStatusToken token) {
- return new JavaMinecraftServer(ip, port, token.getVersion(), token.getPlayers());
+ /**
+ * Create a new Java Minecraft server.
+ *
+ * @param hostname the hostname of the server
+ * @param ip the IP address of the server
+ * @param port the port of the server
+ * @param token the status token
+ * @return the Java Minecraft server
+ */
+ @NonNull
+ public static JavaMinecraftServer create(@NonNull String hostname, String ip, int port, @NonNull JavaServerStatusToken token) {
+ return new JavaMinecraftServer(hostname, ip, port, token.getVersion(), token.getPlayers());
}
}
\ 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 dec4dab..00a4932 100644
--- a/src/main/java/me/braydon/mc/service/MojangService.java
+++ b/src/main/java/me/braydon/mc/service/MojangService.java
@@ -2,6 +2,7 @@ package me.braydon.mc.service;
import lombok.NonNull;
import lombok.extern.log4j.Log4j2;
+import me.braydon.mc.common.DNSUtils;
import me.braydon.mc.common.EnumUtils;
import me.braydon.mc.common.Tuple;
import me.braydon.mc.common.UUIDUtils;
@@ -21,6 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
+import java.net.InetSocketAddress;
import java.util.Optional;
import java.util.UUID;
@@ -129,12 +131,28 @@ public final class MojangService {
}
}
- public MinecraftServer getMinecraftServer(@NonNull String platformName, @NonNull String hostname) throws InvalidMinecraftServerPlatform {
+ /**
+ * Resolve a Minecraft server on the given
+ * platform with the given hostname.
+ *
+ * @param platformName the name of the platform
+ * @param hostname the hostname of the server
+ * @return the resolved Minecraft server
+ * @throws InvalidMinecraftServerPlatform if the platform is invalid
+ * @throws ResourceNotFoundException if the server isn't found
+ */
+ @NonNull
+ public MinecraftServer getMinecraftServer(@NonNull String platformName, @NonNull String hostname)
+ throws InvalidMinecraftServerPlatform, ResourceNotFoundException {
MinecraftServer.Platform platform = EnumUtils.getEnumConstant(MinecraftServer.Platform.class, platformName.toUpperCase());
if (platform == null) { // Invalid platform
throw new InvalidMinecraftServerPlatform();
}
- return platform.getPinger().ping(hostname, 25565);
+ InetSocketAddress address = DNSUtils.resolveSRV(hostname); // Resolve the SRV record
+ if (address == null) { // No address found
+ throw new ResourceNotFoundException("No SRV record found for hostname: %s".formatted(hostname));
+ }
+ return platform.getPinger().ping(address.getHostName(), address.getPort()); // Ping the server and return with the response
}
/**
diff --git a/src/main/java/me/braydon/mc/service/pinger/impl/JavaMinecraftServerPinger.java b/src/main/java/me/braydon/mc/service/pinger/impl/JavaMinecraftServerPinger.java
index 89529e1..756d2ab 100644
--- a/src/main/java/me/braydon/mc/service/pinger/impl/JavaMinecraftServerPinger.java
+++ b/src/main/java/me/braydon/mc/service/pinger/impl/JavaMinecraftServerPinger.java
@@ -3,6 +3,7 @@ package me.braydon.mc.service.pinger.impl;
import lombok.NonNull;
import lombok.extern.log4j.Log4j2;
import me.braydon.mc.RESTfulMC;
+import me.braydon.mc.common.DNSUtils;
import me.braydon.mc.common.packet.impl.PacketHandshakingInSetProtocol;
import me.braydon.mc.common.packet.impl.PacketStatusInStart;
import me.braydon.mc.model.server.JavaMinecraftServer;
@@ -12,6 +13,7 @@ import me.braydon.mc.service.pinger.MinecraftServerPinger;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
@@ -34,6 +36,11 @@ public final class JavaMinecraftServerPinger implements MinecraftServerPinger