diff --git a/src/main/java/land/chipmunk/chipmunkbot/Main.java b/src/main/java/land/chipmunk/chipmunkbot/Main.java index c97dbad..3288a2b 100644 --- a/src/main/java/land/chipmunk/chipmunkbot/Main.java +++ b/src/main/java/land/chipmunk/chipmunkbot/Main.java @@ -13,6 +13,7 @@ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; +import java.io.IOException; import com.google.gson.JsonObject; import com.google.gson.JsonElement; @@ -21,7 +22,7 @@ import com.google.gson.JsonParser; import com.google.gson.Gson; public class Main { - private static JsonObject getConfig (File file) throws Exception { + private static JsonObject getConfig (File file) throws IOException { if (!file.exists()) { // Read the default config InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("default_config.json"); diff --git a/src/main/java/land/chipmunk/chipmunkbot/commands/InfoCommand.java b/src/main/java/land/chipmunk/chipmunkbot/commands/InfoCommand.java new file mode 100644 index 0000000..411eccb --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkbot/commands/InfoCommand.java @@ -0,0 +1,90 @@ +package land.chipmunk.chipmunkbot.commands; + +import land.chipmunk.chipmunkbot.util.CPUInfo; +import land.chipmunk.chipmunkbot.command.*; +import static land.chipmunk.chipmunkbot.plugins.CommandManager.literal; +import static land.chipmunk.chipmunkbot.plugins.CommandManager.argument; +import static com.mojang.brigadier.arguments.StringArgumentType.greedyString; +import static com.mojang.brigadier.arguments.StringArgumentType.getString; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.tree.CommandNode; +import com.mojang.brigadier.context.CommandContext; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.JoinConfiguration; +import java.util.List; +import java.util.ArrayList; +import java.net.InetAddress; +import java.lang.management.*; +import java.io.IOException; + +public class InfoCommand extends Command { + public InfoCommand () { + super(); + + this.node( + literal("info") + .then( + literal("server") + .executes(this::sendServerInfo) + ) + ); + } + + public int sendServerInfo (CommandContext context) { + final CommandSource source = context.getSource(); + + final OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean(); + final RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); + final MemoryMXBean memory = ManagementFactory.getMemoryMXBean(); + + // ? Should I send a single message that uses newlines instead? + source.sendOutput(formatEntry(Component.translatable("Working directory"), Component.text(System.getProperty("user.dir"))), false); + try { + final InetAddress localhost = InetAddress.getLocalHost(); + source.sendOutput(formatEntry(Component.translatable("Hostname"), Component.text(localhost.getHostName())), false); + source.sendOutput(formatEntry(Component.translatable("IP address"), Component.text(localhost.getHostAddress())), false); + } catch (Exception ignored) { + } + + source.sendOutput(formatEntry(Component.translatable("OS name"), Component.text(os.getName())), false); + source.sendOutput(formatEntry(Component.translatable("OS version"), Component.text(os.getVersion())), false); + source.sendOutput(formatEntry(Component.translatable("OS architecture"), Component.text(os.getArch())), false); + source.sendOutput(formatEntry(Component.translatable("CPU cores"), Component.text(os.getAvailableProcessors())), false); + source.sendOutput(formatEntry(Component.translatable("CPU load"), Component.text(os.getSystemLoadAverage())), false); + + try { + final String cpuModel = CPUInfo.readCpuInfo().get("model name"); + source.sendOutput(formatEntry(Component.translatable("CPU Model"), Component.text(cpuModel)), false); + } catch (IOException ignored) { + } + + source.sendOutput(formatEntry(Component.translatable("Java VM"), Component.text(runtime.getVmName())), false); + source.sendOutput(formatEntry(Component.translatable("Java version"), Component.text(runtime.getVmVersion())), false); + + source.sendOutput(formatEntry(Component.translatable("Heap memory usage"), formatMemoryUsage(memory.getHeapMemoryUsage())), false); + + return 1; + } + + public Component formatEntry (Component key, Component value) { + return Component.translatable( + "%s: %s", + key.color(NamedTextColor.GREEN), + value.color(NamedTextColor.DARK_GREEN) + ); + } + + public Component formatMemoryUsage (long used, long max) { + return Component.translatable( + "%sMB/%sMB", + Component.text(used / 1024l / 1024l), + Component.text(max / 1024l / 1024l) + ); + } + + public Component formatMemoryUsage (MemoryUsage usage) { + return formatMemoryUsage(usage.getUsed(), usage.getMax()); + } +} diff --git a/src/main/java/land/chipmunk/chipmunkbot/plugins/CommandManager.java b/src/main/java/land/chipmunk/chipmunkbot/plugins/CommandManager.java index 2bcaf80..5b6dacb 100644 --- a/src/main/java/land/chipmunk/chipmunkbot/plugins/CommandManager.java +++ b/src/main/java/land/chipmunk/chipmunkbot/plugins/CommandManager.java @@ -23,7 +23,7 @@ import lombok.Setter; public class CommandManager { private ChipmunkBot client; @Getter @Setter private CommandDispatcher dispatcher = new CommandDispatcher<>(); - private final Command[] commands = {new TestCommand(), new HelpCommand(), new RunCommand(), new EchoCommand()}; + private final Command[] commands = {new TestCommand(), new HelpCommand(), new RunCommand(), new EchoCommand(), new InfoCommand()}; static { // ? Is messing with static properties a good idea? diff --git a/src/main/java/land/chipmunk/chipmunkbot/util/CPUInfo.java b/src/main/java/land/chipmunk/chipmunkbot/util/CPUInfo.java new file mode 100644 index 0000000..52963b5 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkbot/util/CPUInfo.java @@ -0,0 +1,50 @@ +package land.chipmunk.chipmunkbot.util; + +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.Reader; +import java.io.InputStreamReader; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Map; +import java.util.HashMap; + +public class CPUInfo { + public static Map readCpuInfo () throws IOException { + return readCpuInfo(new File("/proc/cpuinfo")); + } + + public static Map readCpuInfo (File file) throws IOException { + final InputStream opt = new FileInputStream(file); + final Reader reader = new BufferedReader(new InputStreamReader(opt)); + + return readCpuInfo(reader); + } + + public static Map readCpuInfo (Reader reader) throws IOException { + final Map map = new HashMap<>(); + + do { + final String key = ((char) reader.read()) + readUntil(reader, ':').trim(); + final String value = readUntil(reader, '\n').trim(); + + if (!key.isEmpty()) map.put(key, value); + } while (reader.ready()); + + return map; + } + + private static String readUntil (Reader reader, char character) throws IOException { + StringBuilder stringBuilder = new StringBuilder(); + + while (true) { + int readInt = reader.read(); + if (readInt == -1 || (char) readInt == character) break; + stringBuilder.append((char) readInt); + } + + return stringBuilder.toString(); + } +}