summaryrefslogtreecommitdiff
path: root/src/main/java/com/keuin/kbackupfabric/util/backup
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/keuin/kbackupfabric/util/backup')
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/BackupFilesystemUtil.java82
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/BackupNameSuggestionProvider.java77
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/BackupNameTimeFormatter.java32
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/BackupType.java21
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/builder/BackupFileNameBuilder.java25
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/builder/ObjectTreeBackupFileNameBuilder.java20
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/builder/PrimitiveZipBackupFileNameBuilder.java22
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/formatter/BackupFileNameFormatter.java32
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/formatter/ObjectTreeBackupFileNameFormatter.java47
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/formatter/PrimitiveZipBackupFileNameFormatter.java46
10 files changed, 404 insertions, 0 deletions
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/BackupFilesystemUtil.java b/src/main/java/com/keuin/kbackupfabric/util/backup/BackupFilesystemUtil.java
new file mode 100644
index 0000000..54c2f58
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/BackupFilesystemUtil.java
@@ -0,0 +1,82 @@
+package com.keuin.kbackupfabric.util.backup;
+
+import com.keuin.kbackupfabric.util.ReflectionUtils;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.world.ThreadedAnvilChunkStorage;
+import net.minecraft.world.World;
+
+import java.io.File;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Functions deal with file name, directory name about Minecraft saves.
+ */
+public final class BackupFilesystemUtil {
+
+ private static final String backupSaveDirectoryName = "backups";
+ private static final String backupFileNamePrefix = "kbackup-";
+
+ public static String getBackupFileNamePrefix() {
+ return backupFileNamePrefix;
+ }
+
+ @Deprecated
+ public static String getBackupFileName(String backupName) {
+ return backupFileNamePrefix + backupName + ".zip";
+ }
+
+ @Deprecated
+ public static String getBackupName(String backupFileName) {
+ try {
+ if (backupFileName.matches(backupFileNamePrefix + ".+\\.zip"))
+ return backupFileName.substring(backupFileNamePrefix.length(), backupFileName.length() - 4);
+ } catch (IndexOutOfBoundsException ignored) {
+ }
+ return backupFileName;
+ }
+
+ public static boolean isBackupNameValid(String backupName, MinecraftServer server) {
+ File backupFile = new File(getBackupSaveDirectory(server), getBackupFileName(backupName));
+ return backupFile.isFile();
+ }
+
+ public static File getBackupSaveDirectory(MinecraftServer server) {
+ return new File(server.getRunDirectory(), backupSaveDirectoryName);
+ }
+
+ public static String getLevelPath(MinecraftServer server) {
+ return (new File(server.getRunDirectory(), server.getLevelName())).getAbsolutePath();
+ }
+
+ public static String getWorldDirectoryName(World world) throws NoSuchFieldException, IllegalAccessException {
+ File saveDir;
+ ThreadedAnvilChunkStorage threadedAnvilChunkStorage = (ThreadedAnvilChunkStorage) ReflectionUtils.getPrivateField(world.getChunkManager(), "threadedAnvilChunkStorage");
+ saveDir = (File) ReflectionUtils.getPrivateField(threadedAnvilChunkStorage, "saveDir");
+ return saveDir.getName();
+ }
+
+ @Deprecated
+ public static long getBackupTimeFromBackupFileName(String backupFileName) {
+ Matcher matcher = Pattern.compile("[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2}").matcher(backupFileName);
+ if (matcher.find()) {
+ String timeString = matcher.group(0);
+ long timeStamp = BackupNameTimeFormatter.timeStringToEpochSeconds(timeString);
+ System.out.println(backupFileName + " -> " + timeStamp);
+ return timeStamp;
+ } else {
+ System.err.println("Failed to extract time from " + backupFileName);
+ }
+ return -1;
+ }
+
+ public static String humanFileSize(long size) {
+ double fileSize = size * 1.0 / 1024 / 1024; // Default unit is MB
+ if (fileSize > 1000)
+ //msgInfo(context, String.format("File size: %.2fGB", fileSize / 1024));
+ return String.format("%.2fGB", fileSize / 1024);
+ else
+ //msgInfo(context, String.format("File size: %.2fMB", fileSize));
+ return String.format("%.2fMB", fileSize);
+ }
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/BackupNameSuggestionProvider.java b/src/main/java/com/keuin/kbackupfabric/util/backup/BackupNameSuggestionProvider.java
new file mode 100644
index 0000000..4639e99
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/BackupNameSuggestionProvider.java
@@ -0,0 +1,77 @@
+package com.keuin.kbackupfabric.util.backup;
+
+import com.mojang.brigadier.suggestion.SuggestionProvider;
+import com.mojang.brigadier.suggestion.Suggestions;
+import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import net.minecraft.server.command.ServerCommandSource;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.CompletableFuture;
+
+public class BackupNameSuggestionProvider {
+
+ private static final List<String> candidateCacheList = new ArrayList<>();
+ private static final Object syncSetDirectory = new Object();
+ private static final Object syncCache = new Object();
+ private static final long CACHE_TTL = 8000;
+ private static String backupSaveDirectory;
+ private static long cacheUpdateTime = 0;
+
+ public static void setBackupSaveDirectory(String backupSaveDirectory) {
+ synchronized (syncSetDirectory) {
+ BackupNameSuggestionProvider.backupSaveDirectory = backupSaveDirectory;
+ }
+ // Immediately perform an update
+ updateCandidateList();
+ }
+
+ public static void updateCandidateList() {
+ synchronized (syncCache) {
+ try {
+ File file = new File(backupSaveDirectory);
+ candidateCacheList.clear();
+ File[] files = file.listFiles();
+ if (files == null)
+ return;
+ for (File f : files)
+ candidateCacheList.add(BackupFilesystemUtil.getBackupName(f.getName()));
+ cacheUpdateTime = System.currentTimeMillis();
+ } catch (NullPointerException ignored) {
+ }
+ }
+ }
+
+// private static void updateCandidateList(Collection<String> stringCollection) {
+// candidateList.clear();
+// candidateList.addAll(stringCollection);
+// }
+
+ public static SuggestionProvider<ServerCommandSource> getProvider() {
+ return (context, builder) -> getCompletableFuture(builder);
+ }
+
+ private static CompletableFuture<Suggestions> getCompletableFuture(SuggestionsBuilder builder) {
+ if (isCacheExpired())
+ updateCandidateList();
+ String remaining = builder.getRemaining().toLowerCase(Locale.ROOT);
+ synchronized (syncCache) {
+ if (candidateCacheList.isEmpty()) { // If the list is empty then return no suggestions
+ return Suggestions.empty(); // No suggestions
+ }
+
+ for (String string : candidateCacheList) { // Iterate through the supplied list
+ if (string.toLowerCase(Locale.ROOT).startsWith(remaining)) {
+ builder.suggest(string); // Add every single entry to suggestions list.
+ }
+ }
+ }
+ return builder.buildFuture(); // Create the CompletableFuture containing all the suggestions
+ }
+
+ private static boolean isCacheExpired() {
+ return System.currentTimeMillis() - cacheUpdateTime > CACHE_TTL || cacheUpdateTime == 0;
+ }
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/BackupNameTimeFormatter.java b/src/main/java/com/keuin/kbackupfabric/util/backup/BackupNameTimeFormatter.java
new file mode 100644
index 0000000..3811ae8
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/BackupNameTimeFormatter.java
@@ -0,0 +1,32 @@
+package com.keuin.kbackupfabric.util.backup;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+
+public class BackupNameTimeFormatter {
+ private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss");
+
+ @Deprecated
+ public static String getTimeString() {
+ return LocalDateTime.now().format(formatter);
+ }
+
+ public static String localDateTimeToString(LocalDateTime localDateTime) {
+ return localDateTime.format(formatter);
+ }
+
+ @Deprecated
+ public static long timeStringToEpochSeconds(String timeString) {
+ ZoneId systemZone = ZoneId.systemDefault(); // my timezone
+ LocalDateTime localDateTime = LocalDateTime.parse(timeString, formatter);
+ ZoneOffset currentOffsetForMyZone = systemZone.getRules().getOffset(localDateTime);
+ return localDateTime.toEpochSecond(currentOffsetForMyZone);
+ }
+
+ public static LocalDateTime timeStringToLocalDateTime(String timeString) {
+ return LocalDateTime.parse(timeString,formatter);
+ }
+
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/BackupType.java b/src/main/java/com/keuin/kbackupfabric/util/backup/BackupType.java
new file mode 100644
index 0000000..95a32ae
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/BackupType.java
@@ -0,0 +1,21 @@
+package com.keuin.kbackupfabric.util.backup;
+
+/**
+ * Representing the backup type.
+ * Should only be used in BackupFileNameBuilder and BackupFileNameFormatter
+ */
+public enum BackupType {
+
+ PRIMITIVE_ZIP_BACKUP("Primitive Zip Backup"),
+ OBJECT_TREE_BACKUP("Object Tree Backup");
+
+ private final String name;
+ BackupType(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/builder/BackupFileNameBuilder.java b/src/main/java/com/keuin/kbackupfabric/util/backup/builder/BackupFileNameBuilder.java
new file mode 100644
index 0000000..16c598b
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/builder/BackupFileNameBuilder.java
@@ -0,0 +1,25 @@
+package com.keuin.kbackupfabric.util.backup.builder;
+
+import com.sun.istack.internal.NotNull;
+
+import java.time.LocalDateTime;
+
+public interface BackupFileNameBuilder {
+
+ static BackupFileNameBuilder primitiveZipBackup() {
+ return PrimitiveZipBackupFileNameBuilder.getInstance();
+ }
+
+ static BackupFileNameBuilder objectTreeBackup() {
+ return ObjectTreeBackupFileNameBuilder.getInstance();
+ }
+
+ /**
+ * Build a backup file name based on given information.
+ * @param time when the backup was created.
+ * @param backupName the custom name of this backup. Note that this should be a valid file name in current file system.
+ * @return the backup file name string.
+ */
+ String build(@NotNull LocalDateTime time, @NotNull String backupName);
+
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/builder/ObjectTreeBackupFileNameBuilder.java b/src/main/java/com/keuin/kbackupfabric/util/backup/builder/ObjectTreeBackupFileNameBuilder.java
new file mode 100644
index 0000000..3c15741
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/builder/ObjectTreeBackupFileNameBuilder.java
@@ -0,0 +1,20 @@
+package com.keuin.kbackupfabric.util.backup.builder;
+
+import com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil;
+import com.keuin.kbackupfabric.util.backup.BackupNameTimeFormatter;
+
+import java.time.LocalDateTime;
+
+public class ObjectTreeBackupFileNameBuilder implements BackupFileNameBuilder {
+ private static final ObjectTreeBackupFileNameBuilder instance = new ObjectTreeBackupFileNameBuilder();
+
+ public static ObjectTreeBackupFileNameBuilder getInstance() {
+ return instance;
+ }
+
+ @Override
+ public String build(LocalDateTime time, String backupName) {
+ String timeString = BackupNameTimeFormatter.localDateTimeToString(time);
+ return String.format("%s%s_%s%s", BackupFilesystemUtil.getBackupFileNamePrefix(),timeString,backupName,".json");
+ }
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/builder/PrimitiveZipBackupFileNameBuilder.java b/src/main/java/com/keuin/kbackupfabric/util/backup/builder/PrimitiveZipBackupFileNameBuilder.java
new file mode 100644
index 0000000..f910c37
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/builder/PrimitiveZipBackupFileNameBuilder.java
@@ -0,0 +1,22 @@
+package com.keuin.kbackupfabric.util.backup.builder;
+
+import com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil;
+import com.keuin.kbackupfabric.util.backup.BackupNameTimeFormatter;
+
+import java.time.LocalDateTime;
+
+public class PrimitiveZipBackupFileNameBuilder implements BackupFileNameBuilder {
+
+ private static final PrimitiveZipBackupFileNameBuilder instance = new PrimitiveZipBackupFileNameBuilder();
+
+ public static PrimitiveZipBackupFileNameBuilder getInstance() {
+ return instance;
+ }
+
+ @Override
+ public String build(LocalDateTime time, String backupName) {
+ String timeString = BackupNameTimeFormatter.localDateTimeToString(time);
+ return String.format("%s%s_%s%s", BackupFilesystemUtil.getBackupFileNamePrefix(),timeString,backupName,".zip");
+ }
+
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/BackupFileNameFormatter.java b/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/BackupFileNameFormatter.java
new file mode 100644
index 0000000..eae3639
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/BackupFileNameFormatter.java
@@ -0,0 +1,32 @@
+package com.keuin.kbackupfabric.util.backup.formatter;
+
+import com.keuin.kbackupfabric.util.backup.BackupNameTimeFormatter;
+import com.sun.istack.internal.NotNull;
+
+import java.time.LocalDateTime;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public interface BackupFileNameFormatter {
+
+ BackupFileName format(@NotNull String fileName);
+
+ class BackupFileName {
+ public final LocalDateTime time;
+ public final String name;
+
+ public BackupFileName(LocalDateTime time, String name) {
+ this.time = time;
+ this.name = name;
+ }
+ }
+
+ static BackupFileNameFormatter objectTreeBackup() {
+ return ObjectTreeBackupFileNameFormatter.getInstance();
+ }
+
+ static BackupFileNameFormatter primitiveZipBackup() {
+ return PrimitiveZipBackupFileNameFormatter.getInstance();
+ }
+
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/ObjectTreeBackupFileNameFormatter.java b/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/ObjectTreeBackupFileNameFormatter.java
new file mode 100644
index 0000000..e5503a9
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/ObjectTreeBackupFileNameFormatter.java
@@ -0,0 +1,47 @@
+package com.keuin.kbackupfabric.util.backup.formatter;
+
+import com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil;
+import com.keuin.kbackupfabric.util.backup.BackupNameTimeFormatter;
+import com.sun.istack.internal.NotNull;
+import com.sun.istack.internal.Nullable;
+import org.spongepowered.asm.mixin.Overwrite;
+
+import java.time.LocalDateTime;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ObjectTreeBackupFileNameFormatter implements BackupFileNameFormatter {
+
+ private static final ObjectTreeBackupFileNameFormatter instance = new ObjectTreeBackupFileNameFormatter();
+
+ public static ObjectTreeBackupFileNameFormatter getInstance() {
+ return instance;
+ }
+
+ @Override
+ public BackupFileNameFormatter.BackupFileName format(@NotNull String fileName) {
+ LocalDateTime time = getTime(fileName);
+ String name = getBackupName(fileName);
+ return new BackupFileNameFormatter.BackupFileName(time,name);
+ }
+
+ @Nullable
+ private LocalDateTime getTime(String fileName) {
+ Matcher matcher = Pattern.compile("[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2}").matcher(fileName);
+ if (matcher.find()) {
+ String timeString = matcher.group(0);
+ return BackupNameTimeFormatter.timeStringToLocalDateTime(timeString);
+ }
+ return null;
+ }
+
+ private String getBackupName(String backupFileName) {
+ try {
+ if (backupFileName.matches(BackupFilesystemUtil.getBackupFileNamePrefix() + ".+\\.json"))
+ return backupFileName.substring(BackupFilesystemUtil.getBackupFileNamePrefix().length(), backupFileName.length() - 4);
+ } catch (IndexOutOfBoundsException ignored) {
+ }
+ return backupFileName;
+ }
+
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/PrimitiveZipBackupFileNameFormatter.java b/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/PrimitiveZipBackupFileNameFormatter.java
new file mode 100644
index 0000000..40450eb
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/formatter/PrimitiveZipBackupFileNameFormatter.java
@@ -0,0 +1,46 @@
+package com.keuin.kbackupfabric.util.backup.formatter;
+
+import com.keuin.kbackupfabric.util.backup.BackupFilesystemUtil;
+import com.keuin.kbackupfabric.util.backup.BackupNameTimeFormatter;
+import com.sun.istack.internal.NotNull;
+import com.sun.istack.internal.Nullable;
+
+import java.time.LocalDateTime;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class PrimitiveZipBackupFileNameFormatter implements BackupFileNameFormatter {
+
+ private static final PrimitiveZipBackupFileNameFormatter instance = new PrimitiveZipBackupFileNameFormatter();
+
+ public static PrimitiveZipBackupFileNameFormatter getInstance() {
+ return instance;
+ }
+
+ @Override
+ public BackupFileNameFormatter.BackupFileName format(@NotNull String fileName) {
+ LocalDateTime time = getTime(fileName);
+ String name = getBackupName(fileName);
+ return new BackupFileNameFormatter.BackupFileName(time,name);
+ }
+
+ @Nullable
+ private LocalDateTime getTime(String fileName) {
+ Matcher matcher = Pattern.compile("[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2}").matcher(fileName);
+ if (matcher.find()) {
+ String timeString = matcher.group(0);
+ return BackupNameTimeFormatter.timeStringToLocalDateTime(timeString);
+ }
+ return null;
+ }
+
+ private String getBackupName(String backupFileName) {
+ try {
+ if (backupFileName.matches(BackupFilesystemUtil.getBackupFileNamePrefix() + ".+\\.zip"))
+ return backupFileName.substring(BackupFilesystemUtil.getBackupFileNamePrefix().length(), backupFileName.length() - 4);
+ } catch (IndexOutOfBoundsException ignored) {
+ }
+ return backupFileName;
+ }
+
+}