-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 4adb570
Showing
11 changed files
with
396 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Project exclude paths | ||
/target/ | ||
/StatTrack/ | ||
/.idea/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<groupId>net.michel</groupId> | ||
<artifactId>StatTrack</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
|
||
<properties> | ||
<maven.compiler.source>17</maven.compiler.source> | ||
<maven.compiler.target>17</maven.compiler.target> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>io.javalin</groupId> | ||
<artifactId>javalin</artifactId> | ||
<version>4.6.1</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.json</groupId> | ||
<artifactId>json</artifactId> | ||
<version>20220320</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.projectlombok</groupId> | ||
<artifactId>lombok</artifactId> | ||
<version>1.18.24</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>commons-io</groupId> | ||
<artifactId>commons-io</artifactId> | ||
<version>2.11.0</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.slf4j</groupId> | ||
<artifactId>slf4j-simple</artifactId> | ||
<version>1.7.36</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.fasterxml.jackson.core</groupId> | ||
<artifactId>jackson-databind</artifactId> | ||
<version>2.13.3</version> | ||
</dependency> | ||
</dependencies> | ||
|
||
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# StatTrack (WIP) | ||
It's a simple tool to track your minecraft server status. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package net.michel.stattrack; | ||
|
||
import io.javalin.Javalin; | ||
import io.javalin.http.staticfiles.Location; | ||
import io.javalin.http.util.RateLimiter; | ||
import lombok.Getter; | ||
import lombok.Setter; | ||
import net.michel.stattrack.api.v1.ServerApi; | ||
import net.michel.stattrack.config.Config; | ||
import net.michel.stattrack.objects.Server; | ||
|
||
import java.util.ArrayList; | ||
import java.util.concurrent.Executors; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
import static io.javalin.apibuilder.ApiBuilder.get; | ||
import static io.javalin.apibuilder.ApiBuilder.path; | ||
|
||
@Getter | ||
@Setter | ||
public class StatTrack { | ||
public static StatTrack instance; | ||
private Config config; | ||
private Javalin javalin; | ||
private final ArrayList<Server> servers = new ArrayList<>(); | ||
|
||
public void init() { | ||
instance = this; | ||
this.config = new Config(); | ||
this.javalin = Javalin.create(config -> { | ||
config.addStaticFiles("/public", Location.CLASSPATH); | ||
}); | ||
} | ||
|
||
public void start() { | ||
System.out.println("Loading config..."); | ||
config.init(); | ||
|
||
System.out.println("Starting server..."); | ||
|
||
var rateLimit = new RateLimiter(TimeUnit.MINUTES); | ||
|
||
javalin.before(ctx -> { | ||
if (ctx.path().startsWith("/api")) rateLimit.incrementCounter(ctx, 15); | ||
}); | ||
|
||
javalin.routes(() -> { | ||
path("/api/v1", () -> { | ||
get("serverlist", ServerApi::getServerList); | ||
get("addserver", ServerApi::addServerToList); | ||
get("updateserver", ServerApi::serverUpdate); | ||
get("serverinfo", ServerApi::serverInfo); | ||
}); | ||
}); | ||
|
||
javalin.start(config.getPort()); | ||
|
||
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> { | ||
servers.forEach(server -> { | ||
if (System.currentTimeMillis() - server.getLastUpdate() > TimeUnit.MINUTES.toMillis(10)) { | ||
server.setOnline(false); | ||
System.err.println("Server " + server.getName() + " is not responding"); | ||
//todo: send a webhook to discord | ||
} | ||
}); | ||
}, 5, 15, TimeUnit.MINUTES); | ||
} | ||
|
||
|
||
public boolean serverExists(String name) { | ||
for (Server server : servers) { | ||
if (server.getName().equals(name)) return true; | ||
} | ||
return false; | ||
} | ||
|
||
public Server getServerByName(String name) { | ||
for (Server server : servers) { | ||
if (server.getName().equals(name)) return server; | ||
} | ||
return null; | ||
} | ||
} |
134 changes: 134 additions & 0 deletions
134
src/main/java/net/michel/stattrack/api/v1/ServerApi.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
package net.michel.stattrack.api.v1; | ||
|
||
import io.javalin.http.Context; | ||
import net.michel.stattrack.StatTrack; | ||
import net.michel.stattrack.objects.Server; | ||
import org.json.JSONArray; | ||
import org.json.JSONObject; | ||
|
||
public class ServerApi { | ||
|
||
/** | ||
* Get a list of all servers | ||
* | ||
* @param ctx The context of the request. | ||
*/ | ||
public static void getServerList(Context ctx) { | ||
var servers = StatTrack.instance.getServers(); | ||
|
||
if (servers.size() == 0) { | ||
responseError(ctx, "server list is empty"); | ||
return; | ||
} | ||
|
||
JSONObject json = new JSONObject(); | ||
JSONArray array = new JSONArray(); | ||
StatTrack.instance.getServers().forEach(server -> array.put(server.getName())); | ||
json.put("servers", array); | ||
|
||
ctx.json(json.toString()); | ||
} | ||
|
||
/** | ||
* Adds a server to the list of servers. | ||
* | ||
* @param ctx The context of the request. | ||
*/ | ||
public static void addServerToList(Context ctx) { | ||
if (checkKey(ctx)) { | ||
ctx.status(401); | ||
return; | ||
} | ||
|
||
String name = ctx.queryParamAsClass("name", String.class).getOrDefault(null); | ||
if (name == null || name.isEmpty()) { | ||
responseError(ctx, "name is required"); | ||
return; | ||
} | ||
|
||
if (StatTrack.instance.serverExists(name)) { | ||
responseError(ctx, "server already exists"); | ||
return; | ||
} | ||
|
||
JSONObject json = new JSONObject(); | ||
json.put("success", true); | ||
json.put("name", name); | ||
|
||
var server = new Server(name, true, 0, 0, 0, System.currentTimeMillis()); | ||
StatTrack.instance.getServers().add(server); | ||
ctx.result(json.toString()); | ||
} | ||
|
||
/** | ||
* Updates the server status | ||
* | ||
* @param ctx The context of the request. | ||
*/ | ||
public static void serverUpdate(Context ctx) { | ||
if (checkKey(ctx)) { | ||
ctx.status(401); | ||
return; | ||
} | ||
|
||
String name = ctx.queryParamAsClass("name", String.class).getOrDefault(null); | ||
if (name == null || name.isEmpty()) { | ||
responseError(ctx, "name is required"); | ||
return; | ||
} | ||
|
||
Boolean online = ctx.queryParamAsClass("online", Boolean.class).getOrDefault(false); | ||
Integer players = ctx.queryParamAsClass("players", Integer.class).getOrDefault(0); | ||
Integer maxPlayers = ctx.queryParamAsClass("maxPlayers", Integer.class).getOrDefault(0); | ||
Integer ping = ctx.queryParamAsClass("ping", Integer.class).getOrDefault(0); | ||
|
||
var server = StatTrack.instance.getServerByName(name); | ||
if (server == null) { | ||
responseError(ctx, "server does not exist"); | ||
return; | ||
} | ||
|
||
server.updateServer(online, players, maxPlayers, ping); | ||
|
||
JSONObject json = new JSONObject(); | ||
json.put("success", true); | ||
json.put("name", name); | ||
ctx.result(json.toString()); | ||
} | ||
|
||
private static boolean checkKey(Context ctx) { | ||
String key = ctx.queryParamAsClass("key", String.class).getOrDefault(null); | ||
if (key == null || !key.equals(StatTrack.instance.getConfig().getSecretKey())) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
private static void responseError(Context ctx, String error) { | ||
JSONObject json = new JSONObject(); | ||
json.put("error", error); | ||
ctx.result(json.toString()); | ||
} | ||
|
||
public static void serverInfo(Context context) { | ||
String name = context.queryParamAsClass("name", String.class).getOrDefault(null); | ||
if (name == null || name.isEmpty()) { | ||
responseError(context, "name is required"); | ||
return; | ||
} | ||
|
||
var server = StatTrack.instance.getServerByName(name); | ||
if (server == null) { | ||
responseError(context, "server does not exist"); | ||
return; | ||
} | ||
|
||
JSONObject json = new JSONObject(); | ||
json.put("name", server.getName()); | ||
json.put("online", server.isOnline()); | ||
json.put("players", server.getPlayers()); | ||
json.put("maxPlayers", server.getMaxPlayers()); | ||
json.put("ping", server.getPing()); | ||
context.result(json.toString()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package net.michel.stattrack.config; | ||
|
||
import lombok.Getter; | ||
import lombok.Setter; | ||
import net.michel.stattrack.utils.StringUtils; | ||
import org.apache.commons.io.IOUtils; | ||
import org.json.JSONObject; | ||
|
||
import java.io.File; | ||
import java.io.FileInputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.nio.charset.StandardCharsets; | ||
import java.nio.file.Files; | ||
import java.util.Objects; | ||
|
||
@Getter | ||
@Setter | ||
public class Config { | ||
private JSONObject json; | ||
private File configFile; | ||
private String secretKey; | ||
private int port; | ||
|
||
public void init() { | ||
try { | ||
configFile = new File("StatTrack/config.json"); | ||
if (!configFile.exists()) { | ||
configFile.getParentFile().mkdirs(); | ||
Files.copy(Objects.requireNonNull(getClass().getResourceAsStream("/config.json")), configFile.toPath()); | ||
} | ||
|
||
InputStream inputStream = new FileInputStream(configFile); | ||
String jsonTxt = IOUtils.toString(inputStream, StandardCharsets.UTF_8); | ||
json = new JSONObject(jsonTxt); | ||
|
||
|
||
this.secretKey = json.getString("secretKey"); | ||
if (this.secretKey.isEmpty()) { | ||
this.secretKey = StringUtils.generateRandomString(32); | ||
saveField("secretKey", this.secretKey); | ||
} | ||
|
||
this.port = json.getInt("port"); | ||
if (this.port == 0) { | ||
this.port = 8080; | ||
saveField("port", this.port); | ||
} | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
|
||
private void saveField(String key, Object value) throws IOException { | ||
json.put(key, value); | ||
Files.write(configFile.toPath(), json.toString(4).getBytes()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package net.michel.stattrack.main; | ||
|
||
import net.michel.stattrack.StatTrack; | ||
|
||
public class Bootstrap { | ||
|
||
public static void main(String[] args) { | ||
StatTrack statTrack = new StatTrack(); | ||
statTrack.init(); | ||
statTrack.start(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package net.michel.stattrack.objects; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.Setter; | ||
|
||
@Getter | ||
@Setter | ||
@AllArgsConstructor | ||
public class Server { | ||
private String name; | ||
private boolean online; | ||
private int players; | ||
private int maxPlayers; | ||
private int ping; | ||
private long lastUpdate; | ||
|
||
public void updateServer(boolean online, int players, int maxPlayers, int ping) { | ||
this.online = online; | ||
this.players = players; | ||
this.maxPlayers = maxPlayers; | ||
this.ping = ping; | ||
this.lastUpdate = System.currentTimeMillis(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package net.michel.stattrack.utils; | ||
|
||
public class StringUtils { | ||
|
||
public static String generateRandomString(int length) { | ||
String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | ||
StringBuilder result = new StringBuilder(); | ||
for (int i = 0; i < length; i++) { | ||
int index = (int) (Math.random() * characters.length()); | ||
result.append(characters.charAt(index)); | ||
} | ||
return result.toString(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"secretKey": "", | ||
"port": 0 | ||
} |
Oops, something went wrong.