From 88d22d8d0883e3092650b28df80f471c67860ac4 Mon Sep 17 00:00:00 2001 From: M_Viper Date: Fri, 2 Jan 2026 21:02:57 +0000 Subject: [PATCH] StatusAPI/src/main/java/net/viper/status/StatusAPI.java aktualisiert --- .../main/java/net/viper/status/StatusAPI.java | 173 +++++++++++++----- 1 file changed, 128 insertions(+), 45 deletions(-) diff --git a/StatusAPI/src/main/java/net/viper/status/StatusAPI.java b/StatusAPI/src/main/java/net/viper/status/StatusAPI.java index ee4b2ad..824f760 100644 --- a/StatusAPI/src/main/java/net/viper/status/StatusAPI.java +++ b/StatusAPI/src/main/java/net/viper/status/StatusAPI.java @@ -1,29 +1,47 @@ package net.viper.status; +import net.luckperms.api.LuckPerms; +import net.luckperms.api.LuckPermsProvider; // <--- HINZUGEFÜGT +import net.luckperms.api.model.user.User; +import net.luckperms.api.query.QueryOptions; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.config.ListenerInfo; +import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.plugin.Plugin; import java.io.*; import java.net.ServerSocket; import java.net.Socket; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.concurrent.TimeUnit; public class StatusAPI extends Plugin implements Runnable { private Thread thread; private int port = 9191; + private UpdateChecker updateChecker; @Override public void onEnable() { getLogger().info("StatusAPI wird aktiviert..."); getLogger().info("Starte Web-Server auf Port " + port + "..."); - - thread = new Thread(this); + + // Start HTTP server thread + thread = new Thread(this, "StatusAPI-HTTP-Server"); thread.start(); + + // Start UpdateChecker: initialer Check (async) + regelmäßiger Schedule + String currentVersion = getDescription() != null ? getDescription().getVersion() : "0.0.0"; + updateChecker = new UpdateChecker(this, currentVersion, 6); // 6 Stunden Intervall + + // initialer sofortiger Start (async) + ProxyServer.getInstance().getScheduler().runAsync(this, () -> updateChecker.checkNow()); + + // planmäßiger Intervall (alle 6 Stunden) + ProxyServer.getInstance().getScheduler().schedule(this, updateChecker, 6, 6, TimeUnit.HOURS); + + // Register join listener to notify OPs on login + ProxyServer.getInstance().getPluginManager().registerListener(this, new UpdateListener(this, updateChecker)); } @Override @@ -31,6 +49,9 @@ public class StatusAPI extends Plugin implements Runnable { getLogger().info("Stoppe Web-Server..."); if (thread != null) { thread.interrupt(); + try { + thread.join(1000); + } catch (InterruptedException ignored) {} } } @@ -44,13 +65,13 @@ public class StatusAPI extends Plugin implements Runnable { Socket clientSocket = serverSocket.accept(); handleConnection(clientSocket); } catch (java.net.SocketTimeoutException e) { - // Loop Check + // Loop Check (timeout) - erlaubt Unterbrechungsschleife } catch (IOException e) { - // Ignorieren + getLogger().warning("Fehler beim Akzeptieren einer Verbindung: " + e.getMessage()); } } } catch (IOException e) { - getLogger().severe("Konnte ServerSocket nicht starten auf Port " + port); + getLogger().severe("Konnte ServerSocket nicht starten auf Port " + port + ": " + e.getMessage()); e.printStackTrace(); } } @@ -58,26 +79,26 @@ public class StatusAPI extends Plugin implements Runnable { private void handleConnection(Socket clientSocket) { BufferedReader in = null; OutputStream out = null; - + try { - in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); + in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "UTF-8")); out = clientSocket.getOutputStream(); String inputLine = in.readLine(); - + if (inputLine != null && inputLine.startsWith("GET")) { - - Map data = new HashMap<>(); + + Map data = new LinkedHashMap<>(); data.put("online", true); - + // --- VERSION CLEANUP START --- String versionRaw = ProxyServer.getInstance().getVersion(); String versionClean = versionRaw; - - if (versionRaw.contains("BungeeCord-Bootstrap:")) { + + if (versionRaw != null && versionRaw.contains(":")) { String[] parts = versionRaw.split(":"); - if(parts.length >= 3) { - versionClean = parts[2]; + if (parts.length >= 3) { + versionClean = parts[2].trim(); } } data.put("version", versionClean); @@ -87,20 +108,53 @@ public class StatusAPI extends Plugin implements Runnable { String motd = "BungeeCord"; try { - ListenerInfo listener = ProxyServer.getInstance().getConfig().getListeners().iterator().next(); - if (listener != null) { - motd = listener.getMotd(); + Iterator it = ProxyServer.getInstance().getConfig().getListeners().iterator(); + if (it.hasNext()) { + ListenerInfo listener = it.next(); + if (listener != null && listener.getMotd() != null) { + motd = listener.getMotd(); + } } } catch (Exception e) { - // Fallback + // Fallback bleibt "BungeeCord" } data.put("motd", motd); - List playerNames = new ArrayList<>(); - for (net.md_5.bungee.api.connection.ProxiedPlayer p : ProxyServer.getInstance().getPlayers()) { - playerNames.add(p.getName()); + // --- LUCKPERMS INTEGRATION START --- + // LuckPerms API über Provider holen (Verhindert ClassCastException) + LuckPerms luckPermsApi = null; + try { + luckPermsApi = LuckPermsProvider.get(); + } catch (IllegalStateException e) { + // LuckPerms ist nicht geladen } - data.put("players", playerNames); + + List> playersList = new ArrayList<>(); + + for (ProxiedPlayer p : ProxyServer.getInstance().getPlayers()) { + Map playerInfo = new LinkedHashMap<>(); + playerInfo.put("name", p.getName()); + + // Prefix abfragen, falls LP gefunden wurde + String prefix = ""; + if (luckPermsApi != null) { + User user = luckPermsApi.getUserManager().getUser(p.getUniqueId()); + if (user != null) { + // Context bestimmen (Global oder Server-spezifisch) + QueryOptions queryOptions = luckPermsApi.getContextManager().getQueryOptions(user) + .orElse(QueryOptions.defaultContextualOptions()); + + String lpPrefix = user.getCachedData().getMetaData(queryOptions).getPrefix(); + if (lpPrefix != null) { + prefix = lpPrefix; + } + } + } + playerInfo.put("prefix", prefix); + playersList.add(playerInfo); + } + data.put("players", playersList); + // --- LUCKPERMS INTEGRATION ENDE --- String json = buildJsonString(data); byte[] jsonBytes = json.getBytes("UTF-8"); @@ -119,6 +173,11 @@ public class StatusAPI extends Plugin implements Runnable { // Body senden out.write(jsonBytes); out.flush(); + } else { + // Ungültige Anfrage -> 400 + String resp = "HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n"; + out.write(resp.getBytes("UTF-8")); + out.flush(); } } catch (Exception e) { getLogger().severe("Fehler beim Verarbeiten der Anfrage: " + e.getMessage()); @@ -137,32 +196,56 @@ public class StatusAPI extends Plugin implements Runnable { } } + /** + * Rekursiver JSON Builder, der nun auch Listen von Objekten (Maps) verarbeiten kann. + */ private String buildJsonString(Map data) { StringBuilder sb = new StringBuilder("{"); boolean first = true; for (Map.Entry entry : data.entrySet()) { if (!first) sb.append(","); first = false; - sb.append("\"").append(entry.getKey()).append("\":"); - - Object value = entry.getValue(); - if (value instanceof List) { - sb.append("["); - List list = (List) value; - for (int i = 0; i < list.size(); i++) { - if (i > 0) sb.append(","); - sb.append("\"").append(list.get(i)).append("\""); - } - sb.append("]"); - } else if (value instanceof String) { - sb.append("\"").append(((String) value).replace("\"", "\\\"")).append("\""); - } else if (value instanceof Boolean) { - sb.append(value); - } else { - sb.append("\"").append(value).append("\""); - } + sb.append("\"").append(escapeJson(entry.getKey())).append("\":"); + + // Wert verarbeiten (String, Boolean, List oder Map) + sb.append(valueToString(entry.getValue())); } sb.append("}"); return sb.toString(); } + + /** + * Hilfsmethode, um verschiedene Objekttypen in JSON-Strings umzuwandeln. + */ + private String valueToString(Object value) { + if (value == null) { + return "null"; + } else if (value instanceof Boolean) { + return value.toString(); + } else if (value instanceof List) { + StringBuilder sb = new StringBuilder("["); + List list = (List) value; + for (int i = 0; i < list.size(); i++) { + if (i > 0) sb.append(","); + Object item = list.get(i); + // Wenn es eine Map ist (Player-Objekt), rufen wir buildJsonString rekursiv auf + if (item instanceof Map) { + sb.append(buildJsonString((Map) item)); + } else { + // Andernfalls String behandeln + sb.append("\"").append(escapeJson(String.valueOf(item))).append("\""); + } + } + sb.append("]"); + return sb.toString(); + } else { + // Standard String Behandlung + return "\"" + escapeJson(String.valueOf(value)) + "\""; + } + } + + private String escapeJson(String s) { + if (s == null) return ""; + return s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "\\r"); + } } \ No newline at end of file