mirror of
https://github.com/JonasunderscoreJones/McWebserver.git
synced 2025-10-23 03:19:19 +02:00
simple api
This commit is contained in:
parent
ca0be55429
commit
8f8820db65
14 changed files with 437 additions and 39 deletions
|
@ -19,6 +19,9 @@ repositories {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation 'org.projectlombok:lombok:1.18.26'
|
||||||
|
annotationProcessor 'org.projectlombok:lombok:1.18.26'
|
||||||
|
|
||||||
// To change the versions see the gradle.properties file
|
// To change the versions see the gradle.properties file
|
||||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||||
|
@ -33,6 +36,7 @@ dependencies {
|
||||||
// modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}"
|
// modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}"
|
||||||
|
|
||||||
implementation files('libs/java-curl-1.2.2.jar')
|
implementation files('libs/java-curl-1.2.2.jar')
|
||||||
|
implementation 'com.google.code.gson:gson:2.10.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package me.jonasjones.mcwebserver;
|
||||||
|
|
||||||
import com.roxstudio.utils.CUrl;
|
import com.roxstudio.utils.CUrl;
|
||||||
import me.jonasjones.mcwebserver.config.ModConfigs;
|
import me.jonasjones.mcwebserver.config.ModConfigs;
|
||||||
|
import me.jonasjones.mcwebserver.web.api.v1.ApiHandler;
|
||||||
import me.jonasjones.mcwebserver.web.ServerHandler;
|
import me.jonasjones.mcwebserver.web.ServerHandler;
|
||||||
import net.fabricmc.api.ModInitializer;
|
import net.fabricmc.api.ModInitializer;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -9,7 +10,7 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static me.jonasjones.mcwebserver.config.ModConfigs.WEB_PORT;
|
import static me.jonasjones.mcwebserver.config.ModConfigs.*;
|
||||||
|
|
||||||
public class McWebserver implements ModInitializer {
|
public class McWebserver implements ModInitializer {
|
||||||
// This logger is used to write text to the console and the log file.
|
// This logger is used to write text to the console and the log file.
|
||||||
|
@ -18,44 +19,26 @@ public class McWebserver implements ModInitializer {
|
||||||
public static String MOD_ID = "mcwebserver";
|
public static String MOD_ID = "mcwebserver";
|
||||||
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
||||||
public static final Logger VERBOSELOGGER = LoggerFactory.getLogger(MOD_ID + " - VERBOSE LOGGER");
|
public static final Logger VERBOSELOGGER = LoggerFactory.getLogger(MOD_ID + " - VERBOSE LOGGER");
|
||||||
private static ServerHandler webserver = new ServerHandler();
|
|
||||||
public static Thread webserverthread = new Thread(webserver);
|
|
||||||
public static boolean mcserveractive = true;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInitialize() {
|
public void onInitialize() {
|
||||||
|
|
||||||
// register configs
|
// register configs
|
||||||
ModConfigs.registerConfigs();
|
ModConfigs.registerConfigs();
|
||||||
|
|
||||||
LOGGER.info("McWebserver initialized!");
|
LOGGER.info("McWebserver initialized!");
|
||||||
|
|
||||||
|
if (SERVER_API_ENABLED) {
|
||||||
webserverthread.start();
|
//start collecting api info
|
||||||
new Thread(() -> {
|
ApiHandler.startHandler();
|
||||||
while (true) {
|
LOGGER.info("Server API enabled!");
|
||||||
if (!mcserveractive) {
|
|
||||||
sleep(2);
|
|
||||||
for (int i = 0; i < 2; i++) {
|
|
||||||
CUrl curl = new CUrl("http://localhost:" + WEB_PORT + "/index.html").timeout(1, 1);
|
|
||||||
curl.exec();
|
|
||||||
sleep(1);
|
|
||||||
}
|
|
||||||
LOGGER.info("Webserver Stopped!");
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
sleep(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sleep(int seconds) {
|
|
||||||
try {
|
|
||||||
TimeUnit.SECONDS.sleep(seconds);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
if (ADV_API_ENABLED) {
|
||||||
|
//start collecting advanced api info
|
||||||
|
ApiHandler.startAdvHandler();
|
||||||
|
LOGGER.info("Advanced Server API enabled!");
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerHandler.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@ public class ModConfigs {
|
||||||
public static String WEB_ROOT;
|
public static String WEB_ROOT;
|
||||||
public static String WEB_FILE_ROOT;
|
public static String WEB_FILE_ROOT;
|
||||||
public static String WEB_FILE_404;
|
public static String WEB_FILE_404;
|
||||||
|
public static Boolean SERVER_API_ENABLED;
|
||||||
|
public static Boolean ADV_API_ENABLED;
|
||||||
public static String WEB_FILE_NOSUPPORT;
|
public static String WEB_FILE_NOSUPPORT;
|
||||||
public static Boolean VERBOSE = false; //needs to be set to false since the verbose logger is called before config file is fully loaded
|
public static Boolean VERBOSE = false; //needs to be set to false since the verbose logger is called before config file is fully loaded
|
||||||
|
|
||||||
|
@ -40,6 +42,8 @@ public class ModConfigs {
|
||||||
config.addKeyValuePair(new Pair<>("web.root", "webserver/"), "the root directory of the webserver, starting from the main server directory");
|
config.addKeyValuePair(new Pair<>("web.root", "webserver/"), "the root directory of the webserver, starting from the main server directory");
|
||||||
config.addKeyValuePair(new Pair<>("web.file.root", "index.html"), "the name of the html file for the homepage");
|
config.addKeyValuePair(new Pair<>("web.file.root", "index.html"), "the name of the html file for the homepage");
|
||||||
config.addKeyValuePair(new Pair<>("web.file.404", "404.html"), "the name of the html file for 404 page");
|
config.addKeyValuePair(new Pair<>("web.file.404", "404.html"), "the name of the html file for 404 page");
|
||||||
|
config.addKeyValuePair(new Pair<>("web.api", true), "whether or not the webserver api should be enabled or not");
|
||||||
|
config.addKeyValuePair(new Pair<>("web.api.adv", true), "whether or not the api should expose information such as player coordinates and inventory");
|
||||||
config.addKeyValuePair(new Pair<>("web.file.notSupported", "not_supported.html"), "the name of the html file for 'not supported' page");
|
config.addKeyValuePair(new Pair<>("web.file.notSupported", "not_supported.html"), "the name of the html file for 'not supported' page");
|
||||||
config.addKeyValuePair(new Pair<>("logger.verbose", true), "whether or not to log verbose output");
|
config.addKeyValuePair(new Pair<>("logger.verbose", true), "whether or not to log verbose output");
|
||||||
}
|
}
|
||||||
|
@ -50,6 +54,8 @@ public class ModConfigs {
|
||||||
WEB_ROOT = CONFIG.getOrDefault("web.root", "webserver/");
|
WEB_ROOT = CONFIG.getOrDefault("web.root", "webserver/");
|
||||||
WEB_FILE_ROOT = CONFIG.getOrDefault("web.file.root", "index.html");
|
WEB_FILE_ROOT = CONFIG.getOrDefault("web.file.root", "index.html");
|
||||||
WEB_FILE_404 = CONFIG.getOrDefault("web.file.404", "404.html");
|
WEB_FILE_404 = CONFIG.getOrDefault("web.file.404", "404.html");
|
||||||
|
SERVER_API_ENABLED = CONFIG.getOrDefault("web.api", true);
|
||||||
|
ADV_API_ENABLED = CONFIG.getOrDefault("web.api.adv", true);
|
||||||
WEB_FILE_NOSUPPORT = CONFIG.getOrDefault("web.file.notSupported", "not_supported.html");
|
WEB_FILE_NOSUPPORT = CONFIG.getOrDefault("web.file.notSupported", "not_supported.html");
|
||||||
VERBOSE = CONFIG.getOrDefault("logger.verbose", true);
|
VERBOSE = CONFIG.getOrDefault("logger.verbose", true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package me.jonasjones.mcwebserver.mixin;
|
package me.jonasjones.mcwebserver.mixin;
|
||||||
|
|
||||||
import me.jonasjones.mcwebserver.McWebserver;
|
import me.jonasjones.mcwebserver.McWebserver;
|
||||||
|
import me.jonasjones.mcwebserver.web.ServerHandler;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
@ -12,6 +13,6 @@ public class WebserverStopMixin {
|
||||||
@Inject(at = @At("HEAD"), method = "shutdown")
|
@Inject(at = @At("HEAD"), method = "shutdown")
|
||||||
private void init(CallbackInfo info) {
|
private void init(CallbackInfo info) {
|
||||||
McWebserver.LOGGER.info("Stopping Webserver...");
|
McWebserver.LOGGER.info("Stopping Webserver...");
|
||||||
McWebserver.mcserveractive = false;
|
ServerHandler.mcserveractive = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@ package me.jonasjones.mcwebserver.web;
|
||||||
import me.jonasjones.mcwebserver.config.ModConfigs;
|
import me.jonasjones.mcwebserver.config.ModConfigs;
|
||||||
import me.jonasjones.mcwebserver.McWebserver;
|
import me.jonasjones.mcwebserver.McWebserver;
|
||||||
import me.jonasjones.mcwebserver.util.VerboseLogger;
|
import me.jonasjones.mcwebserver.util.VerboseLogger;
|
||||||
|
import me.jonasjones.mcwebserver.web.api.v1.ApiHandler;
|
||||||
|
import me.jonasjones.mcwebserver.web.api.v1.ApiRequests;
|
||||||
|
import me.jonasjones.mcwebserver.web.api.v1.ApiRequestsUtil;
|
||||||
|
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
@ -20,9 +23,10 @@ import java.nio.file.Path;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
import static me.jonasjones.mcwebserver.McWebserver.mcserveractive;
|
import static me.jonasjones.mcwebserver.web.ServerHandler.mcserveractive;
|
||||||
|
import static me.jonasjones.mcwebserver.web.api.v1.ApiHandler.isApiRequest;
|
||||||
|
|
||||||
public class HTTPServer implements Runnable {
|
public class HttpServer implements Runnable {
|
||||||
static Path WEB_ROOT;
|
static Path WEB_ROOT;
|
||||||
static final String DEFAULT_FILE = ModConfigs.WEB_FILE_ROOT;
|
static final String DEFAULT_FILE = ModConfigs.WEB_FILE_ROOT;
|
||||||
static final String FILE_NOT_FOUND = ModConfigs.WEB_FILE_404;
|
static final String FILE_NOT_FOUND = ModConfigs.WEB_FILE_404;
|
||||||
|
@ -44,6 +48,7 @@ public class HTTPServer implements Runnable {
|
||||||
|
|
||||||
// Client Connection via Socket Class
|
// Client Connection via Socket Class
|
||||||
private final Socket connect;
|
private final Socket connect;
|
||||||
|
private Boolean isApiRequest = false;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
|
@ -53,7 +58,7 @@ public class HTTPServer implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public HTTPServer(Socket c) {
|
public HttpServer(Socket c) {
|
||||||
connect = c;
|
connect = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,12 +70,13 @@ public class HTTPServer implements Runnable {
|
||||||
|
|
||||||
// we listen until user halts server execution
|
// we listen until user halts server execution
|
||||||
while (mcserveractive) {
|
while (mcserveractive) {
|
||||||
HTTPServer myServer = new HTTPServer(serverConnect.accept());
|
HttpServer myServer = new HttpServer(serverConnect.accept());
|
||||||
|
|
||||||
VerboseLogger.info("Connection opened. (" + Instant.now() + ")");
|
VerboseLogger.info("Connection opened. (" + Instant.now() + ")");
|
||||||
|
|
||||||
// create dedicated thread to manage the client connection
|
// create dedicated thread to manage the client connection
|
||||||
Thread thread = new Thread(myServer);
|
Thread thread = new Thread(myServer);
|
||||||
|
thread.setName("McWebserver-worker");
|
||||||
thread.start();
|
thread.start();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -108,6 +114,7 @@ public class HTTPServer implements Runnable {
|
||||||
|
|
||||||
// we support only GET and HEAD methods, we check
|
// we support only GET and HEAD methods, we check
|
||||||
if (!method.equals("GET") && !method.equals("HEAD")) {
|
if (!method.equals("GET") && !method.equals("HEAD")) {
|
||||||
|
isApiRequest = false;
|
||||||
VerboseLogger.info("501 Not Implemented : " + method + " method.");
|
VerboseLogger.info("501 Not Implemented : " + method + " method.");
|
||||||
|
|
||||||
// we return the not supported file to the client
|
// we return the not supported file to the client
|
||||||
|
@ -127,8 +134,50 @@ public class HTTPServer implements Runnable {
|
||||||
// file
|
// file
|
||||||
dataOut.write(fileData, 0, fileData.length);
|
dataOut.write(fileData, 0, fileData.length);
|
||||||
dataOut.flush();
|
dataOut.flush();
|
||||||
|
} else if (isApiRequest(fileRequested)) {
|
||||||
|
isApiRequest = true;
|
||||||
|
|
||||||
|
// Set appropriate response headers
|
||||||
|
dataOut.write("HTTP/1.1 200 OK\r\n".getBytes(StandardCharsets.UTF_8));
|
||||||
|
dataOut.write("Date: %s\r\n".formatted(Instant.now()).getBytes(StandardCharsets.UTF_8));
|
||||||
|
if (fileRequested.equals("/api/v1/servericon")) {
|
||||||
|
dataOut.write("Content-Type: image/png\r\n".getBytes(StandardCharsets.UTF_8));
|
||||||
|
// Get server icon from ApiHandler
|
||||||
|
byte[] serverIcon = ApiRequestsUtil.getServerIcon();
|
||||||
|
int contentLength = serverIcon.length;
|
||||||
|
|
||||||
|
dataOut.write(("Content-Length: " + contentLength + "\r\n").getBytes(StandardCharsets.UTF_8));
|
||||||
|
dataOut.write("\r\n".getBytes(StandardCharsets.UTF_8)); // Blank line before content
|
||||||
|
|
||||||
|
// Send server icon
|
||||||
|
dataOut.write(serverIcon, 0, contentLength);
|
||||||
|
dataOut.flush();
|
||||||
|
} else {
|
||||||
|
dataOut.write("Content-Type: application/json\r\n".getBytes(StandardCharsets.UTF_8));
|
||||||
|
String jsonString = "";
|
||||||
|
try {
|
||||||
|
// Get JSON data from ApiHandler
|
||||||
|
jsonString = ApiHandler.handle(fileRequested);
|
||||||
|
} catch (Exception e) {
|
||||||
|
VerboseLogger.error("Error getting JSON data from ApiHandler: " + e.getMessage());
|
||||||
|
jsonString = ApiRequests.internalServerError();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
byte[] jsonBytes = jsonString.getBytes(StandardCharsets.UTF_8);
|
||||||
|
int contentLength = jsonBytes.length;
|
||||||
|
|
||||||
|
dataOut.write(("Content-Length: " + contentLength + "\r\n").getBytes(StandardCharsets.UTF_8));
|
||||||
|
dataOut.write("\r\n".getBytes(StandardCharsets.UTF_8)); // Blank line before content
|
||||||
|
|
||||||
|
// Send JSON data
|
||||||
|
dataOut.write(jsonBytes, 0, contentLength);
|
||||||
|
dataOut.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
isApiRequest = false;
|
||||||
// GET or HEAD method
|
// GET or HEAD method
|
||||||
if (fileRequested.endsWith("/")) {
|
if (fileRequested.endsWith("/")) {
|
||||||
fileRequested += DEFAULT_FILE;
|
fileRequested += DEFAULT_FILE;
|
||||||
|
@ -164,6 +213,8 @@ public class HTTPServer implements Runnable {
|
||||||
|
|
||||||
} catch (NoSuchFileException e) {
|
} catch (NoSuchFileException e) {
|
||||||
try {
|
try {
|
||||||
|
assert out != null;
|
||||||
|
assert dataOut != null;
|
||||||
fileNotFound(out, dataOut, fileRequested);
|
fileNotFound(out, dataOut, fileRequested);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
VerboseLogger.error("Error with file not found exception : " + ioe.getMessage());
|
VerboseLogger.error("Error with file not found exception : " + ioe.getMessage());
|
||||||
|
@ -175,6 +226,7 @@ public class HTTPServer implements Runnable {
|
||||||
try {
|
try {
|
||||||
in.close();
|
in.close();
|
||||||
out.close();
|
out.close();
|
||||||
|
assert dataOut != null;
|
||||||
dataOut.close();
|
dataOut.close();
|
||||||
connect.close(); // we close socket connection
|
connect.close(); // we close socket connection
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -193,7 +245,9 @@ public class HTTPServer implements Runnable {
|
||||||
|
|
||||||
// return supported MIME Types
|
// return supported MIME Types
|
||||||
private String getContentType(String fileRequested) {
|
private String getContentType(String fileRequested) {
|
||||||
if (fileRequested.endsWith(".htm") || fileRequested.endsWith(".html"))
|
if (isApiRequest) {
|
||||||
|
return "application/json";
|
||||||
|
} else if (fileRequested.endsWith(".htm") || fileRequested.endsWith(".html"))
|
||||||
return "text/html";
|
return "text/html";
|
||||||
else if (fileRequested.endsWith(".css"))
|
else if (fileRequested.endsWith(".css"))
|
||||||
return "text/css";
|
return "text/css";
|
|
@ -1,21 +1,60 @@
|
||||||
package me.jonasjones.mcwebserver.web;
|
package me.jonasjones.mcwebserver.web;
|
||||||
|
|
||||||
|
|
||||||
|
import com.roxstudio.utils.CUrl;
|
||||||
import me.jonasjones.mcwebserver.config.ModConfigs;
|
import me.jonasjones.mcwebserver.config.ModConfigs;
|
||||||
|
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static me.jonasjones.mcwebserver.McWebserver.LOGGER;
|
import static me.jonasjones.mcwebserver.McWebserver.LOGGER;
|
||||||
|
import static me.jonasjones.mcwebserver.config.ModConfigs.WEB_PORT;
|
||||||
|
|
||||||
public class ServerHandler implements Runnable {
|
public class ServerHandler implements Runnable {
|
||||||
public static Socket socket = new Socket();
|
public static Socket socket = new Socket();
|
||||||
|
|
||||||
|
private static final ServerHandler webserver = new ServerHandler();
|
||||||
|
public static Thread webserverthread = new Thread(webserver);
|
||||||
|
|
||||||
|
public static boolean mcserveractive = true;
|
||||||
|
|
||||||
|
public static void start() {
|
||||||
|
webserverthread.setName("McWebserver-webserver");
|
||||||
|
webserverthread.start();
|
||||||
|
Thread serverthread = new Thread(() -> {
|
||||||
|
while (true) {
|
||||||
|
if (!mcserveractive) {
|
||||||
|
sleep(2);
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
CUrl curl = new CUrl("http://localhost:" + WEB_PORT + "/api/v1/dummy").timeout(1, 1); // a truly awful way of stopping this thread
|
||||||
|
curl.exec();
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
LOGGER.info("Webserver Stopped!");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
sleep(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
serverthread.setName("McWebserver-main");
|
||||||
|
serverthread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void sleep(int seconds) {
|
||||||
|
try {
|
||||||
|
TimeUnit.SECONDS.sleep(seconds);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
if (ModConfigs.IS_ENABLED) {
|
if (ModConfigs.IS_ENABLED) {
|
||||||
LOGGER.info("Starting Webserver...");
|
LOGGER.info("Starting Webserver...");
|
||||||
|
|
||||||
new HTTPServer(socket);
|
new HttpServer(socket);
|
||||||
HTTPServer.main();
|
HttpServer.main();
|
||||||
} else {
|
} else {
|
||||||
LOGGER.info("Webserver disabled in the config file.");
|
LOGGER.info("Webserver disabled in the config file.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
package me.jonasjones.mcwebserver.web.api.v1;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||||
|
|
||||||
|
public class ApiHandler {
|
||||||
|
|
||||||
|
public static Boolean isApiRequest(String request) {
|
||||||
|
return request.startsWith("/api/v1/");
|
||||||
|
}
|
||||||
|
public static String handle(String request) {
|
||||||
|
switch (request.replace("/api/v1/", "")) {
|
||||||
|
// Simple API Requests
|
||||||
|
case "motd" -> {
|
||||||
|
return ApiRequests.singleValueRequest(ApiRequestsUtil.getMOTD());
|
||||||
|
}
|
||||||
|
case "serverip" -> {
|
||||||
|
return ApiRequests.singleValueRequest(ApiRequestsUtil.getSERVER_IP());
|
||||||
|
}
|
||||||
|
case "serverport" -> {
|
||||||
|
return ApiRequests.singleValueRequest(String.valueOf(ApiRequestsUtil.getSERVER_PORT()));
|
||||||
|
}
|
||||||
|
case "servername" -> {
|
||||||
|
return ApiRequests.singleValueRequest(ApiRequestsUtil.getSERVER_NAME());
|
||||||
|
}
|
||||||
|
case "serverversion" -> {
|
||||||
|
return ApiRequests.singleValueRequest(ApiRequestsUtil.getSERVER_VERSION());
|
||||||
|
}
|
||||||
|
case "loaderversion" -> {
|
||||||
|
return ApiRequests.singleValueRequest(ApiRequestsUtil.getLOADER_VERSION());
|
||||||
|
}
|
||||||
|
case "currentplayercount" -> {
|
||||||
|
return ApiRequests.singleValueRequest(String.valueOf(ApiRequestsUtil.getCURRENT_PLAYER_COUNT()));
|
||||||
|
}
|
||||||
|
case "defaultgamemode" -> {
|
||||||
|
return ApiRequests.singleValueRequest(ApiRequestsUtil.getDEFAULT_GAME_MODE().toString());
|
||||||
|
}
|
||||||
|
case "maxplayercount" -> {
|
||||||
|
return ApiRequests.singleValueRequest(String.valueOf(ApiRequestsUtil.getMAX_PLAYER_COUNT()));
|
||||||
|
}
|
||||||
|
case "playernames" -> {
|
||||||
|
return ApiRequests.playerNamesRequest();
|
||||||
|
}
|
||||||
|
case "servermetadata" -> {
|
||||||
|
return ApiRequests.serverMetadataRequest();
|
||||||
|
}
|
||||||
|
case "ticks" -> {
|
||||||
|
return ApiRequests.singleValueRequest(String.valueOf(ApiRequestsUtil.getTICKS()));
|
||||||
|
}
|
||||||
|
case "ticktime" -> {
|
||||||
|
return ApiRequests.singleValueRequest(String.valueOf(ApiRequestsUtil.getTICK_TIME()));
|
||||||
|
}
|
||||||
|
case "timereference" -> {
|
||||||
|
return ApiRequests.singleValueRequest(String.valueOf(ApiRequestsUtil.getTIME_REFERENCE()));
|
||||||
|
}
|
||||||
|
case "getall" -> {
|
||||||
|
return ApiRequests.serverGetAllRequest();
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
return ApiRequests.badRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startHandler() {
|
||||||
|
//This is a really awful way of collection all this info. Please don't kill me.
|
||||||
|
ServerTickEvents.END_SERVER_TICK.register(server -> {
|
||||||
|
if (server.isRunning()) {
|
||||||
|
ApiRequestsUtil.setMOTD(server.getServerMotd());
|
||||||
|
ApiRequestsUtil.setSERVER_IP(server.getServerIp());
|
||||||
|
ApiRequestsUtil.setSERVER_PORT(server.getServerPort());
|
||||||
|
ApiRequestsUtil.setSERVER_NAME(server.getName());
|
||||||
|
ApiRequestsUtil.setSERVER_VERSION(server.getVersion());
|
||||||
|
ApiRequestsUtil.setCURRENT_PLAYER_COUNT(server.getCurrentPlayerCount());
|
||||||
|
ApiRequestsUtil.setDEFAULT_GAME_MODE(server.getDefaultGameMode());
|
||||||
|
ApiRequestsUtil.setMAX_PLAYER_COUNT(server.getMaxPlayerCount());
|
||||||
|
ApiRequestsUtil.setSERVER_METADATA(server.getServerMetadata());
|
||||||
|
ApiRequestsUtil.setTICKS(server.getTicks());
|
||||||
|
ApiRequestsUtil.setTICK_TIME(server.getTickTime());
|
||||||
|
ApiRequestsUtil.setTIME_REFERENCE(server.getTimeReference());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startAdvHandler() {
|
||||||
|
//This is a really awful way of collection all this info. Please don't kill me.
|
||||||
|
ServerTickEvents.END_SERVER_TICK.register(server -> {
|
||||||
|
if (server.isRunning()) {
|
||||||
|
ApiRequestsUtil.setSERVER_PLAYER_ENTITY_LIST(server.getPlayerManager().getPlayerList());
|
||||||
|
ApiRequestsUtil.setSERVER_RESOURCE_PACK_PROFILE_COLLECTION(server.getDataPackManager().getProfiles());
|
||||||
|
ApiRequestsUtil.setSERVER_ADVANCEMENT_COLLECTION(server.getAdvancementLoader().getAdvancements());
|
||||||
|
ApiRequestsUtil.setSERVER_BOSSBAR_COLLECTION(server.getBossBarManager().getAll());
|
||||||
|
ApiRequestsUtil.getSERVER_PLAYER_ENTITY_LIST().forEach(serverPlayerEntity -> {
|
||||||
|
|
||||||
|
});
|
||||||
|
//SERVER_PLAYER_ENTITY_LIST = server.getPlayerInteractionManager().getPlayerList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package me.jonasjones.mcwebserver.web.api.v1;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
public class ApiRequests {
|
||||||
|
private static final Gson gson = new Gson();
|
||||||
|
|
||||||
|
public static String singleValueRequest(String value) {
|
||||||
|
return "[\"" + value + "\"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String playerNamesRequest() {
|
||||||
|
return gson.toJsonTree(ApiRequestsUtil.convertPlayerList(ApiRequestsUtil.getSERVER_METADATA().players().get().sample())).getAsJsonArray().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String serverMetadataRequest() {
|
||||||
|
return gson.toJson(ApiRequestsUtil.serverMetadata());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String serverGetAllRequest() {
|
||||||
|
return gson.toJson(ApiRequestsUtil.getAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String badRequest() {
|
||||||
|
return "{\"error\":{\"status\":400,\"message\":\"Bad Request\"}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String internalServerError() {
|
||||||
|
return "{\"error\":{\"status\":500,\"message\":\"Internal Server Error\"}}";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
package me.jonasjones.mcwebserver.web.api.v1;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import me.jonasjones.mcwebserver.web.api.v1.json.ApiServerInfo;
|
||||||
|
import me.jonasjones.mcwebserver.web.api.v1.json.ApiServerMetadata;
|
||||||
|
import me.jonasjones.mcwebserver.web.api.v1.json.ApiServerMetadataPlayer;
|
||||||
|
import me.jonasjones.mcwebserver.web.api.v1.json.ApiServerMetadataPlayers;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.advancement.Advancement;
|
||||||
|
import net.minecraft.entity.boss.CommandBossBar;
|
||||||
|
import net.minecraft.resource.ResourcePackProfile;
|
||||||
|
import net.minecraft.server.ServerMetadata;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.world.GameMode;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static me.jonasjones.mcwebserver.config.ModConfigs.WEB_PORT;
|
||||||
|
|
||||||
|
public class ApiRequestsUtil {
|
||||||
|
@Getter @Setter
|
||||||
|
private static String MOTD;
|
||||||
|
@Getter @Setter
|
||||||
|
private static String SERVER_IP;
|
||||||
|
@Getter @Setter
|
||||||
|
private static int SERVER_PORT;
|
||||||
|
@Getter @Setter
|
||||||
|
private static String SERVER_NAME;
|
||||||
|
@Getter @Setter
|
||||||
|
private static String SERVER_VERSION;
|
||||||
|
@Getter @Setter
|
||||||
|
private static int CURRENT_PLAYER_COUNT;
|
||||||
|
@Getter @Setter
|
||||||
|
private static GameMode DEFAULT_GAME_MODE;
|
||||||
|
@Getter
|
||||||
|
private static final String LOADER_VERSION = FabricLoader.getInstance().getModContainer("fabricloader").get().getMetadata().getVersion().getFriendlyString();
|
||||||
|
@Getter @Setter
|
||||||
|
private static int MAX_PLAYER_COUNT;
|
||||||
|
@Getter @Setter
|
||||||
|
private static ServerMetadata SERVER_METADATA;
|
||||||
|
@Getter @Setter
|
||||||
|
private static int TICKS;
|
||||||
|
@Getter @Setter
|
||||||
|
private static float TICK_TIME;
|
||||||
|
@Getter @Setter
|
||||||
|
private static long TIME_REFERENCE;
|
||||||
|
@Getter @Setter
|
||||||
|
private static List<ServerPlayerEntity> SERVER_PLAYER_ENTITY_LIST = new ArrayList<>();
|
||||||
|
@Getter @Setter
|
||||||
|
private static Collection<ResourcePackProfile> SERVER_RESOURCE_PACK_PROFILE_COLLECTION = new ArrayList<>();
|
||||||
|
@Getter @Setter
|
||||||
|
private static Collection<Advancement> SERVER_ADVANCEMENT_COLLECTION = new ArrayList<>();
|
||||||
|
@Getter @Setter
|
||||||
|
private static Collection<CommandBossBar> SERVER_BOSSBAR_COLLECTION = new ArrayList<>();
|
||||||
|
private static final ApiServerInfo apiServerInfo = new ApiServerInfo();
|
||||||
|
private static final ApiServerMetadata apiServerMetadata = new ApiServerMetadata();
|
||||||
|
private static final ApiServerMetadataPlayers apiServerMetadataPlayers = new ApiServerMetadataPlayers();
|
||||||
|
private static final Gson gson = new Gson();
|
||||||
|
|
||||||
|
|
||||||
|
public static JsonObject serverMetadata() {
|
||||||
|
apiServerMetadataPlayers.setMAX(ApiRequestsUtil.getSERVER_METADATA().players().get().max());
|
||||||
|
apiServerMetadataPlayers.setONLINE(ApiRequestsUtil.getSERVER_METADATA().players().get().online());
|
||||||
|
apiServerMetadataPlayers.setSAMPLE(convertPlayerList(ApiRequestsUtil.getSERVER_METADATA().players().get().sample()));
|
||||||
|
|
||||||
|
apiServerMetadata.setDESCRIPTION(ApiRequestsUtil.getSERVER_METADATA().description().getString());
|
||||||
|
apiServerMetadata.setPLAYERS(JsonParser.parseString(gson.toJson(apiServerMetadataPlayers)).getAsJsonObject());
|
||||||
|
apiServerMetadata.setVERSION((JsonObject) JsonParser.parseString("{\"version\":\"" + ApiRequestsUtil.getSERVER_METADATA().version().get().gameVersion() + "\",\"protocol\":" + ApiRequestsUtil.getSERVER_METADATA().version().get().protocolVersion() + "}"));
|
||||||
|
if (ApiRequestsUtil.getSERVER_METADATA().favicon().isPresent()) {
|
||||||
|
if (!ApiRequestsUtil.getSERVER_IP().equals("")) {
|
||||||
|
apiServerMetadata.setFAVICON("http://" + ApiRequestsUtil.getSERVER_IP() + ":" + WEB_PORT + "/api/v1/servericon");
|
||||||
|
} else {
|
||||||
|
apiServerMetadata.setFAVICON("/api/v1/servericon");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
apiServerMetadata.setFAVICON(""); // if favicon doesn't exist
|
||||||
|
}
|
||||||
|
|
||||||
|
apiServerMetadata.setSECURE_CHAT_EINFORCED(ApiRequestsUtil.getSERVER_METADATA().secureChatEnforced());
|
||||||
|
|
||||||
|
return JsonParser.parseString(gson.toJson(apiServerMetadata)).getAsJsonObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ArrayList<ApiServerMetadataPlayer> convertPlayerList(List<GameProfile> list) {
|
||||||
|
ArrayList<ApiServerMetadataPlayer> players = new ArrayList<>();
|
||||||
|
for (GameProfile profile : list) {
|
||||||
|
ApiServerMetadataPlayer player = new ApiServerMetadataPlayer();
|
||||||
|
player.setID(profile.getId().toString());
|
||||||
|
player.setNAME(profile.getName());
|
||||||
|
//player.setPROPERTIES(profile.getProperties().toString()); //Add support for the properties later
|
||||||
|
player.setLEGACY(profile.isLegacy());
|
||||||
|
players.add(player);
|
||||||
|
}
|
||||||
|
return players;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JsonObject getAll() {
|
||||||
|
apiServerInfo.setSERVER_IP(ApiRequestsUtil.getSERVER_IP());
|
||||||
|
apiServerInfo.setSERVER_PORT(ApiRequestsUtil.getSERVER_PORT());
|
||||||
|
apiServerInfo.setSERVER_NAME(ApiRequestsUtil.getSERVER_NAME());
|
||||||
|
apiServerInfo.setDEFAULT_GAME_MODE(ApiRequestsUtil.getDEFAULT_GAME_MODE().toString());
|
||||||
|
apiServerInfo.setLOADER_VERSION(LOADER_VERSION);
|
||||||
|
apiServerInfo.setMETADATA(serverMetadata());
|
||||||
|
apiServerInfo.setTICKS(ApiRequestsUtil.getTICKS());
|
||||||
|
apiServerInfo.setTICK_TIME(ApiRequestsUtil.getTICK_TIME());
|
||||||
|
apiServerInfo.setTIME_REFERENCE(ApiRequestsUtil.getTIME_REFERENCE());
|
||||||
|
|
||||||
|
return gson.toJsonTree(apiServerInfo).getAsJsonObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] getServerIcon() {
|
||||||
|
return ApiRequestsUtil.getSERVER_METADATA().favicon().get().iconBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package me.jonasjones.mcwebserver.web.api.v1.json;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
public class ApiServerInfo {
|
||||||
|
private String SERVER_IP;
|
||||||
|
private int SERVER_PORT;
|
||||||
|
private String SERVER_NAME;
|
||||||
|
private String DEFAULT_GAME_MODE;
|
||||||
|
private String LOADER_VERSION;
|
||||||
|
private JsonObject METADATA;
|
||||||
|
private int TICKS;
|
||||||
|
private float TICK_TIME;
|
||||||
|
private long TIME_REFERENCE;
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package me.jonasjones.mcwebserver.web.api.v1.json;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
public class ApiServerMetadata {
|
||||||
|
private String DESCRIPTION;
|
||||||
|
private JsonObject PLAYERS;
|
||||||
|
private JsonObject VERSION;
|
||||||
|
private String FAVICON;
|
||||||
|
private Boolean SECURE_CHAT_EINFORCED;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package me.jonasjones.mcwebserver.web.api.v1.json;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
public class ApiServerMetadataPlayer {
|
||||||
|
private String ID;
|
||||||
|
private String NAME;
|
||||||
|
private String PROPERTIES;
|
||||||
|
private Boolean LEGACY;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package me.jonasjones.mcwebserver.web.api.v1.json;
|
||||||
|
|
||||||
|
public class ApiServerMetadataPlayerProperty {
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package me.jonasjones.mcwebserver.web.api.v1.json;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
public class ApiServerMetadataPlayers {
|
||||||
|
private int MAX;
|
||||||
|
private int ONLINE;
|
||||||
|
private ArrayList<ApiServerMetadataPlayer> SAMPLE;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue