From 8bac2ee4590470107bc4377859e3c8230271e4c5 Mon Sep 17 00:00:00 2001 From: M_Viper Date: Thu, 7 May 2026 19:39:31 +0000 Subject: [PATCH] Soft-delete copy _trash/2026-05-07T19-39-23-130Z/src/main/java/net/viper/status/modules/chat/ChatLogger.java --- .../viper/status/modules/chat/ChatLogger.java | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 _trash/2026-05-07T19-39-23-130Z/src/main/java/net/viper/status/modules/chat/ChatLogger.java diff --git a/_trash/2026-05-07T19-39-23-130Z/src/main/java/net/viper/status/modules/chat/ChatLogger.java b/_trash/2026-05-07T19-39-23-130Z/src/main/java/net/viper/status/modules/chat/ChatLogger.java new file mode 100644 index 0000000..c5e2685 --- /dev/null +++ b/_trash/2026-05-07T19-39-23-130Z/src/main/java/net/viper/status/modules/chat/ChatLogger.java @@ -0,0 +1,152 @@ +package net.viper.status.modules.chat; + +import java.io.*; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Logger; + +/** + * Protokolliert alle Chat-Nachrichten in tagesweise rotierende Logdateien. + * + * Verzeichnis: plugins/StatusAPI/chatlogs/chatlog_YYYY-MM-DD.log + * Format: [HH:mm:ss] [MSG-XXXXXX] [SERVER] [CHANNEL] Spieler: Nachricht + * + * Alte Logs werden beim Start und täglich automatisch bereinigt. + * Die Aufbewahrungsdauer ist in der chat.yml konfigurierbar (7 oder 14 Tage). + */ +public class ChatLogger { + + private final File logDir; + private final Logger logger; + private final int retentionDays; + private final AtomicInteger counter = new AtomicInteger(0); + + private static final SimpleDateFormat DATE_FMT = new SimpleDateFormat("yyyy-MM-dd"); + private static final SimpleDateFormat TIME_FMT = new SimpleDateFormat("HH:mm:ss"); + + public ChatLogger(File dataFolder, Logger logger, int retentionDays) { + this.logDir = new File(dataFolder, "chatlogs"); + this.logger = logger; + this.retentionDays = Math.max(1, retentionDays); + this.logDir.mkdirs(); + cleanup(); + } + + // ===== Nachrichten-ID ===== + + /** + * Generiert eine eindeutige Nachrichten-ID (z.B. MSG-A3F2B1). + * Kombiniert Zeitstempel + inkrementellen Zähler für Eindeutigkeit. + */ + public String generateMessageId() { + int seq = counter.incrementAndGet(); + long ts = System.currentTimeMillis(); + int hash = (int)(ts ^ (ts >>> 32)) ^ (seq * 0x9E3779B9); + return "MSG-" + String.format("%06X", hash & 0xFFFFFF); + } + + // ===== Logging ===== + + /** + * Loggt eine Nachricht und gibt die generierte Nachrichten-ID zurück. + * + * @param msgId Vorher generierte ID (aus generateMessageId()) + * @param server Servername des Absenders + * @param channel Kanal-ID + * @param player Spielername + * @param message Nachrichtentext (Rohtext, ohne Farbcodes) + */ + public void log(String msgId, String server, String channel, String player, String message) { + String date = DATE_FMT.format(new Date()); + String time = TIME_FMT.format(new Date()); + + // Minecraft-Farbcodes aus dem Log entfernen + String cleanMsg = stripColor(message); + + String line = "[" + time + "] [" + msgId + "] [" + server + "] [" + channel + "] " + + player + ": " + cleanMsg; + + File logFile = new File(logDir, "chatlog_" + date + ".log"); + try (BufferedWriter bw = new BufferedWriter( + new OutputStreamWriter(new FileOutputStream(logFile, true), "UTF-8"))) { + bw.write(line); + bw.newLine(); + } catch (IOException e) { + logger.warning("[ChatLogger] Fehler beim Schreiben: " + e.getMessage()); + } + } + + // ===== Cleanup ===== + + /** + * Löscht Log-Dateien, die älter als retentionDays Tage sind. + * Wird beim Start und kann manuell aufgerufen werden. + */ + public void cleanup() { + if (!logDir.exists()) return; + long cutoff = System.currentTimeMillis() - ((long) retentionDays * 24L * 60L * 60L * 1000L); + File[] files = logDir.listFiles((dir, name) -> + name.startsWith("chatlog_") && name.endsWith(".log")); + if (files == null) return; + for (File f : files) { + if (f.lastModified() < cutoff) { + if (f.delete()) { + logger.info("[ChatLogger] Altes Log gelöscht: " + f.getName()); + } + } + } + } + + // ===== Hilfsmethoden ===== + + /** Entfernt §-Farbcodes aus dem Text. */ + private static String stripColor(String input) { + if (input == null) return ""; + return input.replaceAll("(?i)§[0-9A-FK-OR]", "") + .replaceAll("(?i)&[0-9A-FK-OR]", ""); + } + + public int getRetentionDays() { return retentionDays; } + public File getLogDir() { return logDir; } + + /** + * Liest die letzten `maxLines` Zeilen aus dem heutigen Chatlog. + * Wenn ein Spielername angegeben ist, werden nur seine Zeilen zurückgegeben. + * + * @param playerFilter Spielername (case-insensitiv) oder null für alle + * @param maxLines Maximale Anzahl zurückgegebener Zeilen + * @return Liste der Logzeilen (älteste zuerst) + */ + public List readLastLines(String playerFilter, int maxLines) { + String date = DATE_FMT.format(new Date()); + File logFile = new File(logDir, "chatlog_" + date + ".log"); + if (!logFile.exists()) return Collections.emptyList(); + + List allLines = new ArrayList<>(); + try (BufferedReader br = new BufferedReader( + new InputStreamReader(new FileInputStream(logFile), "UTF-8"))) { + String line; + while ((line = br.readLine()) != null) { + if (line.trim().isEmpty()) continue; + // Spieler-Filter: Format ist [...] [...] [...] [...] Spieler: Nachricht + if (playerFilter != null) { + // Spielername steht nach dem 4. [...]-Block + int lastBracket = line.indexOf("] ", line.lastIndexOf("[")); + if (lastBracket >= 0) { + String rest = line.substring(lastBracket + 2); + String name = rest.contains(":") ? rest.substring(0, rest.indexOf(":")).trim() : ""; + if (!name.equalsIgnoreCase(playerFilter)) continue; + } + } + allLines.add(line); + } + } catch (IOException e) { + logger.warning("[ChatLogger] Fehler beim Lesen: " + e.getMessage()); + } + + // Letzte maxLines zurückgeben + if (allLines.size() <= maxLines) return allLines; + return allLines.subList(allLines.size() - maxLines, allLines.size()); + } +} \ No newline at end of file