Add Bedrock server pinger
This commit is contained in:
parent
e5342b5445
commit
8cca0c2b51
@ -911,22 +911,21 @@ public final class MojangService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the favicon of a server on the
|
* Get the favicon of a Java
|
||||||
* given platform with the given hostname.
|
* server with the given hostname.
|
||||||
* <p>
|
* <p>
|
||||||
* If the favicon of the server cannot be
|
* If the favicon of the server cannot be
|
||||||
* retrieved, the default icon will be used.
|
* retrieved, the default icon will be used.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param platform the platform of the server
|
|
||||||
* @param hostname the hostname of the server
|
* @param hostname the hostname of the server
|
||||||
* @return the server favicon
|
* @return the server favicon
|
||||||
* @see #DEFAULT_SERVER_ICON for the default server icon
|
* @see #DEFAULT_SERVER_ICON for the default server icon
|
||||||
*/
|
*/
|
||||||
public byte[] getServerFavicon(@NonNull String platform, @NonNull String hostname) {
|
public byte[] getServerFavicon(@NonNull String hostname) {
|
||||||
String icon = null; // The server base64 icon
|
String icon = null; // The server base64 icon
|
||||||
try {
|
try {
|
||||||
MinecraftServer.Favicon favicon = getMinecraftServer(platform, hostname).getValue().getFavicon();
|
JavaMinecraftServer.Favicon favicon = ((JavaMinecraftServer) getMinecraftServer(MinecraftServer.Platform.JAVA.name(), hostname).getValue()).getFavicon();
|
||||||
if (favicon != null) { // Use the server's favicon
|
if (favicon != null) { // Use the server's favicon
|
||||||
icon = favicon.getBase64();
|
icon = favicon.getBase64();
|
||||||
icon = icon.substring(icon.indexOf(",") + 1); // Remove the data type from the server icon
|
icon = icon.substring(icon.indexOf(",") + 1); // Remove the data type from the server icon
|
||||||
@ -1014,7 +1013,7 @@ public final class MojangService {
|
|||||||
return cached.get();
|
return cached.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
InetSocketAddress address = DNSUtils.resolveSRV(hostname); // Resolve the SRV record
|
InetSocketAddress address = platform == MinecraftServer.Platform.JAVA ? DNSUtils.resolveSRV(hostname) : null; // Resolve the SRV record
|
||||||
int port = platform.getDefaultPort(); // Port to ping
|
int port = platform.getDefaultPort(); // Port to ping
|
||||||
if (address != null) { // SRV was resolved, use the hostname and port
|
if (address != null) { // SRV was resolved, use the hostname and port
|
||||||
hostname = address.getHostName();
|
hostname = address.getHostName();
|
||||||
|
@ -678,9 +678,17 @@ package me.braydon.mc.service.pinger.impl;
|
|||||||
|
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import me.braydon.mc.common.DNSUtils;
|
||||||
|
import me.braydon.mc.common.packet.impl.bedrock.BedrockPacketUnconnectedPing;
|
||||||
|
import me.braydon.mc.common.packet.impl.bedrock.BedrockPacketUnconnectedPong;
|
||||||
|
import me.braydon.mc.exception.impl.BadRequestException;
|
||||||
|
import me.braydon.mc.exception.impl.ResourceNotFoundException;
|
||||||
import me.braydon.mc.model.server.BedrockMinecraftServer;
|
import me.braydon.mc.model.server.BedrockMinecraftServer;
|
||||||
import me.braydon.mc.service.pinger.MinecraftServerPinger;
|
import me.braydon.mc.service.pinger.MinecraftServerPinger;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link MinecraftServerPinger} for
|
* The {@link MinecraftServerPinger} for
|
||||||
* pinging {@link BedrockMinecraftServer}'s.
|
* pinging {@link BedrockMinecraftServer}'s.
|
||||||
@ -689,6 +697,8 @@ import me.braydon.mc.service.pinger.MinecraftServerPinger;
|
|||||||
*/
|
*/
|
||||||
@Log4j2(topic = "Bedrock MC Server Pinger")
|
@Log4j2(topic = "Bedrock MC Server Pinger")
|
||||||
public final class BedrockMinecraftServerPinger implements MinecraftServerPinger<BedrockMinecraftServer> {
|
public final class BedrockMinecraftServerPinger implements MinecraftServerPinger<BedrockMinecraftServer> {
|
||||||
|
private static final int TIMEOUT = 3000; // The timeout for the socket
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ping the server with the given hostname and port.
|
* Ping the server with the given hostname and port.
|
||||||
*
|
*
|
||||||
@ -698,6 +708,41 @@ public final class BedrockMinecraftServerPinger implements MinecraftServerPinger
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public BedrockMinecraftServer ping(@NonNull String hostname, int port) {
|
public BedrockMinecraftServer ping(@NonNull String hostname, int port) {
|
||||||
throw new UnsupportedOperationException("Not yet implemented.");
|
InetAddress inetAddress = DNSUtils.resolveA(hostname); // Resolve the hostname to an IP address
|
||||||
|
String ip = inetAddress == null ? null : inetAddress.getHostAddress(); // Get the IP address
|
||||||
|
if (ip != null) { // Was the IP resolved?
|
||||||
|
log.info("Resolved hostname: {} -> {}", hostname, ip);
|
||||||
|
}
|
||||||
|
log.info("Pinging {}:{}...", hostname, port);
|
||||||
|
long before = System.currentTimeMillis(); // Timestamp before pinging
|
||||||
|
|
||||||
|
// Open a socket connection to the server
|
||||||
|
try (DatagramSocket socket = new DatagramSocket()) {
|
||||||
|
socket.setSoTimeout(TIMEOUT);
|
||||||
|
socket.connect(new InetSocketAddress(hostname, port));
|
||||||
|
|
||||||
|
long ping = System.currentTimeMillis() - before; // Calculate the ping
|
||||||
|
log.info("Pinged {}:{} in {}ms", hostname, port, ping);
|
||||||
|
|
||||||
|
// Send the unconnected ping packet
|
||||||
|
new BedrockPacketUnconnectedPing().process(socket);
|
||||||
|
|
||||||
|
// Handle the received unconnected pong packet
|
||||||
|
BedrockPacketUnconnectedPong unconnectedPong = new BedrockPacketUnconnectedPong();
|
||||||
|
unconnectedPong.process(socket);
|
||||||
|
String response = unconnectedPong.getResponse();
|
||||||
|
if (response == null) { // No pong response
|
||||||
|
throw new ResourceNotFoundException("Server didn't respond to ping");
|
||||||
|
}
|
||||||
|
return BedrockMinecraftServer.create(hostname, ip, port, response); // Return the server
|
||||||
|
} catch (IOException ex) {
|
||||||
|
if (ex instanceof UnknownHostException) {
|
||||||
|
throw new BadRequestException("Unknown hostname: %s".formatted(hostname));
|
||||||
|
} else if (ex instanceof SocketTimeoutException) {
|
||||||
|
throw new ResourceNotFoundException(ex);
|
||||||
|
}
|
||||||
|
log.error("An error occurred pinging %s:%s:".formatted(hostname, port), ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -680,8 +680,8 @@ import lombok.NonNull;
|
|||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import me.braydon.mc.RESTfulMC;
|
import me.braydon.mc.RESTfulMC;
|
||||||
import me.braydon.mc.common.DNSUtils;
|
import me.braydon.mc.common.DNSUtils;
|
||||||
import me.braydon.mc.common.packet.impl.PacketHandshakingInSetProtocol;
|
import me.braydon.mc.common.packet.impl.java.JavaPacketHandshakingInSetProtocol;
|
||||||
import me.braydon.mc.common.packet.impl.PacketStatusInStart;
|
import me.braydon.mc.common.packet.impl.java.JavaPacketStatusInStart;
|
||||||
import me.braydon.mc.exception.impl.BadRequestException;
|
import me.braydon.mc.exception.impl.BadRequestException;
|
||||||
import me.braydon.mc.exception.impl.ResourceNotFoundException;
|
import me.braydon.mc.exception.impl.ResourceNotFoundException;
|
||||||
import me.braydon.mc.model.server.JavaMinecraftServer;
|
import me.braydon.mc.model.server.JavaMinecraftServer;
|
||||||
@ -726,6 +726,7 @@ public final class JavaMinecraftServerPinger implements MinecraftServerPinger<Ja
|
|||||||
try (Socket socket = new Socket()) {
|
try (Socket socket = new Socket()) {
|
||||||
socket.setTcpNoDelay(true);
|
socket.setTcpNoDelay(true);
|
||||||
socket.connect(new InetSocketAddress(hostname, port), TIMEOUT);
|
socket.connect(new InetSocketAddress(hostname, port), TIMEOUT);
|
||||||
|
|
||||||
long ping = System.currentTimeMillis() - before; // Calculate the ping
|
long ping = System.currentTimeMillis() - before; // Calculate the ping
|
||||||
log.info("Pinged {}:{} in {}ms", hostname, port, ping);
|
log.info("Pinged {}:{} in {}ms", hostname, port, ping);
|
||||||
|
|
||||||
@ -733,10 +734,10 @@ public final class JavaMinecraftServerPinger implements MinecraftServerPinger<Ja
|
|||||||
try (DataInputStream inputStream = new DataInputStream(socket.getInputStream());
|
try (DataInputStream inputStream = new DataInputStream(socket.getInputStream());
|
||||||
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream())) {
|
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream())) {
|
||||||
// Begin handshaking with the server
|
// Begin handshaking with the server
|
||||||
new PacketHandshakingInSetProtocol(hostname, port, 47).process(inputStream, outputStream);
|
new JavaPacketHandshakingInSetProtocol(hostname, port, 47).process(inputStream, outputStream);
|
||||||
|
|
||||||
// Send the status request to the server, and await back the response
|
// Send the status request to the server, and await back the response
|
||||||
PacketStatusInStart packetStatusInStart = new PacketStatusInStart();
|
JavaPacketStatusInStart packetStatusInStart = new JavaPacketStatusInStart();
|
||||||
packetStatusInStart.process(inputStream, outputStream);
|
packetStatusInStart.process(inputStream, outputStream);
|
||||||
JavaServerStatusToken token = RESTfulMC.GSON.fromJson(packetStatusInStart.getResponse(), JavaServerStatusToken.class);
|
JavaServerStatusToken token = RESTfulMC.GSON.fromJson(packetStatusInStart.getResponse(), JavaServerStatusToken.class);
|
||||||
return JavaMinecraftServer.create(hostname, ip, port, token); // Return the server
|
return JavaMinecraftServer.create(hostname, ip, port, token); // Return the server
|
||||||
|
Loading…
x
Reference in New Issue
Block a user