47 Commits

Author SHA1 Message Date
9a0b6e1635 Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.4.1 2024-10-28 18:01:00 +00:00
Lee
0bc614ce39 Merge pull request 'Update dependency com.influxdb:influxdb-client-java to v7.2.0' (#44) from renovate/com.influxdb-influxdb-client-java-7.x into master
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 2m36s
Reviewed-on: #44
2024-08-13 17:28:18 +00:00
Lee
499c54c8cf Merge pull request 'Update dependency io.sentry:sentry-spring-boot-starter-jakarta to v7.14.0' (#46) from renovate/io.sentry-sentry-spring-boot-starter-jakarta-7.x into master
Some checks failed
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Has been cancelled
Reviewed-on: #46
2024-08-13 17:28:09 +00:00
Lee
41f7ca07b0 Merge pull request 'Update dependency com.influxdb:influxdb-spring to v7.2.0' (#45) from renovate/com.influxdb-influxdb-spring-7.x into master
Some checks failed
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Has been cancelled
Reviewed-on: #45
2024-08-13 17:26:51 +00:00
5ec61940ac Update dependency io.sentry:sentry-spring-boot-starter-jakarta to v7.14.0 2024-08-13 09:01:06 +00:00
6665e8a655 Update dependency com.influxdb:influxdb-spring to v7.2.0 2024-08-12 08:01:06 +00:00
07562eb94d Update dependency com.influxdb:influxdb-client-java to v7.2.0 2024-08-12 08:01:04 +00:00
Lee
a78adf67c7 Merge pull request 'Update dependency io.sentry:sentry-spring-boot-starter-jakarta to v7.13.0' (#43) from renovate/io.sentry-sentry-spring-boot-starter-jakarta-7.x into master
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 2m13s
Reviewed-on: #43
2024-07-31 15:59:25 +00:00
fc1f51da75 Update dependency io.sentry:sentry-spring-boot-starter-jakarta to v7.13.0 2024-07-31 10:00:30 +00:00
c796875d8c increase the timeout for mojang servers
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 3m12s
2024-07-30 22:06:01 +01:00
82fb2a3d23 Merge remote-tracking branch 'origin/master'
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 3m15s
2024-07-30 22:00:30 +01:00
2e326bb7be oopsie 2024-07-30 22:00:07 +01:00
Lee
c5bf941c54 Merge pull request 'Update dependency de.flapdoodle.embed:de.flapdoodle.embed.mongo.spring3x to v4.16.1' (#22) from renovate/de.flapdoodle.embed-de.flapdoodle.embed.mongo.spring3x-4.x into master
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 2m0s
Reviewed-on: #22
2024-07-30 20:55:26 +00:00
Lee
0eb965a26d Merge pull request 'Update dependency org.springframework.boot:spring-boot-starter-parent to v3.3.2' (#42) from renovate/org.springframework.boot-spring-boot-starter-parent-3.x into master
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 2m58s
Reviewed-on: #42
2024-07-30 20:52:18 +00:00
Lee
5481c9302c Merge pull request 'Update dependency io.sentry:sentry-spring-boot-starter-jakarta to v7.12.1' (#21) from renovate/io.sentry-sentry-spring-boot-starter-jakarta-7.x into master
Some checks failed
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Has been cancelled
Reviewed-on: #21
2024-07-30 20:52:12 +00:00
b7834ab389 change how the mojang server status' are fetched
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 2m9s
2024-07-30 21:04:37 +01:00
bb651bd88b Merge remote-tracking branch 'origin/master'
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 3m47s
2024-07-30 20:52:09 +01:00
2b017f9ef7 fix mojang status endpoint 2024-07-30 20:49:36 +01:00
d83391de33 Update dependency org.springframework.boot:spring-boot-starter-parent to v3.3.2 2024-07-26 12:03:27 +00:00
76bef70473 Update dependency io.sentry:sentry-spring-boot-starter-jakarta to v7.12.1 2024-07-25 13:00:32 +00:00
4aa5b0a90d Update dependency de.flapdoodle.embed:de.flapdoodle.embed.mongo.spring3x to v4.16.1 2024-07-18 16:00:22 +00:00
Lee
6a44618ae9 Merge pull request 'Update dependency org.codehaus.plexus:plexus-archiver to v4.10.0' (#20) from renovate/org.codehaus.plexus-plexus-archiver-4.x into master
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 2m12s
Reviewed-on: #20
2024-07-06 18:48:57 +00:00
146d053af8 Update dependency org.codehaus.plexus:plexus-archiver to v4.10.0 2024-07-06 08:00:23 +00:00
Lee
796146c039 Merge pull request 'Update dependency de.flapdoodle.embed:de.flapdoodle.embed.mongo.spring3x to v4.15.0' (#10) from renovate/de.flapdoodle.embed-de.flapdoodle.embed.mongo.spring3x-4.x into master
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 2m44s
Reviewed-on: #10
2024-07-06 07:34:23 +00:00
Lee
00c83d9ae3 Merge pull request 'Update dependency io.sentry:sentry-spring-boot-starter-jakarta to v7.11.0' (#11) from renovate/io.sentry-sentry-spring-boot-starter-jakarta-7.x into master
Some checks failed
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Has been cancelled
Reviewed-on: #11
2024-07-06 07:34:16 +00:00
Lee
3bbab24e45 Merge pull request 'Update dependency com.influxdb:influxdb-client-java to v7.1.0' (#12) from renovate/com.influxdb-influxdb-client-java-7.x into master
Some checks are pending
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Waiting to run
Reviewed-on: #12
2024-07-06 07:34:08 +00:00
Lee
5034a11e63 Merge pull request 'Update dependency com.influxdb:influxdb-spring to v7.1.0' (#13) from renovate/com.influxdb-influxdb-spring-7.x into master
Some checks are pending
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Waiting to run
Reviewed-on: #13
2024-07-06 07:34:01 +00:00
Lee
3d11c65678 Merge pull request 'Update s4u/setup-maven-action action to v1.14.0' (#14) from renovate/s4u-setup-maven-action-1.x into master
Some checks are pending
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Waiting to run
Reviewed-on: #14
2024-07-06 07:33:54 +00:00
Lee
fd3da02159 Merge pull request 'Update dependency com.google.code.gson:gson to v2.11.0' (#15) from renovate/com.google.code.gson-gson-2.x into master
Some checks are pending
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Waiting to run
Reviewed-on: #15
2024-07-06 07:33:46 +00:00
Lee
0bdaefe4a2 Merge pull request 'Update dependency org.springframework.boot:spring-boot-starter-parent to v3.3.1' (#16) from renovate/spring-boot into master
Some checks failed
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Has been cancelled
Reviewed-on: #16
2024-07-06 07:33:38 +00:00
Lee
ba167b4e56 Merge pull request 'Update maven Docker tag to v3.9.8' (#17) from renovate/maven-3.x into master
Some checks failed
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Has been cancelled
Reviewed-on: #17
2024-07-06 07:33:18 +00:00
Lee
493e7ce4c0 Merge pull request 'Update dependency org.projectlombok:lombok to v1.18.34' (#18) from renovate/org.projectlombok-lombok-1.x into master
Some checks failed
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Has been cancelled
Reviewed-on: #18
2024-07-06 07:33:08 +00:00
Lee
7f501431b1 Merge pull request 'Update dependency org.springdoc:springdoc-openapi-starter-webmvc-ui to v2.6.0' (#19) from renovate/org.springdoc-springdoc-openapi-starter-webmvc-ui-2.x into master
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 3m35s
Reviewed-on: #19
2024-07-06 07:28:56 +00:00
fa92791b56 Update dependency de.flapdoodle.embed:de.flapdoodle.embed.mongo.spring3x to v4.15.0 2024-07-04 18:00:28 +00:00
6750773640 Update dependency io.sentry:sentry-spring-boot-starter-jakarta to v7.11.0 2024-07-01 17:00:30 +00:00
cecc6bc94f Update dependency org.springdoc:springdoc-openapi-starter-webmvc-ui to v2.6.0 2024-06-30 19:00:29 +00:00
20db1c1aff Update s4u/setup-maven-action action to v1.14.0 2024-06-29 08:00:30 +00:00
e62e7f0fc2 Update dependency org.projectlombok:lombok to v1.18.34 2024-06-28 01:00:20 +00:00
c9ed681204 Update maven Docker tag to v3.9.8 2024-06-27 18:00:21 +00:00
c6642e85fe Update dependency org.springframework.boot:spring-boot-starter-parent to v3.3.1 2024-06-20 12:00:34 +00:00
9dfbd1af47 Update dependency com.google.code.gson:gson to v2.11.0 2024-05-19 20:01:05 +00:00
c8629e4f27 Update dependency com.influxdb:influxdb-spring to v7.1.0 2024-05-17 10:01:10 +00:00
a6209c45ff Update dependency com.influxdb:influxdb-client-java to v7.1.0 2024-05-17 10:01:07 +00:00
ee5b1f12d8 Merge branch 'master' of https://git.fascinated.cc/MinecraftUtilities/Backend
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 2m16s
2024-04-22 22:07:52 +01:00
ff79372ead don't throw an error on geo lookup error 2024-04-22 22:06:11 +01:00
Lee
f0e1490463 Merge pull request 'Update dependency org.codehaus.plexus:plexus-archiver to v4.9.2' (#9) from renovate/org.codehaus.plexus-plexus-archiver-4.x into master
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 2m15s
Reviewed-on: #9
2024-04-21 23:10:18 +00:00
9196ec3578 Update dependency org.codehaus.plexus:plexus-archiver to v4.9.2 2024-04-21 23:00:39 +00:00
17 changed files with 181 additions and 103 deletions

View File

@ -27,7 +27,7 @@ jobs:
# Setup Java and Maven # Setup Java and Maven
- name: Set up JDK and Maven - name: Set up JDK and Maven
uses: s4u/setup-maven-action@v1.12.0 uses: s4u/setup-maven-action@v1.14.0
with: with:
java-version: ${{ matrix.java-version }} java-version: ${{ matrix.java-version }}
distribution: "zulu" distribution: "zulu"

View File

@ -1,4 +1,4 @@
FROM maven:3.9.6-eclipse-temurin-17-alpine FROM maven:3.9.8-eclipse-temurin-17-alpine
RUN apk --update --upgrade --no-cache add fontconfig ttf-freefont font-noto terminus-font \ RUN apk --update --upgrade --no-cache add fontconfig ttf-freefont font-noto terminus-font \
&& fc-cache -f \ && fc-cache -f \

20
pom.xml
View File

@ -17,7 +17,7 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version> <version>3.3.2</version>
<relativePath/> <!-- lookup parent from repository --> <relativePath/> <!-- lookup parent from repository -->
</parent> </parent>
@ -93,13 +93,13 @@
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<version>1.18.32</version> <version>1.18.34</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.google.code.gson</groupId> <groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId> <artifactId>gson</artifactId>
<version>2.10.1</version> <version>2.11.0</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -122,7 +122,7 @@
<dependency> <dependency>
<groupId>org.apache.httpcomponents.client5</groupId> <groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId> <artifactId>httpclient5</artifactId>
<version>5.3.1</version> <version>5.4.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@ -133,20 +133,20 @@
<dependency> <dependency>
<groupId>io.sentry</groupId> <groupId>io.sentry</groupId>
<artifactId>sentry-spring-boot-starter-jakarta</artifactId> <artifactId>sentry-spring-boot-starter-jakarta</artifactId>
<version>7.8.0</version> <version>7.14.0</version>
</dependency> </dependency>
<!-- InfluxDB Metrics --> <!-- InfluxDB Metrics -->
<dependency> <dependency>
<groupId>com.influxdb</groupId> <groupId>com.influxdb</groupId>
<artifactId>influxdb-spring</artifactId> <artifactId>influxdb-spring</artifactId>
<version>7.0.0</version> <version>7.2.0</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.influxdb</groupId> <groupId>com.influxdb</groupId>
<artifactId>influxdb-client-java</artifactId> <artifactId>influxdb-client-java</artifactId>
<version>7.0.0</version> <version>7.2.0</version>
</dependency> </dependency>
<!-- DNS Lookup --> <!-- DNS Lookup -->
@ -161,7 +161,7 @@
<dependency> <dependency>
<groupId>org.springdoc</groupId> <groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.5.0</version> <version>2.6.0</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@ -176,7 +176,7 @@
<dependency> <dependency>
<groupId>org.codehaus.plexus</groupId> <groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-archiver</artifactId> <artifactId>plexus-archiver</artifactId>
<version>4.9.1</version> <version>4.10.0</version>
</dependency> </dependency>
<!-- Tests --> <!-- Tests -->
@ -194,7 +194,7 @@
<dependency> <dependency>
<groupId>de.flapdoodle.embed</groupId> <groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo.spring3x</artifactId> <artifactId>de.flapdoodle.embed.mongo.spring3x</artifactId>
<version>4.12.6</version> <version>4.16.1</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -22,7 +22,7 @@ public final class AppConfig {
private static boolean isRunningTest = true; private static boolean isRunningTest = true;
static { static {
try { try {
Class.forName("org.junit.Test"); Class.forName("org.junit.jupiter.engine.JupiterTestEngine");
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
isRunningTest = false; isRunningTest = false;
} }

View File

@ -0,0 +1,85 @@
package xyz.mcutils.backend.common;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import lombok.ToString;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;
/**
* @author Fascinated (fascinated7)
*/
@AllArgsConstructor
@Getter
@ToString
public enum MojangServer {
SESSION("Session Server", "https://sessionserver.mojang.com"),
API("Mojang API", "https://api.mojang.com"),
TEXTURES("Textures Server", "https://textures.minecraft.net"),
ASSETS("Assets Server", "https://assets.mojang.com"),
LIBRARIES("Libraries Server", "https://libraries.minecraft.net"),
SERVICES("Minecraft Services", "https://api.minecraftservices.com");
private static final long STATUS_TIMEOUT = TimeUnit.SECONDS.toMillis(10);
/**
* The name of this server.
*/
@NonNull private final String name;
/**
* The endpoint of this service.
*/
@NonNull private final String endpoint;
/**
* Ping this service and get the status of it.
*
* @return the service status
*/
@NonNull
public Status getStatus() {
try {
InetAddress address = InetAddress.getByName(endpoint.substring(8));
long before = System.currentTimeMillis();
if (address.isReachable((int) STATUS_TIMEOUT)) {
// The time it took to reach the host is 75% of
// the timeout, consider it to be degraded.
if ((System.currentTimeMillis() - before) > STATUS_TIMEOUT * 0.75D) {
return Status.DEGRADED;
}
return Status.ONLINE;
}
} catch (UnknownHostException ex) {
ex.printStackTrace();
} catch (IOException ignored) {
// We can safely ignore any errors, we're simply checking
// if the host is reachable, if it's not, then it's offline.
}
return Status.OFFLINE;
}
/**
* The status of a service.
*/
public enum Status {
/**
* The service is online and accessible.
*/
ONLINE,
/**
* The service is online, but is experiencing degraded performance.
*/
DEGRADED,
/**
* The service is offline and inaccessible.
*/
OFFLINE
}
}

View File

@ -12,23 +12,21 @@ import org.springframework.web.bind.annotation.RestController;
import xyz.mcutils.backend.model.cache.CachedEndpointStatus; import xyz.mcutils.backend.model.cache.CachedEndpointStatus;
import xyz.mcutils.backend.service.MojangService; import xyz.mcutils.backend.service.MojangService;
import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@RestController @RestController
@Tag(name = "Mojang Controller", description = "The Mojang Controller is used to get information about the Mojang APIs.")
@RequestMapping(value = "/mojang/", produces = MediaType.APPLICATION_JSON_VALUE) @RequestMapping(value = "/mojang/", produces = MediaType.APPLICATION_JSON_VALUE)
@Tag(name = "Mojang Controller", description = "The Mojang Controller is used to get information about the Mojang APIs.")
public class MojangController { public class MojangController {
@Autowired @Autowired
private MojangService mojangService; private MojangService mojangService;
@ResponseBody @ResponseBody
@GetMapping(value = "/status") @GetMapping(value = "/status")
public ResponseEntity<CachedEndpointStatus> getStatus() { public ResponseEntity<?> getStatus() {
CachedEndpointStatus status = mojangService.getMojangApiStatus();
return ResponseEntity.ok() return ResponseEntity.ok()
.cacheControl(CacheControl.maxAge(1, TimeUnit.MINUTES).cachePublic()) .cacheControl(CacheControl.maxAge(1, TimeUnit.MINUTES).cachePublic())
.body(status); .body(Map.of("endpoints", mojangService.getMojangServerStatus()));
} }
} }

View File

@ -16,8 +16,8 @@ import xyz.mcutils.backend.service.PlayerService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@RestController @RestController
@Tag(name = "Player Controller", description = "The Player Controller is used to get information about a player.")
@RequestMapping(value = "/player/") @RequestMapping(value = "/player/")
@Tag(name = "Player Controller", description = "The Player Controller is used to get information about a player.")
public class PlayerController { public class PlayerController {
private final PlayerService playerService; private final PlayerService playerService;

View File

@ -16,8 +16,8 @@ import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@RestController @RestController
@Tag(name = "Server Controller", description = "The Server Controller is used to get information about a server.")
@RequestMapping(value = "/server/") @RequestMapping(value = "/server/")
@Tag(name = "Server Controller", description = "The Server Controller is used to get information about a server.")
public class ServerController { public class ServerController {
private final ServerService serverService; private final ServerService serverService;

View File

@ -1,6 +1,7 @@
package xyz.mcutils.backend.exception; package xyz.mcutils.backend.exception;
import io.micrometer.common.lang.NonNull; import io.micrometer.common.lang.NonNull;
import io.sentry.Sentry;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ControllerAdvice;
@ -39,6 +40,7 @@ public final class ExceptionControllerAdvice {
} }
if (status == null) { // Fallback to 500 if (status == null) { // Fallback to 500
status = HttpStatus.INTERNAL_SERVER_ERROR; status = HttpStatus.INTERNAL_SERVER_ERROR;
Sentry.captureException(ex); // Capture the exception with Sentry
} }
return new ResponseEntity<>(new ErrorResponse(status, message), status); return new ResponseEntity<>(new ErrorResponse(status, message), status);
} }

View File

@ -8,10 +8,13 @@ import lombok.Setter;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash; import org.springframework.data.redis.core.RedisHash;
import xyz.mcutils.backend.common.CachedResponse; import xyz.mcutils.backend.common.CachedResponse;
import xyz.mcutils.backend.model.mojang.EndpointStatus; import xyz.mcutils.backend.common.MojangServer;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
@Setter @Getter @EqualsAndHashCode(callSuper = false) @Setter @Getter @EqualsAndHashCode(callSuper = false)
@RedisHash(value = "mojangEndpointStatus", timeToLive = 60L) // 1 minute (in seconds) @RedisHash(value = "mojangEndpointStatus", timeToLive = 60L) // 1 minute (in seconds)
@ -26,11 +29,21 @@ public class CachedEndpointStatus extends CachedResponse implements Serializable
/** /**
* The endpoint cache. * The endpoint cache.
*/ */
private final List<EndpointStatus> endpoints; private final List<Map<String, Object>> endpoints;
public CachedEndpointStatus(@NonNull String id, List<EndpointStatus> endpoints) { public CachedEndpointStatus(@NonNull String id, Map<MojangServer, MojangServer.Status> mojangServers) {
super(Cache.defaultCache()); super(Cache.defaultCache());
this.id = id; this.id = id;
this.endpoints = endpoints; this.endpoints = new ArrayList<>();
for (Map.Entry<MojangServer, MojangServer.Status> entry : mojangServers.entrySet()) {
MojangServer server = entry.getKey();
Map<String, Object> serverStatus = new HashMap<>();
serverStatus.put("name", server.getName());
serverStatus.put("endpoint", server.getEndpoint());
serverStatus.put("status", entry.getValue().name());
endpoints.add(serverStatus);
}
} }
} }

View File

@ -58,7 +58,7 @@ public final class BedrockMinecraftServer extends MinecraftServer {
Edition edition = Edition.valueOf(split[0]); Edition edition = Edition.valueOf(split[0]);
Version version = new Version(Integer.parseInt(split[2]), split[3]); Version version = new Version(Integer.parseInt(split[2]), split[3]);
Players players = new Players(Integer.parseInt(split[4]), Integer.parseInt(split[5]), null); Players players = new Players(Integer.parseInt(split[4]), Integer.parseInt(split[5]), null);
MOTD motd = MOTD.create(split[1] + "\n" + split[7]); MOTD motd = MOTD.create(hostname, Platform.BEDROCK, split[1] + "\n" + split[7]);
GameMode gameMode = new GameMode(split[8], split.length > 9 ? Integer.parseInt(split[9]) : -1); GameMode gameMode = new GameMode(split[8], split.length > 9 ? Integer.parseInt(split[9]) : -1);
return new BedrockMinecraftServer( return new BedrockMinecraftServer(
split[6], split[6],

View File

@ -97,7 +97,7 @@ public final class JavaMinecraftServer extends MinecraftServer {
hostname, hostname,
ip, ip,
port, port,
MinecraftServer.MOTD.create(motdString), MinecraftServer.MOTD.create(hostname, Platform.JAVA, motdString),
token.getPlayers(), token.getPlayers(),
location, location,
records, records,

View File

@ -4,6 +4,7 @@ import com.maxmind.geoip2.model.CityResponse;
import io.micrometer.common.lang.NonNull; import io.micrometer.common.lang.NonNull;
import lombok.*; import lombok.*;
import xyz.mcutils.backend.common.ColorUtils; import xyz.mcutils.backend.common.ColorUtils;
import xyz.mcutils.backend.config.Config;
import xyz.mcutils.backend.model.dns.DNSRecord; import xyz.mcutils.backend.model.dns.DNSRecord;
import xyz.mcutils.backend.service.pinger.MinecraftServerPinger; import xyz.mcutils.backend.service.pinger.MinecraftServerPinger;
import xyz.mcutils.backend.service.pinger.impl.BedrockMinecraftServerPinger; import xyz.mcutils.backend.service.pinger.impl.BedrockMinecraftServerPinger;
@ -100,6 +101,11 @@ public class MinecraftServer {
*/ */
private final String[] html; private final String[] html;
/**
* The URL to the server preview image.
*/
private final String preview;
/** /**
* Create a new MOTD from a raw string. * Create a new MOTD from a raw string.
* *
@ -107,12 +113,14 @@ public class MinecraftServer {
* @return the new motd * @return the new motd
*/ */
@NonNull @NonNull
public static MOTD create(@NonNull String raw) { public static MOTD create(@NonNull String hostname, @NonNull Platform platform, @NonNull String raw) {
String[] rawLines = raw.split("\n"); // The raw lines String[] rawLines = raw.split("\n"); // The raw lines
return new MOTD( return new MOTD(
rawLines, rawLines,
Arrays.stream(rawLines).map(ColorUtils::stripColor).toArray(String[]::new), Arrays.stream(rawLines).map(ColorUtils::stripColor).toArray(String[]::new),
Arrays.stream(rawLines).map(ColorUtils::toHTML).toArray(String[]::new) Arrays.stream(rawLines).map(ColorUtils::toHTML).toArray(String[]::new),
Config.INSTANCE.getWebPublicUrl() + "/server/%s/preview/%s".formatted(
platform.name().toLowerCase(),hostname)
); );
} }
} }

View File

@ -1,11 +0,0 @@
package xyz.mcutils.backend.repository.redis;
import org.springframework.data.repository.CrudRepository;
import xyz.mcutils.backend.model.cache.CachedEndpointStatus;
/**
* A cache repository for {@link CachedEndpointStatus}'s.
*
* @author Braydon
*/
public interface EndpointStatusRepository extends CrudRepository<CachedEndpointStatus, String> { }

View File

@ -3,6 +3,7 @@ package xyz.mcutils.backend.service;
import com.maxmind.geoip2.DatabaseReader; import com.maxmind.geoip2.DatabaseReader;
import com.maxmind.geoip2.exception.GeoIp2Exception; import com.maxmind.geoip2.exception.GeoIp2Exception;
import com.maxmind.geoip2.model.CityResponse; import com.maxmind.geoip2.model.CityResponse;
import io.sentry.Sentry;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.codehaus.plexus.archiver.tar.TarGZipUnArchiver; import org.codehaus.plexus.archiver.tar.TarGZipUnArchiver;
@ -68,7 +69,8 @@ public class MaxMindService {
return database.city(InetAddress.getByName(ip)); return database.city(InetAddress.getByName(ip));
} catch (IOException | GeoIp2Exception e) { } catch (IOException | GeoIp2Exception e) {
log.error("Failed to lookup the GeoIP information for '{}'", ip, e); log.error("Failed to lookup the GeoIP information for '{}'", ip, e);
throw new RuntimeException("Failed to lookup the IP for '%s'".formatted(ip)); Sentry.captureException(e);
return null;
} }
} }

View File

@ -9,26 +9,23 @@ import lombok.Getter;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import net.jodah.expiringmap.ExpirationPolicy; import net.jodah.expiringmap.ExpirationPolicy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import xyz.mcutils.backend.common.AppConfig;
import xyz.mcutils.backend.common.ExpiringSet; import xyz.mcutils.backend.common.ExpiringSet;
import xyz.mcutils.backend.common.MojangServer;
import xyz.mcutils.backend.common.WebRequest; import xyz.mcutils.backend.common.WebRequest;
import xyz.mcutils.backend.model.cache.CachedEndpointStatus;
import xyz.mcutils.backend.model.mojang.EndpointStatus;
import xyz.mcutils.backend.model.token.MojangProfileToken; import xyz.mcutils.backend.model.token.MojangProfileToken;
import xyz.mcutils.backend.model.token.MojangUsernameToUuidToken; import xyz.mcutils.backend.model.token.MojangUsernameToUuidToken;
import xyz.mcutils.backend.repository.redis.EndpointStatusRepository;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.InetAddress;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@Service @Log4j2(topic = "Mojang Service") @Getter @Service
@Log4j2(topic = "Mojang Service")
@Getter
public class MojangService { public class MojangService {
/** /**
@ -50,19 +47,9 @@ public class MojangService {
private static final long FETCH_BLOCKED_SERVERS_INTERVAL = TimeUnit.HOURS.toMillis(1L); private static final long FETCH_BLOCKED_SERVERS_INTERVAL = TimeUnit.HOURS.toMillis(1L);
/** /**
* Information about the Mojang API endpoints. * The interval to fetch the Mojang server status.
*/ */
private static final String MOJANG_ENDPOINT_STATUS_KEY = "mojang"; private static final long FETCH_MOJANG_SERVERS_STATUS_INTERVAL = TimeUnit.MINUTES.toMillis(1L);
private static final List<EndpointStatus> MOJANG_ENDPOINTS = List.of(
new EndpointStatus("Minecraft Textures", "textures.minecraft.net"),
new EndpointStatus("Minecraft Libraries", "libraries.minecraft.net"),
new EndpointStatus("Minecraft Services", "api.minecraftservices.com"),
new EndpointStatus("Mojang Assets", "assets.mojang.com"),
new EndpointStatus("Mojang API", "api.mojang.com"),
new EndpointStatus("Mojang Session Server", "sessionserver.mojang.com"));
@Autowired
private EndpointStatusRepository mojangEndpointStatusRepository;
/** /**
* A list of banned server hashes provided by Mojang. * A list of banned server hashes provided by Mojang.
@ -82,6 +69,11 @@ public class MojangService {
*/ */
private final ExpiringSet<String> blockedServersCache = new ExpiringSet<>(ExpirationPolicy.CREATED, 10L, TimeUnit.MINUTES); private final ExpiringSet<String> blockedServersCache = new ExpiringSet<>(ExpirationPolicy.CREATED, 10L, TimeUnit.MINUTES);
/**
* The status of the Mojang API.
*/
private final List<Map<String, Object>> mojangServerStatus = new ArrayList<>();
public MojangService() { public MojangService() {
new Timer().scheduleAtFixedRate(new TimerTask() { new Timer().scheduleAtFixedRate(new TimerTask() {
@Override @Override
@ -89,6 +81,33 @@ public class MojangService {
fetchBlockedServers(); fetchBlockedServers();
} }
}, 0L, FETCH_BLOCKED_SERVERS_INTERVAL); }, 0L, FETCH_BLOCKED_SERVERS_INTERVAL);
new Timer().scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
log.info("Fetching Mojang Server status...");
Map<MojangServer, MojangServer.Status> mojangServers = new HashMap<>();
Arrays.stream(MojangServer.values()).parallel().forEach(server -> {
log.info("Pinging {}...", server.getEndpoint());
MojangServer.Status status = server.getStatus(); // Retrieve the server status
log.info("Retrieved status of {}: {}", server.getEndpoint(), status.name());
mojangServers.put(server, status); // Cache the server status
});
mojangServerStatus.clear();
for (Map.Entry<MojangServer, MojangServer.Status> entry : mojangServers.entrySet()) {
MojangServer server = entry.getKey();
Map<String, Object> serverStatus = new HashMap<>();
serverStatus.put("name", server.getName());
serverStatus.put("endpoint", server.getEndpoint());
serverStatus.put("status", entry.getValue().name());
mojangServerStatus.add(serverStatus);
}
log.info("Fetched Mojang Server status for {} endpoints", mojangServers.size());
}
}, 0L, FETCH_MOJANG_SERVERS_STATUS_INTERVAL);
} }
/** /**
@ -107,6 +126,8 @@ public class MojangService {
} }
bannedServerHashes = Collections.synchronizedList(hashes); bannedServerHashes = Collections.synchronizedList(hashes);
log.info("Fetched {} banned server hashes", bannedServerHashes.size()); log.info("Fetched {} banned server hashes", bannedServerHashes.size());
} catch (IOException e) {
log.error("Failed to fetch blocked servers from Mojang", e);
} }
} }
@ -177,46 +198,6 @@ public class MojangService {
return blocked; return blocked;
} }
/**
* Gets the status of the Mojang APIs.
*
* @return the status
*/
public CachedEndpointStatus getMojangApiStatus() {
log.info("Getting Mojang API status");
Optional<CachedEndpointStatus> endpointStatus = mojangEndpointStatusRepository.findById(MOJANG_ENDPOINT_STATUS_KEY);
if (endpointStatus.isPresent() && AppConfig.isProduction()) {
log.info("Got cached Mojang API status");
return endpointStatus.get();
}
MOJANG_ENDPOINTS.parallelStream().forEach(endpoint -> {
try {
long start = System.currentTimeMillis();
InetAddress address = InetAddress.getByName(endpoint.getHostname());
if (address.isReachable((int) TimeUnit.SECONDS.toMillis(4))) { // Check if the endpoint is reachable
endpoint.setStatus(EndpointStatus.Status.ONLINE);
return;
}
// Check if the endpoint took too long to respond
if (System.currentTimeMillis() - start > TimeUnit.SECONDS.toMillis(2)) {
endpoint.setStatus(EndpointStatus.Status.DEGRADED);
}
} catch (IOException e) {
endpoint.setStatus(EndpointStatus.Status.OFFLINE);
}
});
log.info("Fetched Mojang API status for {} endpoints", MOJANG_ENDPOINTS.size());
CachedEndpointStatus status = new CachedEndpointStatus(
MOJANG_ENDPOINT_STATUS_KEY,
MOJANG_ENDPOINTS
);
mojangEndpointStatusRepository.save(status);
status.getCache().setCached(false);
return status;
}
/** /**
* Gets the Session Server profile of the * Gets the Session Server profile of the
* player with the given UUID. * player with the given UUID.