From 1242c8566327db9f76d4058bab337f39701d0f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Gla=C3=9F?= Date: Wed, 6 Apr 2022 20:20:46 +0200 Subject: [PATCH] [Improved] Generify of minecraft servers --- .../yoshibot/main/YoshiBot.java | 18 +--- .../yoshibot/utils/Resources.java | 18 ++-- .../yoshibot/utils/StatusProvider.java | 101 +++++------------- .../yoshibot/utils/StatusProviderFactory.java | 99 +++++++++++++++++ rsc/Config.properties | 1 + rsc/mcservers.json | 22 ++++ 6 files changed, 160 insertions(+), 99 deletions(-) create mode 100644 app/src/main/java/de/yannicpunktdee/yoshibot/utils/StatusProviderFactory.java create mode 100644 rsc/mcservers.json diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/main/YoshiBot.java b/app/src/main/java/de/yannicpunktdee/yoshibot/main/YoshiBot.java index c4e094e..7dca5a7 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/main/YoshiBot.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/main/YoshiBot.java @@ -110,31 +110,19 @@ public final class YoshiBot { jdaBuilder.setStatus(OnlineStatus.ONLINE); - System.out.println("YoshiBot online."); + Logger.logInfo("YoshiBot online."); commandLineThread = new CommandLine(); commandLineThread.start(); - allProvides.add( - new StatusProvider("Kreativ - 1.17", "status_message_kreativ", guild, Resources.getStatus_update(), - 25565)); - allProvides.add( - new StatusProvider("Enigmatica 6: Expert 1.0.0", "status_message_modded", guild, - Resources.getStatus_update(), - 25566)); - allProvides.add(new StatusProvider("Vanilla - 1.18", "status_message_eighteen_vanilla", guild, - Resources.getStatus_update(), 25567)); - allProvides.add(new StatusProvider("MCMuffing™®㋏ Inc.", "status_message_selina", guild, - Resources.getStatus_update(), 25568)); + StatusProviderFactory.createStatusProviders(Resources.getMcserver_config_file(), allProvides); //SauceProvider.init(300); Executors.newScheduledThreadPool(1).scheduleAtFixedRate(YoshiBot::setRandomActivity, 0, 10, TimeUnit.HOURS); - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - YoshiBot.getInstance().stop(); - })); + Runtime.getRuntime().addShutdownHook(new Thread(() -> YoshiBot.getInstance().stop())); joinVoiceChannelWithMostMembers(); } diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/utils/Resources.java b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/Resources.java index 88cc8ba..14c36a8 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/utils/Resources.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/Resources.java @@ -22,15 +22,15 @@ public final class Resources { private static boolean greetings_and_byebyes_on; @Getter - private static int status_update; + private static int statusUpdate; @Getter private static long guild_id; @Getter private static String resourcePath, configPath, audioPath, tempPath, activitiesPath, greetingsPath, byebyesPath, - sauceConfigPath, ttsPath, patPngPath, imagePath, bonkPngPath, jda_builder_string, mc_server, status_channel, - path_to_mcstatus, comebacksPath, departsPath; + sauceConfigPath, ttsPath, patPngPath, imagePath, bonkPngPath, jda_builder_string, status_channel, + path_to_mcstatus, comebacksPath, departsPath, mcserver_config_file; private static List greetings, byebyes, departs, comebacks; @@ -288,12 +288,14 @@ public final class Resources { } private static boolean initStatusMessage() { - if (propertiesFile.containsKey("mc_server") && propertiesFile.containsKey("status_channel")) { - mc_server = propertiesFile.getProperty("mc_server"); - status_channel = propertiesFile.getProperty("status_channel"); - path_to_mcstatus = propertiesFile.getProperty("path_to_mcstatus"); + if (propertiesFile.containsKey("path_to_mcstatus") && + propertiesFile.containsKey("status_channel") && + propertiesFile.containsKey("path_to_status_json")) { + status_channel = propertiesFile.getProperty("status_channel"); + path_to_mcstatus = propertiesFile.getProperty("path_to_mcstatus"); + mcserver_config_file = propertiesFile.getProperty("path_to_status_json"); try { - status_update = Integer.parseInt(propertiesFile.getProperty("status_update")); + statusUpdate = Integer.parseInt(propertiesFile.getProperty("status_update")); } catch (NumberFormatException e) { return false; } diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/utils/StatusProvider.java b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/StatusProvider.java index b538b9b..cec5fa1 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/utils/StatusProvider.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/StatusProvider.java @@ -1,25 +1,15 @@ package de.yannicpunktdee.yoshibot.utils; -import de.yannicpunktdee.yoshibot.main.YoshiBot; -import lombok.SneakyThrows; +import lombok.Getter; import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.MessageBuilder; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; -import org.apache.commons.io.FileUtils; import org.json.JSONObject; import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.InputStreamReader; -import java.nio.file.Files; import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -33,64 +23,31 @@ public class StatusProvider implements Provider { private int lastPlayersOnline = -1; - private volatile String messageId = null; - - private final int serverPort; + @Getter + private final String ip; private final String desc; private LocalDateTime timestampLastPlayerOnline; - private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss E, dd.MM.yyyy", - Locale.GERMANY); - private final ProcessBuilder mcstatus = new ProcessBuilder(); - @SneakyThrows - @SuppressWarnings("empty") - public StatusProvider(String desc, String messageIdKey, Guild guild, int secondsPerTime, - int serverPort) { - TextChannel statusChannel = guild.getTextChannelById(Resources.getStatus_channel()); - - this.desc = desc; - this.messageId = StatusProvider.ensureMessageId(statusChannel, messageIdKey, guild); - this.serverPort = serverPort; - this.mcstatus.command(Resources.getPath_to_mcstatus(), Resources.getMc_server() + ":" + serverPort, "json"); + public StatusProvider(String desc, int secondsPerTime, String ip, LocalDateTime timestamp) { + this.timestampLastPlayerOnline = timestamp; + this.desc = desc; + this.ip = ip; + this.mcstatus.command(Resources.getPath_to_mcstatus(), ip, "json"); - File timeStampSave = new File(String.format("%s/%d.txt", Resources.getResourcePath(), serverPort)); - timestampLastPlayerOnline = null; - - if (!timeStampSave.createNewFile()) { - List contents = Files.readAllLines(timeStampSave.toPath()); - if (contents.size() > 0) { - timestampLastPlayerOnline = LocalDateTime.parse(contents.get(0), TIME_FORMATTER); - } - } - - statusScheduler.scheduleAtFixedRate(() -> updateStatusMessage(statusChannel), 0, secondsPerTime, + statusScheduler.scheduleAtFixedRate(this::updateStatusMessage, 0, secondsPerTime, TimeUnit.SECONDS); } - private synchronized static String ensureMessageId(TextChannel statusChannel, String messageIdKey, Guild guild) { - if (Resources.getProperty(messageIdKey) != null) { - return Resources.getProperty(messageIdKey); - } else { - assert statusChannel != null; - MessageBuilder mb = new MessageBuilder(); - mb.append("ServerInformation"); - Message msg = mb.build(); - statusChannel.sendMessage(msg).complete(); - Resources.setProperty(messageIdKey, statusChannel.getLatestMessageId()); - return statusChannel.getLatestMessageId(); - } - } - @SuppressWarnings("unchecked") - public void updateStatusMessage(TextChannel statusChannel) { + public void updateStatusMessage() { EmbedBuilder eb = new EmbedBuilder(); eb.setTitle(desc); - eb.addField("IP", Resources.getMc_server() + ":" + serverPort, false); + eb.addField("IP", ip, false); try { Map serverInfo = getPlayersOnline(); @@ -99,30 +56,27 @@ public class StatusProvider implements Provider { eb.addField("Server still Starting", "True", false); } else { int newPlayersOnline = (int) serverInfo.get("playerCount"); - if (newPlayersOnline == lastPlayersOnline) return; - else { - if (timestampLastPlayerOnline == null && newPlayersOnline == 0 && lastPlayersOnline != -1) { - timestampLastPlayerOnline = LocalDateTime.now(); - } else if (timestampLastPlayerOnline != null && newPlayersOnline > 0) { - timestampLastPlayerOnline = null; - } - lastPlayersOnline = newPlayersOnline; - } eb.addField("Version", (String) serverInfo.get("version"), true); eb.addField("MOTD", (String) serverInfo.get("motd"), true); - eb.addField("Spieler online", lastPlayersOnline + " / " + serverInfo.get("playerMax"), false); - if (timestampLastPlayerOnline != null) { - eb.addField("Zuletzt gesehen", TIME_FORMATTER.format(timestampLastPlayerOnline), false); - } - if (lastPlayersOnline > 0) { + eb.addField("Spieler online", newPlayersOnline + " / " + serverInfo.get("playerMax"), false); + if (newPlayersOnline == 0) { + if (lastPlayersOnline > newPlayersOnline) { + timestampLastPlayerOnline = LocalDateTime.now(); + StatusProviderFactory.updateTimestamp(this, timestampLastPlayerOnline); + } + eb.addField("Zuletzt gesehen", + StatusProviderFactory.TIME_FORMATTER.format(timestampLastPlayerOnline), false); + } else { eb.addField("Spieler:", String.join(", ", (List) serverInfo.get("playerNames")), false); + } + lastPlayersOnline = newPlayersOnline; } } else { eb.addField("Offline", "", false); } - statusChannel.editMessageById(this.messageId, eb.build()).queue(); + StatusProviderFactory.updateStatus(this, eb.build()); } catch (IOException e) { Logger.logError(e.toString()); } @@ -138,7 +92,7 @@ public class StatusProvider implements Provider { e.printStackTrace(); } if (process.exitValue() != 0) { - Logger.logError("MCStatus on port " + serverPort + " exited with errorcode " + process.exitValue()); + Logger.logError("MCStatus on IP " + ip + " exited with errorcode " + process.exitValue()); } String output = new BufferedReader(new InputStreamReader(process.getInputStream())).lines() @@ -175,13 +129,8 @@ public class StatusProvider implements Provider { return result; } - @SneakyThrows @Override public void onStop() { - Logger.logInfo(String.format("Stopping StatusProvider for \"%s\" on Port %d", desc, serverPort)); - if (timestampLastPlayerOnline != null) { - FileUtils.writeStringToFile(new File(Resources.getResourcePath() + "/" + serverPort + ".txt"), - TIME_FORMATTER.format(timestampLastPlayerOnline), "UTF" + "-8"); - } + StatusProviderFactory.updateTimestamp(this, timestampLastPlayerOnline); } } diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/utils/StatusProviderFactory.java b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/StatusProviderFactory.java new file mode 100644 index 0000000..e214954 --- /dev/null +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/StatusProviderFactory.java @@ -0,0 +1,99 @@ +package de.yannicpunktdee.yoshibot.utils; + +import de.yannicpunktdee.yoshibot.main.YoshiBot; +import lombok.NonNull; +import lombok.SneakyThrows; +import net.dv8tion.jda.api.MessageBuilder; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.exceptions.ErrorResponseException; +import org.apache.commons.io.FileUtils; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.nio.file.Files; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; + +public abstract class StatusProviderFactory { + + public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss E, dd.MM.yyyy", + Locale.GERMANY); + private static final Map providers = new HashMap<>(); + private static final Map providerJSON = new HashMap<>(); + private static JSONObject rootJSON; + private static File configFile; + + @NonNull + private static final TextChannel statusChannel = + Objects.requireNonNull(YoshiBot.getInstance().getGuild().getTextChannelById(Resources.getStatus_channel())); + + @SneakyThrows + public static void createStatusProviders(String configFilePath, Set allProviders) { + configFile = new File(configFilePath); + rootJSON = new JSONObject(String.join("\n", Files.readAllLines(configFile.toPath()))); + final JSONArray servers = rootJSON.getJSONArray("servers"); + for (int i = 0; i < servers.length(); i++) { + final JSONObject server = servers.getJSONObject(i); + final String ip = server.getString("ip"); + final String name = server.getString("name"); + + if (!server.has("timestamp")) { + server.put("timestamp", TIME_FORMATTER.format(LocalDateTime.now())); + } + final LocalDateTime timestamp = LocalDateTime.parse(server.getString("timestamp"), TIME_FORMATTER); + + if (!server.has("message")) { + server.put("message", -1); + } + final long msg = ensureMessageId(server.getLong("message")); + server.put("message", msg); + + StatusProvider provider = new StatusProvider(name, Resources.getStatusUpdate(), ip, timestamp); + providers.put(provider, msg); + providerJSON.put(provider, servers.getJSONObject(i)); + } + + allProviders.addAll(providers.keySet()); + writeJSON(); + } + + public static void updateStatus(StatusProvider provider, MessageEmbed msg) { + statusChannel.editMessageById(providers.get(provider), msg).queue(); + } + + public static void updateTimestamp(StatusProvider provider, LocalDateTime timestamp) { + providerJSON.get(provider).put("timestamp", TIME_FORMATTER.format(timestamp)); + writeJSON(); + } + + @SneakyThrows + private static void writeJSON() { + BufferedWriter bw = new BufferedWriter(new FileWriter(configFile)); + bw.write(rootJSON.toString(2)); + bw.flush(); + } + + private static long createStatusMessage() { + Logger.logInfo("Creating new Status Message!"); + return StatusProviderFactory.statusChannel.sendMessage( + new MessageBuilder() + .append("ServerInformation") + .build()) + .complete().getIdLong(); + } + + private static long ensureMessageId(long messageId) { + try { + Message msg = StatusProviderFactory.statusChannel.retrieveMessageById(messageId).complete(); + return msg.getIdLong(); + } catch (ErrorResponseException e) { + return createStatusMessage(); + } + } +} diff --git a/rsc/Config.properties b/rsc/Config.properties index feb8fdb..33f533a 100644 --- a/rsc/Config.properties +++ b/rsc/Config.properties @@ -11,3 +11,4 @@ status_message_modded=952638124197040139 status_message_kreativ=952638123324616735 status_update=30 path_to_mcstatus=/home/paul/.local/bin/mcstatus +path_to_status_json=/home/paul/gits/YoshiBot/rsc/mcservers.json diff --git a/rsc/mcservers.json b/rsc/mcservers.json new file mode 100644 index 0000000..8440f20 --- /dev/null +++ b/rsc/mcservers.json @@ -0,0 +1,22 @@ +{ + "servers": [ + { + "ip": "85.214.148.23:25568", + "name": "MCMuffing™®㋏ Inc.", + "message": 960979835361046558, + "timestamp": "21:16:35 Di, 05.04.2022" + }, + { + "ip": "85.214.148.23:25566", + "name": "Enigmatica 6: Expert 1.0.0", + "message": 960970269051191386, + "timestamp": "20:15:36 Di, 05.04.2022" + }, + { + "ip": "85.214.148.23:25570", + "name": "Medieval Minecraft 1.16.5 v52", + "message": 960970288194002954, + "timestamp": "20:15:36 Di, 05.04.2022" + } + ] +} \ No newline at end of file