From 723e29cdd0fa81cb05568d455b1be631504ff371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 10 May 2020 14:02:25 +0200 Subject: [PATCH] Continue working on the backup system --- .../com/plotsquared/bukkit/BukkitMain.java | 16 +++- .../java/com/plotsquared/core/IPlotMain.java | 9 +++ .../com/plotsquared/core/backup/Backup.java | 21 ++++- .../core/backup/BackupManager.java | 54 ++++++++----- .../core/backup/BackupProfile.java | 8 ++ .../core/backup/NullBackupManager.java | 61 +++++++++++++++ .../core/backup/NullBackupProfile.java | 5 ++ .../core/backup/PlayerBackupProfile.java | 21 ++++- .../core/backup/SimpleBackupManager.java | 77 +++++++++++++++++++ .../com/plotsquared/core/command/Save.java | 1 - .../core/configuration/Settings.java | 9 +++ 11 files changed, 257 insertions(+), 25 deletions(-) create mode 100644 Core/src/main/java/com/plotsquared/core/backup/NullBackupManager.java create mode 100644 Core/src/main/java/com/plotsquared/core/backup/SimpleBackupManager.java diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java index 79d27ae33..85a216e9f 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java @@ -52,6 +52,9 @@ import com.plotsquared.bukkit.util.uuid.OfflineUUIDWrapper; import com.plotsquared.bukkit.util.uuid.SQLUUIDHandler; import com.plotsquared.core.IPlotMain; import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.backup.BackupManager; +import com.plotsquared.core.backup.NullBackupManager; +import com.plotsquared.core.backup.SimpleBackupManager; import com.plotsquared.core.configuration.Captions; import com.plotsquared.core.configuration.ChatFormatter; import com.plotsquared.core.configuration.ConfigurationNode; @@ -136,6 +139,7 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain { + private static final int BSTATS_ID = 1404; @Getter private static WorldEdit worldEdit; static { @@ -151,7 +155,7 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain private Method methodUnloadChunk0; private boolean methodUnloadSetup = false; private boolean metricsStarted; - private static final int BSTATS_ID = 1404; + @Getter private BackupManager backupManager; @Override public int[] getServerVersion() { if (this.version == null) { @@ -229,6 +233,15 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain e.printStackTrace(); } } + + try { + this.backupManager = new SimpleBackupManager(); + } catch (final Exception e) { + PlotSquared.log(Captions.PREFIX + "&6Failed to initialize backup manager"); + e.printStackTrace(); + PlotSquared.log(Captions.PREFIX + "&6Backup features will be disabled"); + this.backupManager = new NullBackupManager(); + } } private void unload() { @@ -886,4 +899,5 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain ((WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit")); return wePlugin.wrapCommandSender(console); } + } diff --git a/Core/src/main/java/com/plotsquared/core/IPlotMain.java b/Core/src/main/java/com/plotsquared/core/IPlotMain.java index 1b04b220f..cf6c8fb95 100644 --- a/Core/src/main/java/com/plotsquared/core/IPlotMain.java +++ b/Core/src/main/java/com/plotsquared/core/IPlotMain.java @@ -25,6 +25,7 @@ */ package com.plotsquared.core; +import com.plotsquared.core.backup.BackupManager; import com.plotsquared.core.generator.GeneratorWrapper; import com.plotsquared.core.generator.HybridUtils; import com.plotsquared.core.generator.IndependentPlotGenerator; @@ -262,4 +263,12 @@ public interface IPlotMain extends ILogger { List, Boolean>> getPluginIds(); Actor getConsole(); + + /** + * Get the backup manager instance + * + * @return Backup manager + */ + BackupManager getBackupManager(); + } diff --git a/Core/src/main/java/com/plotsquared/core/backup/Backup.java b/Core/src/main/java/com/plotsquared/core/backup/Backup.java index 3adb9acf0..a84fc497f 100644 --- a/Core/src/main/java/com/plotsquared/core/backup/Backup.java +++ b/Core/src/main/java/com/plotsquared/core/backup/Backup.java @@ -26,18 +26,35 @@ package com.plotsquared.core.backup; import lombok.AccessLevel; +import lombok.Getter; import lombok.RequiredArgsConstructor; +import org.jetbrains.annotations.Nullable; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; /** * Object representing a plot backup. This does not actually contain the * backup itself, it is just a pointer to an available backup */ -@RequiredArgsConstructor(access = AccessLevel.PACKAGE) public class Backup { +@RequiredArgsConstructor(access = AccessLevel.PACKAGE) @Getter public class Backup { private final BackupProfile owner; private final long creationTime; - private final Path file; + @Nullable private final Path file; + + /** + * Delete the backup + */ + public void delete() { + if (file != null) { + try { + Files.deleteIfExists(file); + } catch (final IOException e) { + e.printStackTrace(); + } + } + } } diff --git a/Core/src/main/java/com/plotsquared/core/backup/BackupManager.java b/Core/src/main/java/com/plotsquared/core/backup/BackupManager.java index 16f30eeb8..0d1842fc3 100644 --- a/Core/src/main/java/com/plotsquared/core/backup/BackupManager.java +++ b/Core/src/main/java/com/plotsquared/core/backup/BackupManager.java @@ -25,24 +25,13 @@ */ package com.plotsquared.core.backup; -import com.plotsquared.core.PlotSquared; import com.plotsquared.core.plot.Plot; -import lombok.Getter; import org.jetbrains.annotations.NotNull; -import java.nio.file.Files; import java.nio.file.Path; +import java.util.concurrent.CompletableFuture; -public class BackupManager { - - @Getter private final Path backupPath; - - public BackupManager() throws Exception { - this.backupPath = PlotSquared.imp().getDirectory().toPath().resolve("backups"); - if (!Files.exists(backupPath)) { - Files.createDirectory(backupPath); - } - } +public interface BackupManager { /** * Get the backup profile for a plot based on its @@ -51,11 +40,38 @@ public class BackupManager { * @param plot Plot to get the backup profile for * @return Backup profile */ - @NotNull public BackupProfile getProfile(@NotNull final Plot plot) { - if (plot.hasOwner()) { - return new PlayerBackupProfile(plot.getOwnerAbs(), plot, this); - } - return new NullBackupProfile(); - } + @NotNull BackupProfile getProfile(@NotNull final Plot plot); + + /** + * This will perform an automatic backup of the plot iff the plot has an owner + * and automatic backups are enabled. Otherwise it will complete immediately. + * + * @param plot Plot to perform the automatic backup on + * @return Future that completes when the backup is finished + */ + @NotNull CompletableFuture automaticBackup(@NotNull final Plot plot); + + /** + * Get the directory in which backups are stored + * + * @return Backup directory path + */ + @NotNull Path getBackupPath(); + + /** + * Get the maximum amount of backups that may be stored for + * a plot-owner combo + * + * @return Backup limit + */ + int getBackupLimit(); + + /** + * Returns true if (potentially) destructive actions should cause + * PlotSquared to create automatic plot backups + * + * @return True if automatic backups are enabled + */ + boolean shouldAutomaticallyBackup(); } diff --git a/Core/src/main/java/com/plotsquared/core/backup/BackupProfile.java b/Core/src/main/java/com/plotsquared/core/backup/BackupProfile.java index 8ba756e87..90b4d9694 100644 --- a/Core/src/main/java/com/plotsquared/core/backup/BackupProfile.java +++ b/Core/src/main/java/com/plotsquared/core/backup/BackupProfile.java @@ -54,4 +54,12 @@ public interface BackupProfile { */ @NotNull Path getBackupDirectory(); + /** + * Create a backup of the plot. If the profile is at the + * maximum backup capacity, the oldest backup will be deleted. + * + * @return Future that completes with the created backup. + */ + @NotNull CompletableFuture createBackup(); + } diff --git a/Core/src/main/java/com/plotsquared/core/backup/NullBackupManager.java b/Core/src/main/java/com/plotsquared/core/backup/NullBackupManager.java new file mode 100644 index 000000000..d5f9bd954 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/backup/NullBackupManager.java @@ -0,0 +1,61 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.backup; + +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.plot.Plot; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; + +/** + * {@inheritDoc} + */ +public class NullBackupManager implements BackupManager { + + @Override @NotNull public BackupProfile getProfile(@NotNull Plot plot) { + return new NullBackupProfile(); + } + + @Override @NotNull public CompletableFuture automaticBackup(@NotNull Plot plot) { + return CompletableFuture.completedFuture(null); + } + + @Override @NotNull public Path getBackupPath() { + return Objects.requireNonNull(PlotSquared.imp()).getDirectory().toPath(); + } + + @Override public int getBackupLimit() { + return 0; + } + + @Override public boolean shouldAutomaticallyBackup() { + return false; + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/backup/NullBackupProfile.java b/Core/src/main/java/com/plotsquared/core/backup/NullBackupProfile.java index add8c3eb3..e4647592c 100644 --- a/Core/src/main/java/com/plotsquared/core/backup/NullBackupProfile.java +++ b/Core/src/main/java/com/plotsquared/core/backup/NullBackupProfile.java @@ -35,6 +35,7 @@ import java.util.concurrent.CompletableFuture; /** * Backup profile for a plot without an owner + * {@inheritDoc} */ public class NullBackupProfile implements BackupProfile { @@ -49,4 +50,8 @@ public class NullBackupProfile implements BackupProfile { return new File(".").toPath(); } + @Override @NotNull public CompletableFuture createBackup() { + throw new UnsupportedOperationException("Cannot create backup of an unowned plot"); + } + } diff --git a/Core/src/main/java/com/plotsquared/core/backup/PlayerBackupProfile.java b/Core/src/main/java/com/plotsquared/core/backup/PlayerBackupProfile.java index c87286093..f99bd8cd9 100644 --- a/Core/src/main/java/com/plotsquared/core/backup/PlayerBackupProfile.java +++ b/Core/src/main/java/com/plotsquared/core/backup/PlayerBackupProfile.java @@ -26,6 +26,7 @@ package com.plotsquared.core.backup; import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.util.SchematicHandler; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; @@ -56,7 +57,7 @@ public class PlayerBackupProfile implements BackupProfile { return name.endsWith(".schem") || name.endsWith(".schematic"); } - @NotNull public CompletableFuture> listBackups() { + @Override @NotNull public CompletableFuture> listBackups() { return CompletableFuture.supplyAsync(() -> { final Path path = this.getBackupDirectory(); if (!Files.exists(path)) { @@ -85,7 +86,7 @@ public class PlayerBackupProfile implements BackupProfile { }); } - public void destroy() throws IOException { + @Override public void destroy() throws IOException { Files.delete(this.getBackupDirectory()); } @@ -94,4 +95,20 @@ public class PlayerBackupProfile implements BackupProfile { .resolve(plot.getId().toCommaSeparatedString()).resolve(owner.toString()); } + @Override @NotNull public CompletableFuture createBackup() { + final CompletableFuture future = new CompletableFuture<>(); + this.listBackups().thenAcceptAsync(backups -> { + if (backups.size() == backupManager.getBackupLimit()) { + backups.get(backups.size() - 1).delete(); + } + final List plots = Collections.singletonList(plot); + final boolean result = SchematicHandler.manager.exportAll(plots, null, null, () -> + future.complete(new Backup(this, System.currentTimeMillis(), null))); + if (!result) { + future.completeExceptionally(new RuntimeException("Failed to complete the backup")); + } + }); + return future; + } + } diff --git a/Core/src/main/java/com/plotsquared/core/backup/SimpleBackupManager.java b/Core/src/main/java/com/plotsquared/core/backup/SimpleBackupManager.java new file mode 100644 index 000000000..4f86af781 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/backup/SimpleBackupManager.java @@ -0,0 +1,77 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.backup; + +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.configuration.Settings; +import com.plotsquared.core.plot.Plot; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; + +/** + * {@inheritDoc} + */ +@RequiredArgsConstructor public class SimpleBackupManager implements BackupManager { + + @Getter private final Path backupPath; + private final boolean automaticBackup; + @Getter private final int backupLimit; + + public SimpleBackupManager() throws Exception { + this.backupPath = Objects.requireNonNull(PlotSquared.imp()).getDirectory().toPath().resolve("backups"); + if (!Files.exists(backupPath)) { + Files.createDirectory(backupPath); + } + this.automaticBackup = Settings.Backup.AUTOMATIC_BACKUPS; + this.backupLimit = Settings.Backup.BACKUP_LIMIT; + } + + @Override @NotNull public BackupProfile getProfile(@NotNull final Plot plot) { + if (plot.hasOwner()) { + return new PlayerBackupProfile(plot.getOwnerAbs(), plot, this); + } + return new NullBackupProfile(); + } + + @Override @NotNull public CompletableFuture automaticBackup(@NotNull final Plot plot) { + final BackupProfile profile; + if (!this.shouldAutomaticallyBackup() || (profile = getProfile(plot)) instanceof NullBackupProfile) { + return CompletableFuture.completedFuture(null); + } + return profile.createBackup(); + } + + @Override public boolean shouldAutomaticallyBackup() { + return this.automaticBackup; + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/command/Save.java b/Core/src/main/java/com/plotsquared/core/command/Save.java index 207ce9cbc..6196f08b7 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Save.java +++ b/Core/src/main/java/com/plotsquared/core/command/Save.java @@ -43,7 +43,6 @@ import java.util.List; import java.util.UUID; @CommandDeclaration(command = "save", - aliases = {"backup"}, description = "Save your plot", category = CommandCategory.SCHEMATIC, requiredType = RequiredType.NONE, diff --git a/Core/src/main/java/com/plotsquared/core/configuration/Settings.java b/Core/src/main/java/com/plotsquared/core/configuration/Settings.java index 3b1fe6b22..6db5f8476 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Settings.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Settings.java @@ -413,4 +413,13 @@ public class Settings extends Config { @Comment("Try to guess plot owners from sign data. This may decrease server performance") public static boolean GUESS_PLOT_OWNER = false; } + + @Comment("Backup related settings") + public static final class Backup { + @Comment("Automatically backup plots when destructive commands are performed") + public static boolean AUTOMATIC_BACKUPS = true; + @Comment("Maximum amount of backups associated with a plot") + public static int BACKUP_LIMIT = 3; + } + }