add server pinger
Some checks are pending
ci / deploy (push) Waiting to run

This commit is contained in:
Lee
2024-04-10 07:43:13 +01:00
parent ed3b7e3064
commit 25c69e11e1
38 changed files with 104 additions and 1299 deletions

View File

@ -1,40 +0,0 @@
package cc.fascinated.service;
import cc.fascinated.common.WebRequest;
import cc.fascinated.model.mojang.MojangProfile;
import cc.fascinated.model.mojang.MojangUsernameToUuid;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service @Log4j2
public class MojangAPIService {
@Value("${mojang.session-server}")
private String mojangSessionServerUrl;
@Value("${mojang.api}")
private String mojangApiUrl;
/**
* Gets the Session Server profile of the
* player with the given UUID.
*
* @param id the uuid or name of the player
* @return the profile
*/
public MojangProfile getProfile(String id) {
return WebRequest.getAsEntity(mojangSessionServerUrl + "/session/minecraft/profile/" + id, MojangProfile.class);
}
/**
* Gets the UUID of the player using
* the name of the player.
*
* @param id the name of the player
* @return the profile
*/
public MojangUsernameToUuid getUuidFromUsername(String id) {
return WebRequest.getAsEntity(mojangApiUrl + "/users/profiles/minecraft/" + id, MojangUsernameToUuid.class);
}
}

View File

@ -1,81 +0,0 @@
package cc.fascinated.service;
import cc.fascinated.common.UUIDUtils;
import cc.fascinated.model.mojang.MojangProfile;
import cc.fascinated.model.mojang.MojangUsernameToUuid;
import cc.fascinated.model.player.Player;
import lombok.extern.log4j.Log4j2;
import net.jodah.expiringmap.ExpirationPolicy;
import net.jodah.expiringmap.ExpiringMap;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Service @Log4j2
public class PlayerService {
/**
* The cache of players.
*/
private final Map<UUID, Player> players = ExpiringMap.builder()
.expiration(1, TimeUnit.HOURS)
.expirationPolicy(ExpirationPolicy.CREATED)
.build();
/**
* The cache of player names to UUIDs.
*/
private final Map<String, UUID> playerNameToUUIDCache = ExpiringMap.builder()
.expiration(1, TimeUnit.DAYS)
.expirationPolicy(ExpirationPolicy.CREATED)
.build();
private final MojangAPIService mojangAPIService;
public PlayerService(MojangAPIService mojangAPIService) {
this.mojangAPIService = mojangAPIService;
}
/**
* Gets a player by their UUID.
*
* @param id the uuid or name of the player
* @return the player or null if the player does not exist
*/
public Player getPlayer(String id) {
UUID uuid = null;
if (id.length() == 32 || id.length() == 36) { // Check if the id is a UUID
try {
uuid = UUID.fromString(id.length() == 32 ? UUIDUtils.addUuidDashes(id) : id);
} catch (Exception ignored) {}
} else { // Check if the id is a name
uuid = playerNameToUUIDCache.get(id.toUpperCase());
}
// Check if the player is cached
if (uuid != null && players.containsKey(uuid)) {
return players.get(uuid);
}
MojangProfile profile = uuid == null ? null : mojangAPIService.getProfile(uuid.toString());
if (profile == null) { // The player cannot be found using their UUID
MojangUsernameToUuid apiProfile = mojangAPIService.getUuidFromUsername(id); // Get the UUID of the player using their name
if (apiProfile == null || !apiProfile.isValid()) {
return null;
}
// Get the profile of the player using their UUID
profile = mojangAPIService.getProfile(apiProfile.getId().length() == 32 ?
UUIDUtils.addUuidDashes(apiProfile.getId()) : apiProfile.getId());
}
if (profile == null) { // The player cannot be found using their name or UUID
log.info("Player with id {} could not be found", id);
return null;
}
Player player = new Player(profile);
players.put(player.getUuid(), player);
playerNameToUUIDCache.put(player.getName().toUpperCase(), player.getUuid());
return player;
}
}

View File

@ -1,9 +0,0 @@
package cc.fascinated.service.pinger;
/**
* @author Braydon
* @param <T> the type of server to ping
*/
public interface MinecraftServerPinger<T> {
T ping(String hostname, int port);
}

View File

@ -1,53 +0,0 @@
package cc.fascinated.service.pinger.impl;
import cc.fascinated.Main;
import cc.fascinated.common.packet.impl.java.JavaPacketHandshakingInSetProtocol;
import cc.fascinated.common.packet.impl.java.JavaPacketStatusInStart;
import cc.fascinated.model.mojang.JavaServerStatusToken;
import cc.fascinated.model.server.JavaMinecraftServer;
import cc.fascinated.service.pinger.MinecraftServerPinger;
import lombok.extern.log4j.Log4j2;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
/**
* @author Braydon
*/
@Log4j2(topic = "Java Pinger")
public final class JavaMinecraftServerPinger implements MinecraftServerPinger<JavaMinecraftServer> {
public static final JavaMinecraftServerPinger INSTANCE = new JavaMinecraftServerPinger();
private static final int TIMEOUT = 3000; // The timeout for the socket
@Override
public JavaMinecraftServer ping(String hostname, int port) {
log.info("Pinging {}:{}...", hostname, port);
// Open a socket connection to the server
try (Socket socket = new Socket()) {
socket.setTcpNoDelay(true);
socket.connect(new InetSocketAddress(hostname, port), TIMEOUT);
// Open data streams to begin packet transaction
try (DataInputStream inputStream = new DataInputStream(socket.getInputStream());
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream())) {
// Begin handshaking with the server
new JavaPacketHandshakingInSetProtocol(hostname, port, 47).process(inputStream, outputStream);
// Send the status request to the server, and await back the response
JavaPacketStatusInStart packetStatusInStart = new JavaPacketStatusInStart();
packetStatusInStart.process(inputStream, outputStream);
System.out.println("packetStatusInStart.getResponse() = " + packetStatusInStart.getResponse());
JavaServerStatusToken token = Main.GSON.fromJson(packetStatusInStart.getResponse(), JavaServerStatusToken.class);
return new JavaMinecraftServer(hostname, port, token.getDescription());
}
} catch (IOException ex) {
ex.printStackTrace();
}
return null;
}
}