diff --git a/pom.xml b/pom.xml index f1df3f4..93674a3 100644 --- a/pom.xml +++ b/pom.xml @@ -14,6 +14,7 @@ me.braydon RESTfulMC 1.0.0 + A simple, yet useful RESTful API for Minecraft utilizing Springboot. @@ -31,6 +32,19 @@ org.springframework.boot spring-boot-maven-plugin + + + build-info + + build-info + + + + ${project.description} + + + + diff --git a/src/main/java/me/braydon/mc/RESTfulMC.java b/src/main/java/me/braydon/mc/RESTfulMC.java index 75a9992..413d2d1 100644 --- a/src/main/java/me/braydon/mc/RESTfulMC.java +++ b/src/main/java/me/braydon/mc/RESTfulMC.java @@ -23,13 +23,6 @@ */ package me.braydon.mc; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import io.swagger.v3.oas.annotations.OpenAPIDefinition; -import io.swagger.v3.oas.annotations.info.Contact; -import io.swagger.v3.oas.annotations.info.Info; -import io.swagger.v3.oas.annotations.info.License; -import io.swagger.v3.oas.annotations.servers.Server; import lombok.NonNull; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -47,18 +40,7 @@ import java.util.Objects; */ @SpringBootApplication(exclude = { JacksonAutoConfiguration.class }) @Slf4j(topic = "RESTfulMC") -@OpenAPIDefinition(info = @Info( - title = "RESTfulMC", - description = "A simple, yet useful RESTful API for Minecraft utilizing Springboot.", - version = "1.0.0", - contact = @Contact(name = "Braydon (Rainnny)", url = "https://rainnny.club", email = "braydonrainnny@gmail.com"), - license = @License(name = "MIT License", url = "https://opensource.org/license/MIT") -), servers = @Server(url = "https://mc.rainnny.club", description = "Production Server")) public class RESTfulMC { - public static final Gson GSON = new GsonBuilder() - .setDateFormat("MM-dd-yyyy HH:mm:ss") - .create(); - @SneakyThrows public static void main(@NonNull String[] args) { // Handle loading of our configuration file diff --git a/src/main/java/me/braydon/mc/common/DNSUtils.java b/src/main/java/me/braydon/mc/common/DNSUtils.java index ae23a72..1b60125 100644 --- a/src/main/java/me/braydon/mc/common/DNSUtils.java +++ b/src/main/java/me/braydon/mc/common/DNSUtils.java @@ -40,10 +40,11 @@ public final class DNSUtils { private static final String SRV_QUERY_PREFIX = "_minecraft._tcp.%s"; /** - * Resolve the hostname to an {@link InetSocketAddress}. + * Get the resolved address and port of the + * given hostname by resolving the SRV records. * * @param hostname the hostname to resolve - * @return the resolved {@link InetSocketAddress} + * @return the resolved address and port, null if none */ @SneakyThrows public static InetSocketAddress resolveSRV(@NonNull String hostname) { @@ -61,6 +62,13 @@ public final class DNSUtils { return host == null ? null : new InetSocketAddress(host, port); } + /** + * Get the resolved address of the given + * hostname by resolving the A records. + * + * @param hostname the hostname to resolve + * @return the resolved address, null if none + */ @SneakyThrows public static InetAddress resolveA(@NonNull String hostname) { Record[] records = new Lookup(hostname, Type.A).run(); // Resolve A records diff --git a/src/main/java/me/braydon/mc/common/web/JsonWebRequest.java b/src/main/java/me/braydon/mc/common/web/JsonWebRequest.java index 95a8469..df44d41 100644 --- a/src/main/java/me/braydon/mc/common/web/JsonWebRequest.java +++ b/src/main/java/me/braydon/mc/common/web/JsonWebRequest.java @@ -27,7 +27,7 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; -import me.braydon.mc.RESTfulMC; +import me.braydon.mc.config.AppConfig; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; @@ -118,7 +118,7 @@ public final class JsonWebRequest { throw new IOException("Failed to make a %s request to %s: %s".formatted(method.name(), endpoint, status)); } // Return with the response as the type - return RESTfulMC.GSON.fromJson(response.body(), responseType); + return AppConfig.GSON.fromJson(response.body(), responseType); } catch (Exception ex) { if (!(ex instanceof JsonWebException)) { throw new JsonWebException(status, ex); diff --git a/src/main/java/me/braydon/mc/config/AppConfig.java b/src/main/java/me/braydon/mc/config/AppConfig.java index 86cb96f..34e7e15 100644 --- a/src/main/java/me/braydon/mc/config/AppConfig.java +++ b/src/main/java/me/braydon/mc/config/AppConfig.java @@ -23,10 +23,26 @@ */ package me.braydon.mc.config; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.servers.Server; import jakarta.annotation.PostConstruct; import lombok.Getter; +import lombok.NonNull; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.info.BuildProperties; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.GsonHttpMessageConverter; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.List; /** * The configuration for the app. @@ -34,14 +50,70 @@ import org.springframework.context.annotation.Configuration; * @author Braydon */ @Configuration @Getter -public class AppConfig { +public class AppConfig implements WebMvcConfigurer { public static AppConfig INSTANCE; + public static final Gson GSON = new GsonBuilder() + .setDateFormat("MM-dd-yyyy HH:mm:ss") + .create(); @Value("${server.publicUrl}") private String serverPublicUrl; + /** + * The build properties of the + * app, null if the app is not built. + */ + private final BuildProperties buildProperties; + + @Autowired + public AppConfig(BuildProperties buildProperties) { + this.buildProperties = buildProperties; + } + @PostConstruct public void onInitialize() { INSTANCE = this; } + + /** + * Define the OpenAI specification for this app. + * + * @return the specification + */ + @Bean @NonNull + public OpenAPI defineOpenAPI() { + Info info = new Info(); + info.setTitle("RESTfulMC"); + info.setVersion(buildProperties == null ? "N/A" : buildProperties.getVersion()); + info.setDescription(buildProperties == null ? "N/A" : buildProperties.get("description")); + info.setContact(new Contact().name("Braydon (Rainnny)").url("https://rainnny.club").email("braydonrainnny@gmail.com")); + info.setLicense(new License().name("MIT License").url("https://opensource.org/licenses/MIT")); + + return new OpenAPI() + .info(info) + .addServersItem(new Server().url(serverPublicUrl).description("The public server URL")); + } + + /** + * Configure the default HTTP + * message converters to use Gson. + * + * @param converters the converters + */ + @Override + public void configureMessageConverters(@NonNull List> converters) { + GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter(); + gsonHttpMessageConverter.setGson(gson()); + converters.add(gsonHttpMessageConverter); + } + + /** + * Our custom Gson instance to use. + * + * @return the Gson instance + */ + @Bean @NonNull + public Gson gson() { + return GSON; + } } \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/config/WebMvcConfig.java b/src/main/java/me/braydon/mc/config/WebMvcConfig.java deleted file mode 100644 index dbeab90..0000000 --- a/src/main/java/me/braydon/mc/config/WebMvcConfig.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.config; - -import com.google.gson.Gson; -import me.braydon.mc.RESTfulMC; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.json.GsonHttpMessageConverter; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -import java.util.List; - -/** - * @author Braydon - */ -@Configuration -public class WebMvcConfig implements WebMvcConfigurer { - @Override - public void configureMessageConverters(List> converters) { - GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter(); - gsonHttpMessageConverter.setGson(gson()); - converters.add(gsonHttpMessageConverter); - } - - @Bean - public Gson gson() { - return RESTfulMC.GSON; - } -} \ 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 2050493..e88e713 100644 --- a/src/main/java/me/braydon/mc/model/server/JavaMinecraftServer.java +++ b/src/main/java/me/braydon/mc/model/server/JavaMinecraftServer.java @@ -25,7 +25,6 @@ package me.braydon.mc.model.server; import com.google.gson.annotations.SerializedName; import lombok.*; -import me.braydon.mc.RESTfulMC; import me.braydon.mc.common.JavaMinecraftVersion; import me.braydon.mc.config.AppConfig; import me.braydon.mc.model.MinecraftServer; @@ -104,7 +103,7 @@ public final class JavaMinecraftServer extends MinecraftServer { public static JavaMinecraftServer create(@NonNull String hostname, String ip, int port, @NonNull JavaServerStatusToken token) { String motdString = token.getDescription() instanceof String ? (String) token.getDescription() : null; if (motdString == null) { // Not a string motd, convert from Json - motdString = new TextComponent(ComponentSerializer.parse(RESTfulMC.GSON.toJson(token.getDescription()))).toLegacyText(); + motdString = new TextComponent(ComponentSerializer.parse(AppConfig.GSON.toJson(token.getDescription()))).toLegacyText(); } return new JavaMinecraftServer(hostname, ip, port, token.getVersion().detailedCopy(), token.getPlayers(), MOTD.create(motdString), Favicon.create(token.getFavicon(), hostname), token.getModInfo(), diff --git a/src/main/java/me/braydon/mc/model/token/MojangProfileToken.java b/src/main/java/me/braydon/mc/model/token/MojangProfileToken.java index adb8231..d3da2f8 100644 --- a/src/main/java/me/braydon/mc/model/token/MojangProfileToken.java +++ b/src/main/java/me/braydon/mc/model/token/MojangProfileToken.java @@ -25,8 +25,8 @@ package me.braydon.mc.model.token; import com.google.gson.JsonObject; import lombok.*; -import me.braydon.mc.RESTfulMC; import me.braydon.mc.common.Tuple; +import me.braydon.mc.config.AppConfig; import me.braydon.mc.model.Cape; import me.braydon.mc.model.ProfileAction; import me.braydon.mc.model.Skin; @@ -71,7 +71,7 @@ public final class MojangProfileToken { if (textures == null) { // No profile textures return new Tuple<>(); } - JsonObject jsonObject = RESTfulMC.GSON.fromJson(textures.getDecodedValue(), JsonObject.class); // Get the Json object + JsonObject jsonObject = AppConfig.GSON.fromJson(textures.getDecodedValue(), JsonObject.class); // Get the Json object JsonObject texturesJsonObject = jsonObject.getAsJsonObject("textures"); // Get the textures object // Return the tuple containing the skin and cape 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 0817bd3..a06684b 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 @@ -25,10 +25,10 @@ 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.java.JavaPacketHandshakingInSetProtocol; import me.braydon.mc.common.packet.impl.java.JavaPacketStatusInStart; +import me.braydon.mc.config.AppConfig; import me.braydon.mc.exception.impl.BadRequestException; import me.braydon.mc.exception.impl.ResourceNotFoundException; import me.braydon.mc.model.server.JavaMinecraftServer; @@ -86,7 +86,7 @@ public final class JavaMinecraftServerPinger implements MinecraftServerPinger