summaryrefslogtreecommitdiff
path: root/src/main/java/com/keuin/kbackupfabric
diff options
context:
space:
mode:
authorKeuin <[email protected]>2021-01-13 14:32:08 +0800
committerkeuin <[email protected]>2021-01-13 14:32:08 +0800
commit2bc659d8f95a97d0514491e48ed9c66828a4e308 (patch)
tree202962a05caadf652ec117812cc6704ea64d001c /src/main/java/com/keuin/kbackupfabric
parent1c6d68ee303ad3d4b1df5c3d433bf972256f0c8e (diff)
BackupMethod now becomes stateful
Diffstat (limited to 'src/main/java/com/keuin/kbackupfabric')
-rw-r--r--src/main/java/com/keuin/kbackupfabric/KBCommands.java19
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/BackupOperation.java22
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java19
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/backup/method/BackupMethod.java23
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/backup/method/ConfiguredBackupMethod.java23
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/backup/method/ConfiguredIncrementalBackupMethod.java52
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/backup/method/ConfiguredPrimitiveBackupMethod.java (renamed from src/main/java/com/keuin/kbackupfabric/operation/backup/method/PrimitiveBackupMethod.java)23
-rw-r--r--src/main/java/com/keuin/kbackupfabric/operation/backup/method/IncrementalBackupMethod.java17
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionFactory.java2
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/name/IncrementalBackupFileNameEncoder.java4
10 files changed, 121 insertions, 83 deletions
diff --git a/src/main/java/com/keuin/kbackupfabric/KBCommands.java b/src/main/java/com/keuin/kbackupfabric/KBCommands.java
index 0e268ce..8f0e451 100644
--- a/src/main/java/com/keuin/kbackupfabric/KBCommands.java
+++ b/src/main/java/com/keuin/kbackupfabric/KBCommands.java
@@ -5,7 +5,7 @@ import com.keuin.kbackupfabric.operation.BackupOperation;
import com.keuin.kbackupfabric.operation.DeleteOperation;
import com.keuin.kbackupfabric.operation.RestoreOperation;
import com.keuin.kbackupfabric.operation.abstracts.i.Invokable;
-import com.keuin.kbackupfabric.operation.backup.method.PrimitiveBackupMethod;
+import com.keuin.kbackupfabric.operation.backup.method.ConfiguredPrimitiveBackupMethod;
import com.keuin.kbackupfabric.util.PrintUtil;
import com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil;
import com.keuin.kbackupfabric.util.backup.name.PrimitiveBackupFileNameEncoder;
@@ -16,6 +16,7 @@ import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.ServerCommandSource;
import java.io.File;
+import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -227,10 +228,18 @@ public final class KBCommands {
}
}
- // Do backup
- PrintUtil.info("Invoking backup worker ...");
- //BackupWorker.invoke(context, backupName, metadata);
- BackupOperation operation = new BackupOperation(context, customBackupName, PrimitiveBackupMethod.getInstance());
+ PrintUtil.info("Start backup...");
+
+ // configure backup method
+ MinecraftServer server = context.getSource().getMinecraftServer();
+ ConfiguredPrimitiveBackupMethod method = new ConfiguredPrimitiveBackupMethod(
+ new PrimitiveBackupFileNameEncoder().encode(customBackupName, LocalDateTime.now()),
+ getLevelPath(server),
+ getBackupSaveDirectory(server).getAbsolutePath()
+ );
+
+ // dispatch to operation worker
+ BackupOperation operation = new BackupOperation(context, method);
if (operation.invoke()) {
return SUCCESS;
} else if (operation.isBlocked()) {
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/BackupOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/BackupOperation.java
index 0ff2c40..645facd 100644
--- a/src/main/java/com/keuin/kbackupfabric/operation/BackupOperation.java
+++ b/src/main/java/com/keuin/kbackupfabric/operation/BackupOperation.java
@@ -2,7 +2,7 @@ package com.keuin.kbackupfabric.operation;
import com.keuin.kbackupfabric.operation.abstracts.InvokableAsyncBlockingOperation;
import com.keuin.kbackupfabric.operation.backup.feedback.BackupFeedback;
-import com.keuin.kbackupfabric.operation.backup.method.BackupMethod;
+import com.keuin.kbackupfabric.operation.backup.method.ConfiguredBackupMethod;
import com.keuin.kbackupfabric.util.PrintUtil;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.server.MinecraftServer;
@@ -15,22 +15,20 @@ import java.util.HashMap;
import java.util.Map;
import static com.keuin.kbackupfabric.util.PrintUtil.msgInfo;
-import static com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil.*;
+import static com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil.getBackupSaveDirectory;
public class BackupOperation extends InvokableAsyncBlockingOperation {
private final CommandContext<ServerCommandSource> context;
- private final String customBackupName;
private final Map<World, Boolean> oldWorldsSavingDisabled = new HashMap<>();
- private final BackupMethod backupMethod;
+ private final ConfiguredBackupMethod configuredBackupMethod;
private long startTime;
- public BackupOperation(CommandContext<ServerCommandSource> context, String customBackupName, BackupMethod backupMethod) {
+ public BackupOperation(CommandContext<ServerCommandSource> context, ConfiguredBackupMethod configuredBackupMethod) {
super("BackupWorker");
this.context = context;
- this.customBackupName = customBackupName;
- this.backupMethod = backupMethod;
+ this.configuredBackupMethod = configuredBackupMethod;
}
@Override
@@ -49,10 +47,8 @@ public class BackupOperation extends InvokableAsyncBlockingOperation {
}
// Make zip
- String levelPath = getLevelPath(server);
- String backupFileName = getBackupFileName(customBackupName);
- BackupFeedback result = backupMethod.backup(customBackupName, levelPath, backupSaveDirectory);
+ BackupFeedback result = configuredBackupMethod.backup();
if (result.isSuccess()) {
// Restore old auto-save switch stat
server.getWorlds().forEach(world -> world.savingDisabled = oldWorldsSavingDisabled.getOrDefault(world, true));
@@ -74,14 +70,14 @@ public class BackupOperation extends InvokableAsyncBlockingOperation {
@Override
protected boolean sync() {
- //// Save world, save old autosave configs
+ //// Save world, save old auto-save configs
- PrintUtil.broadcast(String.format("Making backup %s, please wait ...", customBackupName));
+ PrintUtil.broadcast("Making backup, please wait ...");
// Get server
MinecraftServer server = context.getSource().getMinecraftServer();
- // Save old autosave switch stat temporally
+ // Save old auto-save switch state for restoration after finished
oldWorldsSavingDisabled.clear();
server.getWorlds().forEach(world -> {
oldWorldsSavingDisabled.put(world, world.savingDisabled);
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java
index 02b76f1..011d2e2 100644
--- a/src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java
+++ b/src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java
@@ -1,37 +1,30 @@
package com.keuin.kbackupfabric.operation;
import com.keuin.kbackupfabric.operation.abstracts.InvokableBlockingOperation;
-import com.keuin.kbackupfabric.operation.backup.method.BackupMethod;
-import com.keuin.kbackupfabric.operation.backup.method.PrimitiveBackupMethod;
+import com.keuin.kbackupfabric.operation.backup.method.ConfiguredBackupMethod;
+import com.keuin.kbackupfabric.operation.backup.method.ConfiguredPrimitiveBackupMethod;
import com.keuin.kbackupfabric.util.PrintUtil;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.ServerCommandSource;
-import java.io.File;
import java.io.IOException;
-import static com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil.getBackupFileName;
-import static com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil.getBackupSaveDirectory;
-
public class RestoreOperation extends InvokableBlockingOperation {
//private static final Logger LOGGER = LogManager.getLogger();
private final String backupFileName;
private final Thread serverThread;
- private final String backupSavePath;
- private final String levelPath;
private final CommandContext<ServerCommandSource> context;
private final MinecraftServer server;
- private final BackupMethod backupMethod = PrimitiveBackupMethod.getInstance();
+ private final ConfiguredBackupMethod configuredBackupMethod;
public RestoreOperation(CommandContext<ServerCommandSource> context, String backupSavePath, String levelPath, String backupFileName) {
server = context.getSource().getMinecraftServer();
this.backupFileName = backupFileName;
this.serverThread = server.getThread();
- this.backupSavePath = backupSavePath;
- this.levelPath = levelPath;
this.context = context;
+ this.configuredBackupMethod = new ConfiguredPrimitiveBackupMethod(backupFileName, levelPath, backupSavePath);
}
@Override
@@ -39,9 +32,7 @@ public class RestoreOperation extends InvokableBlockingOperation {
// do restore to backupName
PrintUtil.broadcast(String.format("Restoring to backup %s ...", backupFileName));
- String backupFileName = getBackupFileName(this.backupFileName);
PrintUtil.debug("Backup file name: " + backupFileName);
- File backupFile = new File(getBackupSaveDirectory(server), backupFileName);
PrintUtil.msgInfo(context, "Server will shutdown in a few seconds, depending on world size and disk speed, the progress may take from seconds to minutes.", true);
PrintUtil.msgInfo(context, "Please do not force the server stop, or the level would be broken.", true);
@@ -94,7 +85,7 @@ public class RestoreOperation extends InvokableBlockingOperation {
}while(--cnt > 0);
////////////////////
- if (backupMethod.restore(backupFileName, levelPath, backupSavePath)) {
+ if (configuredBackupMethod.restore()) {
//ServerRestartUtil.forkAndRestart();
System.exit(111);
} else {
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/backup/method/BackupMethod.java b/src/main/java/com/keuin/kbackupfabric/operation/backup/method/BackupMethod.java
deleted file mode 100644
index 7afbabd..0000000
--- a/src/main/java/com/keuin/kbackupfabric/operation/backup/method/BackupMethod.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.keuin.kbackupfabric.operation.backup.method;
-
-import com.keuin.kbackupfabric.operation.backup.feedback.BackupFeedback;
-
-import java.io.IOException;
-
-/**
- * Provide specific backup method, which is implemented statelessly.
- */
-public interface BackupMethod {
-
- /**
- * Perform a backup with given method. The backup will be saved as the given name.
- * Note: real file name depends on the backup type.
- *
- * @param customBackupName the custom backup name.
- * @return if the backup operation succeed.
- */
- BackupFeedback backup(String customBackupName, String levelPath, String backupSaveDirectory) throws IOException;
-
- boolean restore(String backupName, String levelPath, String backupSaveDirectory) throws IOException;
-
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/backup/method/ConfiguredBackupMethod.java b/src/main/java/com/keuin/kbackupfabric/operation/backup/method/ConfiguredBackupMethod.java
new file mode 100644
index 0000000..b1b8d90
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/operation/backup/method/ConfiguredBackupMethod.java
@@ -0,0 +1,23 @@
+package com.keuin.kbackupfabric.operation.backup.method;
+
+import com.keuin.kbackupfabric.operation.backup.feedback.BackupFeedback;
+
+import java.io.IOException;
+
+/**
+ * Provide specific backup method, which has been configured with proper settings,
+ * such as saving directory and level path.
+ */
+public interface ConfiguredBackupMethod {
+
+ /**
+ * Perform a backup with given method. The backup will be saved as the given name.
+ * Note: real file name depends on the backup type.
+ *
+ * @return backup result.
+ */
+ BackupFeedback backup() throws IOException;
+
+ boolean restore() throws IOException;
+
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/backup/method/ConfiguredIncrementalBackupMethod.java b/src/main/java/com/keuin/kbackupfabric/operation/backup/method/ConfiguredIncrementalBackupMethod.java
new file mode 100644
index 0000000..0201d18
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/operation/backup/method/ConfiguredIncrementalBackupMethod.java
@@ -0,0 +1,52 @@
+package com.keuin.kbackupfabric.operation.backup.method;
+
+import com.keuin.kbackupfabric.operation.backup.feedback.IncrementalBackupFeedback;
+import com.keuin.kbackupfabric.util.backup.incremental.ObjectCollection;
+import com.keuin.kbackupfabric.util.backup.incremental.ObjectCollectionFactory;
+import com.keuin.kbackupfabric.util.backup.incremental.ObjectCollectionSerializer;
+import com.keuin.kbackupfabric.util.backup.incremental.identifier.Sha256Identifier;
+import com.keuin.kbackupfabric.util.backup.incremental.manager.IncrementalBackupStorageManager;
+import com.keuin.kbackupfabric.util.backup.name.IncrementalBackupFileNameEncoder;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.time.LocalDateTime;
+
+public class ConfiguredIncrementalBackupMethod implements ConfiguredBackupMethod {
+
+ private final String backupFileName;
+ private final String levelPath;
+ private final String backupSavePath;
+
+ public ConfiguredIncrementalBackupMethod(String backupFileName, String levelPath, String backupSavePath) {
+ this.backupFileName = backupFileName;
+ this.levelPath = levelPath;
+ this.backupSavePath = backupSavePath;
+ }
+
+ @Override
+ public IncrementalBackupFeedback backup() throws IOException {
+ String customBackupName = new IncrementalBackupFileNameEncoder().decode(backupFileName).customName;
+ String backupIndexFileName = new IncrementalBackupFileNameEncoder().encode(customBackupName, LocalDateTime.now());
+ File levelPathFile = new File(levelPath);
+
+ // construct incremental backup index
+ ObjectCollection collection = new ObjectCollectionFactory<>(Sha256Identifier.getFactory())
+ .fromDirectory(levelPathFile);
+
+ // update storage
+ IncrementalBackupStorageManager storageManager = new IncrementalBackupStorageManager(Paths.get(backupSavePath));
+ int filesAdded = storageManager.addObjectCollection(collection, levelPathFile);
+
+ // save index file
+ ObjectCollectionSerializer.toFile(collection, new File(backupSavePath, backupIndexFileName));
+
+ return new IncrementalBackupFeedback(filesAdded >= 0, filesAdded);
+ }
+
+ @Override
+ public boolean restore() throws IOException {
+ return false;
+ }
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/backup/method/PrimitiveBackupMethod.java b/src/main/java/com/keuin/kbackupfabric/operation/backup/method/ConfiguredPrimitiveBackupMethod.java
index 1f15346..c3013e9 100644
--- a/src/main/java/com/keuin/kbackupfabric/operation/backup/method/PrimitiveBackupMethod.java
+++ b/src/main/java/com/keuin/kbackupfabric/operation/backup/method/ConfiguredPrimitiveBackupMethod.java
@@ -17,12 +17,16 @@ import java.time.LocalDateTime;
import static org.apache.commons.io.FileUtils.forceDelete;
-public class PrimitiveBackupMethod implements BackupMethod {
+public class ConfiguredPrimitiveBackupMethod implements ConfiguredBackupMethod {
- private static final PrimitiveBackupMethod INSTANCE = new PrimitiveBackupMethod();
+ private final String backupFileName;
+ private final String levelPath;
+ private final String backupSavePath;
- public static PrimitiveBackupMethod getInstance() {
- return INSTANCE;
+ public ConfiguredPrimitiveBackupMethod(String backupFileName, String levelPath, String backupSavePath) {
+ this.backupFileName = backupFileName;
+ this.levelPath = levelPath;
+ this.backupSavePath = backupSavePath;
}
@Deprecated
@@ -32,10 +36,9 @@ public class PrimitiveBackupMethod implements BackupMethod {
}
@Override
- public PrimitiveBackupFeedback backup(String customBackupName, String levelPath, String backupSavePath) throws IOException {
-// String backupFileName = getBackupFileName(LocalDateTime.now(),backupName);
- String backupFileName = new PrimitiveBackupFileNameEncoder().encode(customBackupName, LocalDateTime.now());
+ public PrimitiveBackupFeedback backup() throws IOException {
try {
+ String customBackupName = new PrimitiveBackupFileNameEncoder().decode(backupFileName).customName;
BackupMetadata backupMetadata = new BackupMetadata(System.currentTimeMillis(), customBackupName);
PrintUtil.info(String.format("zip(srcPath=%s, destPath=%s)", levelPath, backupSavePath));
PrintUtil.info("Compressing level ...");
@@ -50,10 +53,10 @@ public class PrimitiveBackupMethod implements BackupMethod {
}
@Override
- public boolean restore(String backupFileName, String levelDirectory, String backupSaveDirectory) throws IOException {
+ public boolean restore() throws IOException {
// Delete old level
PrintUtil.info("Server stopped. Deleting old level ...");
- File levelDirFile = new File(levelDirectory);
+ File levelDirFile = new File(levelPath);
long startTime = System.currentTimeMillis();
int failedCounter = 0;
@@ -80,7 +83,7 @@ public class PrimitiveBackupMethod implements BackupMethod {
// TODO: Refactor this to the concrete BackupMethod.
// Decompress archive
PrintUtil.info("Decompressing archived level ...");
- ZipUtil.unzip(Paths.get(backupSaveDirectory, backupFileName).toString(), levelDirectory, false);
+ ZipUtil.unzip(Paths.get(backupSavePath, backupFileName).toString(), levelPath, false);
long endTime = System.currentTimeMillis();
PrintUtil.info(String.format("Restore complete! (%.2fs) Please restart the server manually.", (endTime - startTime) / 1000.0));
PrintUtil.info("If you want to restart automatically after restoring, please check the manual at: https://github.com/keuin/KBackup-Fabric/blob/master/README.md");
diff --git a/src/main/java/com/keuin/kbackupfabric/operation/backup/method/IncrementalBackupMethod.java b/src/main/java/com/keuin/kbackupfabric/operation/backup/method/IncrementalBackupMethod.java
deleted file mode 100644
index 25e5731..0000000
--- a/src/main/java/com/keuin/kbackupfabric/operation/backup/method/IncrementalBackupMethod.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.keuin.kbackupfabric.operation.backup.method;
-
-import com.keuin.kbackupfabric.operation.backup.feedback.IncrementalBackupFeedback;
-
-import java.io.IOException;
-
-public class IncrementalBackupMethod implements BackupMethod {
- @Override
- public IncrementalBackupFeedback backup(String customBackupName, String levelPath, String backupSaveDirectory) throws IOException {
- return null;
- }
-
- @Override
- public boolean restore(String backupName, String levelPath, String backupSaveDirectory) throws IOException {
- return false;
- }
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionFactory.java b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionFactory.java
index ac87883..627cb5c 100644
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionFactory.java
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionFactory.java
@@ -15,7 +15,7 @@ import java.util.*;
* identifiers. Usually, identifier is the combination of hash and other short information (such as size and another hash).
* The identifier should use hashes that are strong enough, to prevent possible collisions.
*/
-public class ObjectCollectionFactory <T extends ObjectIdentifier> {
+public class ObjectCollectionFactory<T extends ObjectIdentifier> {
private final FileIdentifierProvider<T> identifierFactory;
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/name/IncrementalBackupFileNameEncoder.java b/src/main/java/com/keuin/kbackupfabric/util/backup/name/IncrementalBackupFileNameEncoder.java
index ae54930..a0d4128 100644
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/name/IncrementalBackupFileNameEncoder.java
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/name/IncrementalBackupFileNameEncoder.java
@@ -9,6 +9,10 @@ public class IncrementalBackupFileNameEncoder implements BackupFileNameEncoder {
private static final String backupFileNamePrefix = "incremental-";
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss");
+ // TODO: make this private and use singleton pattern
+ public IncrementalBackupFileNameEncoder() {
+ }
+
@Override
public String encode(String customName, LocalDateTime time) {
if (!isValidCustomName(customName))