From c57731692038f13efa31ffb4f01e880258d050f8 Mon Sep 17 00:00:00 2001 From: Shiewk Date: Fri, 14 Mar 2025 14:52:06 +0100 Subject: [PATCH] Added a command to approximate total disk space usage --- .../blockhistory/v3/HistoryManager.java | 64 ++++++++++++++++++- .../v3/command/BlockHistoryCommand.java | 52 +++++++++++++-- src/main/resources/plugin.yml | 5 ++ 3 files changed, 112 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/shiewk/blockhistory/v3/HistoryManager.java b/src/main/java/de/shiewk/blockhistory/v3/HistoryManager.java index 46fd312..233f001 100644 --- a/src/main/java/de/shiewk/blockhistory/v3/HistoryManager.java +++ b/src/main/java/de/shiewk/blockhistory/v3/HistoryManager.java @@ -7,12 +7,13 @@ import de.shiewk.blockhistory.v3.util.BlockHistoryFileNames; import de.shiewk.blockhistory.v3.util.NamedLoggingThreadFactory; import org.bukkit.Location; import org.bukkit.World; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import java.io.*; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; import java.util.Objects; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.CompletableFuture; @@ -159,4 +160,61 @@ public final class HistoryManager { } } } + + public CompletableFuture approximateDiskSpaceBytes() { + return CompletableFuture.supplyAsync(() -> { + try { + DiskSpaceApproximationVisitor visitor = new DiskSpaceApproximationVisitor(); + Files.walkFileTree(saveDirectory, visitor); + return visitor; + } catch (IOException e) { + throw new RuntimeException(e); + } + }, readExecutor); + } + + public static class DiskSpaceApproximationVisitor implements FileVisitor { + + private long bytes = 0; + private long directories = 0; + private long files = 0; + + public long getDiskSpaceBytes(){ + return bytes; + } + + public long getDirectoryCount() { + return directories; + } + + public long getFileCount() { + return files; + } + + @Override + public @NotNull FileVisitResult preVisitDirectory(Path dir, @NotNull BasicFileAttributes attrs) { + directories++; + bytes += dir.getFileName().toString().getBytes().length; + return FileVisitResult.CONTINUE; + } + + @Override + public @NotNull FileVisitResult visitFile(Path file, @NotNull BasicFileAttributes attrs) { + files++; + bytes += file.getFileName().toString().getBytes().length; + bytes += file.toFile().length(); + return FileVisitResult.CONTINUE; + } + + @Override + public @NotNull FileVisitResult visitFileFailed(Path file, @NotNull IOException exc) throws IOException { + throw exc; + } + + @Override + public @NotNull FileVisitResult postVisitDirectory(Path dir, @Nullable IOException exc) throws IOException { + if (exc != null) throw exc; + return FileVisitResult.CONTINUE; + } + } } diff --git a/src/main/java/de/shiewk/blockhistory/v3/command/BlockHistoryCommand.java b/src/main/java/de/shiewk/blockhistory/v3/command/BlockHistoryCommand.java index 2d25fdf..8abbfc0 100644 --- a/src/main/java/de/shiewk/blockhistory/v3/command/BlockHistoryCommand.java +++ b/src/main/java/de/shiewk/blockhistory/v3/command/BlockHistoryCommand.java @@ -41,6 +41,10 @@ public final class BlockHistoryCommand { .requires(CommandUtil.requirePermission("blockhistory.command.stats")) .executes(this::statsCommand) ) + .then(literal("diskspace") + .requires(CommandUtil.requirePermission("blockhistory.command.diskspace")) + .executes(this::approximateDiskSpace) + ) .then(literal("history") .requires(CommandUtil.requirePermission("blockhistory.command.history")) .then(argument("location", ArgumentTypes.blockPosition()) @@ -53,9 +57,45 @@ public final class BlockHistoryCommand { .build(); } + private int approximateDiskSpace(CommandContext context) { + CommandSender sender = context.getSource().getSender(); + sender.sendMessage(CHAT_PREFIX.append( + text("Approximating disk space usage, please wait... (this could take a while)", COLOR_PRIMARY) + )); + try { + instance().getHistoryManager().approximateDiskSpaceBytes().whenComplete((result, throwable) -> { + if (throwable != null){ + sender.sendMessage(CHAT_PREFIX.append( + text("This operation failed, please check the server logs.", COLOR_FAIL) + )); + StringWriter strw = new StringWriter(); + throwable.printStackTrace(new PrintWriter(strw)); + + logger().warn("Exception while approximating disk space:"); + for (String s : strw.toString().split("\n")) { + logger().warn(s); + } + } else { + long bytes = result.getDiskSpaceBytes(); + long directories = result.getDirectoryCount(); + long files = result.getFileCount(); + sender.sendMessage(CHAT_PREFIX.append( + text("Block history files use approximately ", COLOR_PRIMARY) + .append(text(UnitUtil.formatDataSize(bytes), COLOR_SECONDARY)) + .append(text(" of disk space. ")) + .append(text("(%s directories with %s files in total)".formatted(directories, files), NamedTextColor.GRAY)) + )); + } + }); + } catch (RejectedExecutionException e) { + sender.sendMessage(text("The searching system is currently too busy, please try again later.", COLOR_FAIL)); + } + return Command.SINGLE_SUCCESS; + } + private int statsCommand(CommandContext context) { CommandSender sender = context.getSource().getSender(); - StatManager statManager = BlockHistoryPlugin.instance().getStatManager(); + StatManager statManager = instance().getStatManager(); long millisSinceStart = statManager.getTimeMsSinceStart(); sender.sendMessage(CHAT_PREFIX.append( text("The plugin has started up ", COLOR_PRIMARY) @@ -88,9 +128,9 @@ public final class BlockHistoryCommand { StringWriter strw = new StringWriter(); e.printStackTrace(new PrintWriter(strw)); - BlockHistoryPlugin.logger().warn("Exception while getting usable disk space:"); + logger().warn("Exception while getting usable disk space:"); for (String s : strw.toString().split("\n")) { - BlockHistoryPlugin.logger().warn(s); + logger().warn(s); } } return Command.SINGLE_SUCCESS; @@ -125,9 +165,9 @@ public final class BlockHistoryCommand { StringWriter strw = new StringWriter(); throwable.printStackTrace(new PrintWriter(strw)); - BlockHistoryPlugin.logger().warn("Exception while searching block at world {} x {} y {} z {}:", searchedWorld, blockX, blockY, blockZ); + logger().warn("Exception while searching block at world {} x {} y {} z {}:", searchedWorld, blockX, blockY, blockZ); for (String s : strw.toString().split("\n")) { - BlockHistoryPlugin.logger().warn(s); + logger().warn(s); } sender.sendMessage(CHAT_PREFIX.append(text("An error occurred while searching, please check the server console.\n", COLOR_FAIL))); } else { @@ -151,7 +191,7 @@ public final class BlockHistoryCommand { @Override public void onNoFilePresent(FileNotFoundException e) { - BlockHistoryPlugin.logger().info("No file present"); + logger().info("No file present"); } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index f8fe80f..2b64252 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -18,5 +18,10 @@ permissions: blockhistory.command.history: default: op description: Player can search the history of a block + children: + blockhistory.command.root: true + blockhistory.command.diskspace: + default: op + description: Player can approximate disk space usage children: blockhistory.command.root: true \ No newline at end of file