Add Redis caching for Minecraft servers
This commit is contained in:
parent
f99ffbf1e6
commit
3183c56d78
@ -3,6 +3,7 @@ package me.braydon.mc.controller;
|
|||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import me.braydon.mc.model.MinecraftServer;
|
import me.braydon.mc.model.MinecraftServer;
|
||||||
|
import me.braydon.mc.model.cache.CachedMinecraftServer;
|
||||||
import me.braydon.mc.service.MojangService;
|
import me.braydon.mc.service.MojangService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
@ -38,8 +39,8 @@ public final class ServerController {
|
|||||||
*/
|
*/
|
||||||
@GetMapping("/{platform}/{hostname}")
|
@GetMapping("/{platform}/{hostname}")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public ResponseEntity<MinecraftServer> getServer(@PathVariable @NonNull String platform,
|
public ResponseEntity<CachedMinecraftServer> getServer(@PathVariable @NonNull String platform,
|
||||||
@PathVariable @NonNull String hostname
|
@PathVariable @NonNull String hostname
|
||||||
) {
|
) {
|
||||||
return ResponseEntity.ofNullable(mojangService.getMinecraftServer(platform, hostname));
|
return ResponseEntity.ofNullable(mojangService.getMinecraftServer(platform, hostname));
|
||||||
}
|
}
|
||||||
|
@ -62,9 +62,9 @@ public class MinecraftServer {
|
|||||||
private final int max;
|
private final int max;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A sample of players on this server.
|
* A sample of players on this server, null or empty if no sample.
|
||||||
*/
|
*/
|
||||||
@NonNull private final Sample[] sample;
|
private final Sample[] sample;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A sample player.
|
* A sample player.
|
||||||
|
31
src/main/java/me/braydon/mc/model/cache/CachedMinecraftServer.java
vendored
Normal file
31
src/main/java/me/braydon/mc/model/cache/CachedMinecraftServer.java
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package me.braydon.mc.model.cache;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import me.braydon.mc.model.MinecraftServer;
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.redis.core.RedisHash;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Braydon
|
||||||
|
*/
|
||||||
|
@AllArgsConstructor @Setter @Getter @ToString
|
||||||
|
@RedisHash(value = "server", timeToLive = 60L) // 1 minute (in seconds)
|
||||||
|
public final class CachedMinecraftServer implements Serializable {
|
||||||
|
/**
|
||||||
|
* The hostname of the cached server.
|
||||||
|
*/
|
||||||
|
@Id @NonNull private transient final String hostname;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cached server.
|
||||||
|
*/
|
||||||
|
@NonNull private final MinecraftServer value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unix timestamp of when this
|
||||||
|
* server was cached, -1 if not cached.
|
||||||
|
*/
|
||||||
|
private long cached;
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
package me.braydon.mc.model.response;
|
package me.braydon.mc.model.response;
|
||||||
|
|
||||||
import lombok.*;
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
package me.braydon.mc.repository;
|
||||||
|
|
||||||
|
import me.braydon.mc.model.cache.CachedMinecraftServer;
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cache repository for {@link CachedMinecraftServer}'s.
|
||||||
|
*
|
||||||
|
* @author Braydon
|
||||||
|
*/
|
||||||
|
public interface MinecraftServerCacheRepository extends CrudRepository<CachedMinecraftServer, String> { }
|
@ -12,10 +12,12 @@ import me.braydon.mc.exception.impl.BadRequestException;
|
|||||||
import me.braydon.mc.exception.impl.InvalidMinecraftServerPlatform;
|
import me.braydon.mc.exception.impl.InvalidMinecraftServerPlatform;
|
||||||
import me.braydon.mc.exception.impl.ResourceNotFoundException;
|
import me.braydon.mc.exception.impl.ResourceNotFoundException;
|
||||||
import me.braydon.mc.model.*;
|
import me.braydon.mc.model.*;
|
||||||
|
import me.braydon.mc.model.cache.CachedMinecraftServer;
|
||||||
import me.braydon.mc.model.cache.CachedPlayer;
|
import me.braydon.mc.model.cache.CachedPlayer;
|
||||||
import me.braydon.mc.model.cache.CachedPlayerName;
|
import me.braydon.mc.model.cache.CachedPlayerName;
|
||||||
import me.braydon.mc.model.token.MojangProfileToken;
|
import me.braydon.mc.model.token.MojangProfileToken;
|
||||||
import me.braydon.mc.model.token.MojangUsernameToUUIDToken;
|
import me.braydon.mc.model.token.MojangUsernameToUUIDToken;
|
||||||
|
import me.braydon.mc.repository.MinecraftServerCacheRepository;
|
||||||
import me.braydon.mc.repository.PlayerCacheRepository;
|
import me.braydon.mc.repository.PlayerCacheRepository;
|
||||||
import me.braydon.mc.repository.PlayerNameCacheRepository;
|
import me.braydon.mc.repository.PlayerNameCacheRepository;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -49,10 +51,17 @@ public final class MojangService {
|
|||||||
*/
|
*/
|
||||||
@NonNull private final PlayerCacheRepository playerCache;
|
@NonNull private final PlayerCacheRepository playerCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cache repository for {@link MinecraftServer}'s.
|
||||||
|
*/
|
||||||
|
@NonNull private final MinecraftServerCacheRepository minecraftServerCache;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public MojangService(@NonNull PlayerNameCacheRepository playerNameCache, @NonNull PlayerCacheRepository playerCache) {
|
public MojangService(@NonNull PlayerNameCacheRepository playerNameCache, @NonNull PlayerCacheRepository playerCache,
|
||||||
|
@NonNull MinecraftServerCacheRepository minecraftServerCache) {
|
||||||
this.playerNameCache = playerNameCache;
|
this.playerNameCache = playerNameCache;
|
||||||
this.playerCache = playerCache;
|
this.playerCache = playerCache;
|
||||||
|
this.minecraftServerCache = minecraftServerCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -143,19 +152,37 @@ public final class MojangService {
|
|||||||
* @throws ResourceNotFoundException if the server isn't found
|
* @throws ResourceNotFoundException if the server isn't found
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public MinecraftServer getMinecraftServer(@NonNull String platformName, @NonNull String hostname)
|
public CachedMinecraftServer getMinecraftServer(@NonNull String platformName, @NonNull String hostname)
|
||||||
throws BadRequestException, InvalidMinecraftServerPlatform, ResourceNotFoundException {
|
throws BadRequestException, InvalidMinecraftServerPlatform, ResourceNotFoundException {
|
||||||
MinecraftServer.Platform platform = EnumUtils.getEnumConstant(MinecraftServer.Platform.class, platformName.toUpperCase());
|
MinecraftServer.Platform platform = EnumUtils.getEnumConstant(MinecraftServer.Platform.class, platformName.toUpperCase());
|
||||||
if (platform == null) { // Invalid platform
|
if (platform == null) { // Invalid platform
|
||||||
throw new InvalidMinecraftServerPlatform();
|
throw new InvalidMinecraftServerPlatform();
|
||||||
}
|
}
|
||||||
|
String lookupHostname = hostname; // The hostname used to lookup the server
|
||||||
|
|
||||||
|
// Check the cache for the server
|
||||||
|
Optional<CachedMinecraftServer> cached = minecraftServerCache.findById(hostname);
|
||||||
|
if (cached.isPresent()) { // Respond with the cache if present
|
||||||
|
log.info("Found server in cache: {}", hostname);
|
||||||
|
return cached.get();
|
||||||
|
}
|
||||||
|
|
||||||
InetSocketAddress address = DNSUtils.resolveSRV(hostname); // Resolve the SRV record
|
InetSocketAddress address = DNSUtils.resolveSRV(hostname); // 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();
|
||||||
port = address.getPort();
|
port = address.getPort();
|
||||||
}
|
}
|
||||||
return platform.getPinger().ping(hostname, port); // Ping the server and return with the response
|
// Build our server model, cache it, and then return it
|
||||||
|
CachedMinecraftServer minecraftServer = new CachedMinecraftServer(
|
||||||
|
lookupHostname,
|
||||||
|
platform.getPinger().ping(hostname, port),
|
||||||
|
System.currentTimeMillis()
|
||||||
|
);
|
||||||
|
minecraftServerCache.save(minecraftServer);
|
||||||
|
log.info("Cached server: {}", hostname);
|
||||||
|
minecraftServer.setCached(-1L); // Set to -1 to indicate it's not cached in the response
|
||||||
|
return minecraftServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user