Merge branch 'master' of github.com:McGamerZone/McGamerCore into master

This commit is contained in:
Joel 2021-02-20 00:01:54 +01:00
commit 7255024b68
12 changed files with 77 additions and 23 deletions

@ -11,8 +11,8 @@ import zone.themcgamer.api.model.ModelSerializer;
import zone.themcgamer.api.model.impl.*; import zone.themcgamer.api.model.impl.*;
import zone.themcgamer.api.repository.AccountRepository; import zone.themcgamer.api.repository.AccountRepository;
import zone.themcgamer.api.route.AccountRoute; import zone.themcgamer.api.route.AccountRoute;
import zone.themcgamer.api.route.PlayerStatusRoute;
import zone.themcgamer.api.route.ServersRoute; import zone.themcgamer.api.route.ServersRoute;
import zone.themcgamer.api.route.StatusRoute;
import zone.themcgamer.data.APIAccessLevel; import zone.themcgamer.data.APIAccessLevel;
import zone.themcgamer.data.jedis.JedisController; import zone.themcgamer.data.jedis.JedisController;
import zone.themcgamer.data.jedis.data.APIKey; import zone.themcgamer.data.jedis.data.APIKey;
@ -57,12 +57,12 @@ public class API {
addModel(NodeModel.class); addModel(NodeModel.class);
addModel(ServerGroupModel.class); addModel(ServerGroupModel.class);
addModel(AccountModel.class); addModel(AccountModel.class);
addModel(StatusModel.class); addModel(PlayerStatusModel.class);
// Adding the routes // Adding the routes
addRoute(new ServersRoute()); addRoute(new ServersRoute());
addRoute(new AccountRoute(accountRepository)); addRoute(new AccountRoute(accountRepository));
addRoute(new StatusRoute()); addRoute(new PlayerStatusRoute());
// 404 Handling // 404 Handling
Spark.notFound((request, response) -> { Spark.notFound((request, response) -> {
@ -110,6 +110,8 @@ public class API {
System.out.println("Handling incoming request from \"" + request.ip() + "\" using path \"" + request.pathInfo() + "\""); System.out.println("Handling incoming request from \"" + request.ip() + "\" using path \"" + request.pathInfo() + "\"");
APIKey key = new APIKey(UUID.randomUUID().toString(), APIAccessLevel.STANDARD); APIKey key = new APIKey(UUID.randomUUID().toString(), APIAccessLevel.STANDARD);
// If authentication is enabled, handle the api key checking and display a Unauthorized error
// if there is a problem checking the key or the key is invalid
if (requiresAuthentication) { if (requiresAuthentication) {
String apiKey = request.headers("key"); String apiKey = request.headers("key");
if (apiKey == null) if (apiKey == null)
@ -133,7 +135,9 @@ public class API {
if (method.getParameterTypes().length != 3) if (method.getParameterTypes().length != 3)
throw new APIException("Invalid route defined"); throw new APIException("Invalid route defined");
Object object = method.invoke(entry.getKey(), request, response, key); Object object = method.invoke(entry.getKey(), request, response, key);
jsonObject.addProperty("success", "true"); jsonObject.addProperty("success", "true"); // Marking the request as successful in the JsonObject
// Format the Object returned from the route accordingly
if (object instanceof IModel) { if (object instanceof IModel) {
if (models.contains(object.getClass())) if (models.contains(object.getClass()))
jsonObject.add("value", gson.toJsonTree(((IModel) object).toMap(), HashMap.class)); jsonObject.add("value", gson.toJsonTree(((IModel) object).toMap(), HashMap.class));
@ -144,13 +148,17 @@ public class API {
jsonObject.add("value", gson.toJsonTree(object, HashMap.class)); jsonObject.add("value", gson.toJsonTree(object, HashMap.class));
else jsonObject.addProperty("value", object.toString()); else jsonObject.addProperty("value", object.toString());
} catch (Throwable ex) { } catch (Throwable ex) {
// If there is an error thrown from a route, we wanna fetch the error from the invoke method
// and get the cause of the exception
if (ex instanceof InvocationTargetException) if (ex instanceof InvocationTargetException)
ex = ex.getCause(); ex = ex.getCause();
String message = ex.getLocalizedMessage(); String message = ex.getLocalizedMessage();
// If the exception has no message associated with it, display the type of exception instead
if (message == null || (message.trim().isEmpty())) if (message == null || (message.trim().isEmpty()))
message = ex.getClass().getSimpleName(); message = ex.getClass().getSimpleName();
jsonObject.addProperty("success", "false"); jsonObject.addProperty("success", "false");
jsonObject.addProperty("error", message); jsonObject.addProperty("error", message);
// If the caught exception is not an API exception, print the stacktrace
if (!(ex instanceof APIException)) { if (!(ex instanceof APIException)) {
System.err.println("The route \"" + entry.getKey().getClass().getSimpleName() + "\" raised an exception:"); System.err.println("The route \"" + entry.getKey().getClass().getSimpleName() + "\" raised an exception:");
ex.printStackTrace(); ex.printStackTrace();
@ -162,10 +170,20 @@ public class API {
} }
} }
/**
* Adding a {@link IModel}
*
* @param modelClass the class of the model to add
*/
private static void addModel(Class<? extends IModel> modelClass) { private static void addModel(Class<? extends IModel> modelClass) {
models.add(modelClass); models.add(modelClass);
} }
/**
* Adding a route
*
* @param object the instance of the route to add
*/
private static void addRoute(Object object) { private static void addRoute(Object object) {
List<Method> methods = routes.getOrDefault(object, new ArrayList<>()); List<Method> methods = routes.getOrDefault(object, new ArrayList<>());
for (Method method : object.getClass().getMethods()) { for (Method method : object.getClass().getMethods()) {

@ -1,16 +1,14 @@
package zone.themcgamer.api; package zone.themcgamer.api;
import lombok.NoArgsConstructor;
/** /**
* This {@link RuntimeException} gets thrown when there is a problem handling a {@link RestPath}
*
* @author Braydon * @author Braydon
*/ */
@NoArgsConstructor
public class APIException extends RuntimeException { public class APIException extends RuntimeException {
/**
* Constructs a new runtime exception with {@code null} as its
* detail message. The cause is not initialized, and may subsequently be
* initialized by a call to {@link #initCause}.
*/
public APIException() {}
/** /**
* Constructs a new runtime exception with the specified detail message. * Constructs a new runtime exception with the specified detail message.
* The cause is not initialized, and may subsequently be initialized by a * The cause is not initialized, and may subsequently be initialized by a

@ -4,6 +4,8 @@ import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
/** /**
* The API version is used in {@link RestPath}. It represents the version the path is using
*
* @author Braydon * @author Braydon
*/ */
@AllArgsConstructor @Getter @AllArgsConstructor @Getter

@ -8,6 +8,8 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* This annotation represents information for a specific Rest path
*
* @author Braydon * @author Braydon
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)

@ -3,6 +3,8 @@ package zone.themcgamer.api.model;
import java.util.HashMap; import java.util.HashMap;
/** /**
* This interface represents a custom Object that will displayed as json when handling requests
*
* @author Braydon * @author Braydon
*/ */
public interface IModel { public interface IModel {

@ -9,6 +9,8 @@ import java.lang.reflect.Type;
import java.util.Map; import java.util.Map;
/** /**
* This class handles serializing of {@link IModel}'s
*
* @author Braydon * @author Braydon
*/ */
public class ModelSerializer implements JsonSerializer<IModel> { public class ModelSerializer implements JsonSerializer<IModel> {

@ -13,7 +13,7 @@ import java.util.UUID;
* @author Braydon * @author Braydon
*/ */
@AllArgsConstructor @Setter @Getter @ToString @AllArgsConstructor @Setter @Getter @ToString
public class StatusModel implements IModel { public class PlayerStatusModel implements IModel {
private final UUID uuid; private final UUID uuid;
private final String playerName; private final String playerName;
private String server; private String server;

@ -14,6 +14,8 @@ import java.util.Objects;
import java.util.UUID; import java.util.UUID;
/** /**
* This repository handles fetching of {@link AccountModel}'s from MySQL
*
* @author Braydon * @author Braydon
*/ */
public class AccountRepository extends MySQLRepository { public class AccountRepository extends MySQLRepository {
@ -23,6 +25,12 @@ public class AccountRepository extends MySQLRepository {
super(dataSource); super(dataSource);
} }
/**
* Fetch the {@link AccountModel} with the provided {@link UUID}
*
* @param uuid the uuid of the account
* @return the account, null if it doesn't exist
*/
public AccountModel getAccount(UUID uuid) { public AccountModel getAccount(UUID uuid) {
AccountModel[] model = new AccountModel[] { null }; AccountModel[] model = new AccountModel[] { null };
executeQuery(SELECT_ACCOUNT, new Column[] { executeQuery(SELECT_ACCOUNT, new Column[] {
@ -40,6 +48,7 @@ public class AccountRepository extends MySQLRepository {
/** /**
* Construct a {@link AccountModel} from the given parameters * Construct a {@link AccountModel} from the given parameters
*
* @param uuid the uuid * @param uuid the uuid
* @param resultSet the result set * @param resultSet the result set
* @return the account * @return the account

@ -18,6 +18,8 @@ import java.util.UUID;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* This route handles everything associated with {@link AccountModel}
*
* @author Braydon * @author Braydon
*/ */
@AllArgsConstructor @AllArgsConstructor
@ -29,6 +31,9 @@ public class AccountRoute {
private final AccountRepository accountRepository; private final AccountRepository accountRepository;
/**
* This path handles displaying the {@link AccountModel} with the given {@link UUID}
*/
@RestPath(path = "/account/:uuid", version = APIVersion.V1) @RestPath(path = "/account/:uuid", version = APIVersion.V1)
public AccountModel get(Request request, Response response, APIKey apiKey) throws APIException { public AccountModel get(Request request, Response response, APIKey apiKey) throws APIException {
UUID uuid = MiscUtils.getUuid(request.params(":uuid")); UUID uuid = MiscUtils.getUuid(request.params(":uuid"));

@ -5,7 +5,7 @@ import spark.Response;
import zone.themcgamer.api.APIException; import zone.themcgamer.api.APIException;
import zone.themcgamer.api.APIVersion; import zone.themcgamer.api.APIVersion;
import zone.themcgamer.api.RestPath; import zone.themcgamer.api.RestPath;
import zone.themcgamer.api.model.impl.StatusModel; import zone.themcgamer.api.model.impl.PlayerStatusModel;
import zone.themcgamer.data.APIAccessLevel; import zone.themcgamer.data.APIAccessLevel;
import zone.themcgamer.data.jedis.cache.CacheRepository; import zone.themcgamer.data.jedis.cache.CacheRepository;
import zone.themcgamer.data.jedis.cache.ICacheItem; import zone.themcgamer.data.jedis.cache.ICacheItem;
@ -19,15 +19,20 @@ import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* This route handles everything associated with {@link PlayerStatusModel}
*
* @author Braydon * @author Braydon
*/ */
public class StatusRoute { public class PlayerStatusRoute {
private final CacheRepository repository; private final CacheRepository repository;
public StatusRoute() { public PlayerStatusRoute() {
repository = RedisRepository.getRepository(CacheRepository.class).orElse(null); repository = RedisRepository.getRepository(CacheRepository.class).orElse(null);
} }
/**
* This path handles displaying of all of the {@link PlayerStatusModel}'s
*/
@RestPath(path = "/status", version = APIVersion.V1) @RestPath(path = "/status", version = APIVersion.V1)
public Map<String, Object> getStatuses(Request request, Response response, APIKey apiKey) throws APIException { public Map<String, Object> getStatuses(Request request, Response response, APIKey apiKey) throws APIException {
List<ICacheItem<?>> statuses = repository.filter(cacheItem -> cacheItem.getType() == ItemCacheType.PLAYER_STATUS); List<ICacheItem<?>> statuses = repository.filter(cacheItem -> cacheItem.getType() == ItemCacheType.PLAYER_STATUS);
@ -44,8 +49,11 @@ public class StatusRoute {
}}; }};
} }
/**
* This path handles displaying the {@link PlayerStatusModel} with the given name
*/
@RestPath(path = "/status/:name", version = APIVersion.V1) @RestPath(path = "/status/:name", version = APIVersion.V1)
public StatusModel getStatus(Request request, Response response, APIKey apiKey) throws APIException { public PlayerStatusModel getStatus(Request request, Response response, APIKey apiKey) throws APIException {
String name = request.params(":name"); String name = request.params(":name");
if (name == null || (name.trim().isEmpty() || name.length() > 16)) if (name == null || (name.trim().isEmpty() || name.length() > 16))
throw new APIException("Invalid username"); throw new APIException("Invalid username");
@ -54,7 +62,7 @@ public class StatusRoute {
.stream().findFirst().orElse(null); .stream().findFirst().orElse(null);
if (statusCache == null) if (statusCache == null)
throw new APIException("Player not found"); throw new APIException("Player not found");
StatusModel model = new StatusModel(statusCache.getUuid(), statusCache.getPlayerName(), statusCache.getServer(), statusCache.getTimeJoined()); PlayerStatusModel model = new PlayerStatusModel(statusCache.getUuid(), statusCache.getPlayerName(), statusCache.getServer(), statusCache.getTimeJoined());
if (apiKey.getAccessLevel() == APIAccessLevel.STANDARD) if (apiKey.getAccessLevel() == APIAccessLevel.STANDARD)
model.setServer("Unauthorized"); model.setServer("Unauthorized");
return model; return model;

@ -20,6 +20,8 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
/** /**
* This route handles everything associated with {@link ServerGroupModel} and {@link MinecraftServerModel}
*
* @author Braydon * @author Braydon
*/ */
public class ServersRoute { public class ServersRoute {
@ -31,10 +33,9 @@ public class ServersRoute {
minecraftServerRepository = RedisRepository.getRepository(MinecraftServerRepository.class).orElse(null); minecraftServerRepository = RedisRepository.getRepository(MinecraftServerRepository.class).orElse(null);
} }
/* /**
Server Groups * This path handles displaying of all of the {@link ServerGroupModel}'s
*/ */
@RestPath(path = "/serverGroups", version = APIVersion.V1, accessLevel = APIAccessLevel.DEV) @RestPath(path = "/serverGroups", version = APIVersion.V1, accessLevel = APIAccessLevel.DEV)
public List<ServerGroupModel> getGroups(Request request, Response response, APIKey apiKey) throws APIException { public List<ServerGroupModel> getGroups(Request request, Response response, APIKey apiKey) throws APIException {
List<ServerGroupModel> models = new ArrayList<>(); List<ServerGroupModel> models = new ArrayList<>();
@ -43,6 +44,9 @@ public class ServersRoute {
return models; return models;
} }
/**
* This path handles displaying the {@link ServerGroupModel} with the given name
*/
@RestPath(path = "/serverGroup/:name", version = APIVersion.V1, accessLevel = APIAccessLevel.DEV) @RestPath(path = "/serverGroup/:name", version = APIVersion.V1, accessLevel = APIAccessLevel.DEV)
public ServerGroupModel getServerGroup(Request request, Response response, APIKey apiKey) throws APIException { public ServerGroupModel getServerGroup(Request request, Response response, APIKey apiKey) throws APIException {
String name = request.params(":name"); String name = request.params(":name");
@ -54,10 +58,9 @@ public class ServersRoute {
return ServerGroupModel.fromServerGroup(optionalServerGroup.get()); return ServerGroupModel.fromServerGroup(optionalServerGroup.get());
} }
/* /**
Minecraft Servers * This path handles displaying of all of the {@link MinecraftServerModel}'s
*/ */
@RestPath(path = "/minecraftServers", version = APIVersion.V1, accessLevel = APIAccessLevel.DEV) @RestPath(path = "/minecraftServers", version = APIVersion.V1, accessLevel = APIAccessLevel.DEV)
public List<MinecraftServerModel> getMinecraftServers(Request request, Response response, APIKey apiKey) throws APIException { public List<MinecraftServerModel> getMinecraftServers(Request request, Response response, APIKey apiKey) throws APIException {
List<MinecraftServerModel> models = new ArrayList<>(); List<MinecraftServerModel> models = new ArrayList<>();
@ -66,6 +69,9 @@ public class ServersRoute {
return models; return models;
} }
/**
* This path handles displaying the {@link MinecraftServerModel} with the given id
*/
@RestPath(path = "/minecraftServer/:id", version = APIVersion.V1, accessLevel = APIAccessLevel.DEV) @RestPath(path = "/minecraftServer/:id", version = APIVersion.V1, accessLevel = APIAccessLevel.DEV)
public MinecraftServerModel getMinecraftServer(Request request, Response response, APIKey apiKey) throws APIException { public MinecraftServerModel getMinecraftServer(Request request, Response response, APIKey apiKey) throws APIException {
String id = request.params(":id"); String id = request.params(":id");

@ -169,6 +169,8 @@ public class PlayerListener implements Listener {
@EventHandler @EventHandler
private void onBlockInteract(PlayerInteractEvent event) { private void onBlockInteract(PlayerInteractEvent event) {
if (event.getPlayer().getGameMode() == GameMode.CREATIVE)
return;
Block block = event.getClickedBlock(); Block block = event.getClickedBlock();
if (block == null) if (block == null)
return; return;