pt III, slowly moving to the new file handling api (File -> Path)
parent
a85db99d82
commit
b4597f6f1f
|
@ -20,7 +20,7 @@ package net.szum123321.textile_backup;
|
||||||
|
|
||||||
import net.szum123321.textile_backup.core.restore.AwaitThread;
|
import net.szum123321.textile_backup.core.restore.AwaitThread;
|
||||||
|
|
||||||
import java.io.File;
|
import java.nio.file.Path;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
@ -35,6 +35,6 @@ public class Statics {
|
||||||
public static final AtomicBoolean globalShutdownBackupFlag = new AtomicBoolean(true);
|
public static final AtomicBoolean globalShutdownBackupFlag = new AtomicBoolean(true);
|
||||||
public static boolean disableWatchdog = false;
|
public static boolean disableWatchdog = false;
|
||||||
public static AwaitThread restoreAwaitThread = null;
|
public static AwaitThread restoreAwaitThread = null;
|
||||||
public static Optional<File> untouchableFile = Optional.empty();
|
public static Optional<Path> untouchableFile = Optional.empty();
|
||||||
public static boolean disableTMPFiles = false;
|
public static boolean disableTMPFiles = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ package net.szum123321.textile_backup.commands.manage;
|
||||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
|
||||||
import net.minecraft.server.command.CommandManager;
|
import net.minecraft.server.command.CommandManager;
|
||||||
import net.minecraft.server.command.ServerCommandSource;
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
import net.szum123321.textile_backup.TextileBackup;
|
import net.szum123321.textile_backup.TextileBackup;
|
||||||
|
@ -31,11 +30,13 @@ import net.szum123321.textile_backup.Statics;
|
||||||
import net.szum123321.textile_backup.commands.FileSuggestionProvider;
|
import net.szum123321.textile_backup.commands.FileSuggestionProvider;
|
||||||
import net.szum123321.textile_backup.core.Utilities;
|
import net.szum123321.textile_backup.core.Utilities;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeParseException;
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class DeleteCommand {
|
public class DeleteCommand {
|
||||||
private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME);
|
private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME);
|
||||||
|
@ -57,28 +58,28 @@ public class DeleteCommand {
|
||||||
throw CommandExceptions.DATE_TIME_PARSE_COMMAND_EXCEPTION_TYPE.create(e);
|
throw CommandExceptions.DATE_TIME_PARSE_COMMAND_EXCEPTION_TYPE.create(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
File root = Utilities.getBackupRootPath(Utilities.getLevelName(source.getServer()));
|
Path root = Utilities.getBackupRootPath(Utilities.getLevelName(source.getServer()));
|
||||||
|
|
||||||
Optional<File> optionalFile = Arrays.stream(root.listFiles())
|
try (Stream<Path> stream = Files.list(root)) {
|
||||||
.filter(Utilities::isValidBackup)
|
stream.filter(Utilities::isValidBackup)
|
||||||
.filter(file -> Utilities.getFileCreationTime(file).orElse(LocalDateTime.MIN).equals(dateTime))
|
.filter(file -> Utilities.getFileCreationTime(file).orElse(LocalDateTime.MIN).equals(dateTime))
|
||||||
.findFirst();
|
.findFirst().ifPresent(file -> {
|
||||||
|
if(Statics.untouchableFile.isEmpty() || !Statics.untouchableFile.get().equals(file)) {
|
||||||
|
try {
|
||||||
|
Files.delete(file);
|
||||||
|
log.sendInfo(source, "File {} successfully deleted!", file);
|
||||||
|
|
||||||
if(optionalFile.isPresent()) {
|
if(source.isExecutedByPlayer())
|
||||||
if(Statics.untouchableFile.isEmpty() || !Statics.untouchableFile.get().equals(optionalFile.get())) {
|
log.info("Player {} deleted {}.", source.getPlayer().getName(), file);
|
||||||
if(optionalFile.get().delete()) {
|
} catch (IOException e) {
|
||||||
log.sendInfo(source, "File {} successfully deleted!", optionalFile.get().getName());
|
log.sendError(source, "Something went wrong while deleting file!");
|
||||||
|
}
|
||||||
if(source.getEntity() instanceof PlayerEntity)
|
} else {
|
||||||
log.info("Player {} deleted {}.", source.getPlayer().getName(), optionalFile.get().getName());
|
log.sendError(source, "Couldn't delete the file because it's being restored right now.");
|
||||||
} else {
|
log.sendHint(source, "If you want to abort restoration then use: /backup killR");
|
||||||
log.sendError(source, "Something went wrong while deleting file!");
|
}
|
||||||
}
|
});
|
||||||
} else {
|
} catch (IOException ignored) {
|
||||||
log.sendError(source, "Couldn't delete the file because it's being restored right now.");
|
|
||||||
log.sendHint(source, "If you want to abort restoration then use: /backup killR");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.sendError(source, "Couldn't find file by this name.");
|
log.sendError(source, "Couldn't find file by this name.");
|
||||||
log.sendHint(source, "Maybe try /backup list");
|
log.sendHint(source, "Maybe try /backup list");
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ public class RestoreBackupCommand {
|
||||||
Optional<RestoreHelper.RestoreableFile> backupFile = RestoreHelper.findFileAndLockIfPresent(dateTime, source.getServer());
|
Optional<RestoreHelper.RestoreableFile> backupFile = RestoreHelper.findFileAndLockIfPresent(dateTime, source.getServer());
|
||||||
|
|
||||||
if(backupFile.isPresent()) {
|
if(backupFile.isPresent()) {
|
||||||
log.info("Found file to restore {}", backupFile.get().getFile().getName());
|
log.info("Found file to restore {}", backupFile.get().getFile().getFileName().toString());
|
||||||
} else {
|
} else {
|
||||||
log.sendInfo(source, "No file created on {} was found!", dateTime.format(Statics.defaultDateTimeFormatter));
|
log.sendInfo(source, "No file created on {} was found!", dateTime.format(Statics.defaultDateTimeFormatter));
|
||||||
|
|
||||||
|
|
|
@ -60,19 +60,22 @@ public class Utilities {
|
||||||
return ((MinecraftServerSessionAccessor)server).getSession().getDirectoryName();
|
return ((MinecraftServerSessionAccessor)server).getSession().getDirectoryName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static File getWorldFolder(MinecraftServer server) {
|
public static Path getWorldFolder(MinecraftServer server) {
|
||||||
return ((MinecraftServerSessionAccessor)server)
|
return ((MinecraftServerSessionAccessor)server)
|
||||||
.getSession()
|
.getSession()
|
||||||
.getWorldDirectory(World.OVERWORLD)
|
.getWorldDirectory(World.OVERWORLD);
|
||||||
.toFile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static File getBackupRootPath(String worldName) {
|
public static Path getBackupRootPath(String worldName) {
|
||||||
File path = new File(config.get().path).getAbsoluteFile();
|
Path path = Path.of(config.get().path).toAbsolutePath();
|
||||||
|
|
||||||
if (config.get().perWorldBackup) path = path.toPath().resolve(worldName).toFile();
|
if (config.get().perWorldBackup) path = path.resolve(worldName);
|
||||||
|
|
||||||
if (!path.exists()) path.mkdirs();
|
try {
|
||||||
|
Files.createDirectories(path);
|
||||||
|
} catch (IOException e) {
|
||||||
|
//I REALLY shouldn't be handling this here
|
||||||
|
}
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
@ -81,7 +84,7 @@ public class Utilities {
|
||||||
boolean flag = false;
|
boolean flag = false;
|
||||||
Path tmp_dir = Path.of(System.getProperty("java.io.tmpdir"));
|
Path tmp_dir = Path.of(System.getProperty("java.io.tmpdir"));
|
||||||
if(
|
if(
|
||||||
FileUtils.sizeOfDirectory(Utilities.getWorldFolder(server)) >=
|
FileUtils.sizeOfDirectory(Utilities.getWorldFolder(server).toFile()) >=
|
||||||
tmp_dir.toFile().getUsableSpace()
|
tmp_dir.toFile().getUsableSpace()
|
||||||
) {
|
) {
|
||||||
log.error("Not enough space left in TMP directory! ({})", tmp_dir);
|
log.error("Not enough space left in TMP directory! ({})", tmp_dir);
|
||||||
|
@ -130,11 +133,11 @@ public class Utilities {
|
||||||
.findAny();
|
.findAny();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<ConfigPOJO.ArchiveFormat> getArchiveExtension(File f) {
|
public static Optional<ConfigPOJO.ArchiveFormat> getArchiveExtension(Path f) {
|
||||||
return getArchiveExtension(f.getName());
|
return getArchiveExtension(f.getFileName().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<LocalDateTime> getFileCreationTime(File file) {
|
public static Optional<LocalDateTime> getFileCreationTime(Path file) {
|
||||||
LocalDateTime creationTime = null;
|
LocalDateTime creationTime = null;
|
||||||
|
|
||||||
if(getArchiveExtension(file).isPresent()) {
|
if(getArchiveExtension(file).isPresent()) {
|
||||||
|
@ -143,7 +146,7 @@ public class Utilities {
|
||||||
try {
|
try {
|
||||||
creationTime = LocalDateTime.from(
|
creationTime = LocalDateTime.from(
|
||||||
Utilities.getDateTimeFormatter().parse(
|
Utilities.getDateTimeFormatter().parse(
|
||||||
file.getName().split(fileExtension)[0].split("#")[0]
|
file.getFileName().toString().split(fileExtension)[0].split("#")[0]
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
|
@ -152,7 +155,7 @@ public class Utilities {
|
||||||
try {
|
try {
|
||||||
creationTime = LocalDateTime.from(
|
creationTime = LocalDateTime.from(
|
||||||
Utilities.getBackupDateTimeFormatter().parse(
|
Utilities.getBackupDateTimeFormatter().parse(
|
||||||
file.getName().split(fileExtension)[0].split("#")[0]
|
file.getFileName().toString().split(fileExtension)[0].split("#")[0]
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} catch (Exception ignored2){}
|
} catch (Exception ignored2){}
|
||||||
|
@ -160,7 +163,7 @@ public class Utilities {
|
||||||
|
|
||||||
if(creationTime == null) {
|
if(creationTime == null) {
|
||||||
try {
|
try {
|
||||||
FileTime fileTime = (FileTime) Files.getAttribute(file.toPath(), "creationTime");
|
FileTime fileTime = (FileTime) Files.getAttribute(file, "creationTime");
|
||||||
creationTime = LocalDateTime.ofInstant(fileTime.toInstant(), ZoneOffset.systemDefault());
|
creationTime = LocalDateTime.ofInstant(fileTime.toInstant(), ZoneOffset.systemDefault());
|
||||||
} catch (IOException ignored3) {}
|
} catch (IOException ignored3) {}
|
||||||
}
|
}
|
||||||
|
@ -169,7 +172,7 @@ public class Utilities {
|
||||||
return Optional.ofNullable(creationTime);
|
return Optional.ofNullable(creationTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isValidBackup(File f) {
|
public static boolean isValidBackup(Path f) {
|
||||||
return getArchiveExtension(f).isPresent() && getFileCreationTime(f).isPresent() && isFileOk(f);
|
return getArchiveExtension(f).isPresent() && getFileCreationTime(f).isPresent() && isFileOk(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,6 +180,10 @@ public class Utilities {
|
||||||
return f.exists() && f.isFile();
|
return f.exists() && f.isFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isFileOk(Path f) {
|
||||||
|
return Files.exists(f) && Files.isRegularFile(f);
|
||||||
|
}
|
||||||
|
|
||||||
public static DateTimeFormatter getDateTimeFormatter() {
|
public static DateTimeFormatter getDateTimeFormatter() {
|
||||||
return DateTimeFormatter.ofPattern(config.get().dateTimeFormat);
|
return DateTimeFormatter.ofPattern(config.get().dateTimeFormat);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,13 @@ import net.szum123321.textile_backup.config.ConfigHelper;
|
||||||
import net.szum123321.textile_backup.core.Utilities;
|
import net.szum123321.textile_backup.core.Utilities;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class BackupHelper {
|
public class BackupHelper {
|
||||||
private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME);
|
private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME);
|
||||||
|
@ -77,52 +79,76 @@ public class BackupHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int executeFileLimit(ServerCommandSource ctx, String worldName) {
|
public static int executeFileLimit(ServerCommandSource ctx, String worldName) {
|
||||||
File root = Utilities.getBackupRootPath(worldName);
|
Path root = Utilities.getBackupRootPath(worldName);
|
||||||
int deletedFiles = 0;
|
int deletedFiles = 0;
|
||||||
|
|
||||||
if (root.isDirectory() && root.exists() && root.listFiles() != null) {
|
|
||||||
|
if (Files.isDirectory(root) && Files.exists(root) && !isEmpty(root)) {
|
||||||
if (config.get().maxAge > 0) { // delete files older that configured
|
if (config.get().maxAge > 0) { // delete files older that configured
|
||||||
final LocalDateTime now = LocalDateTime.now();
|
final LocalDateTime now = LocalDateTime.now();
|
||||||
|
|
||||||
deletedFiles += Arrays.stream(root.listFiles())
|
try(Stream<Path> stream = Files.list(root)) {
|
||||||
.filter(Utilities::isValidBackup)// We check if we can get file's creation date so that the next line won't throw an exception
|
deletedFiles += stream
|
||||||
.filter(f -> now.toEpochSecond(ZoneOffset.UTC) - Utilities.getFileCreationTime(f).get().toEpochSecond(ZoneOffset.UTC) > config.get().maxAge)
|
.filter(Utilities::isValidBackup)// We check if we can get restoreableFile's creation date so that the next line won't throw an exception
|
||||||
.map(f -> deleteFile(f, ctx))
|
.filter(f -> now.toEpochSecond(ZoneOffset.UTC) - Utilities.getFileCreationTime(f).get().toEpochSecond(ZoneOffset.UTC) > config.get().maxAge)
|
||||||
.filter(b -> b).count(); //a bit awkward
|
.map(f -> deleteFile(f, ctx))
|
||||||
|
.filter(b -> b).count(); //a bit awkward
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (config.get().backupsToKeep > 0 /*&& root.listFiles().length > config.get().backupsToKeep*/) {
|
||||||
|
try(Stream<Path> stream = Files.list(root)) {
|
||||||
|
deletedFiles += stream
|
||||||
|
.filter(Utilities::isValidBackup)
|
||||||
|
.sorted(Comparator.comparing(f -> Utilities.getFileCreationTime((Path) f).get()).reversed())
|
||||||
|
.skip(config.get().backupsToKeep)
|
||||||
|
.map(f -> deleteFile(f, ctx))
|
||||||
|
.filter(b -> b).count();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.get().backupsToKeep > 0 && root.listFiles().length > config.get().backupsToKeep) {
|
//It is fucking quadratic!
|
||||||
deletedFiles += Arrays.stream(root.listFiles())
|
/*if (config.get().maxSize > 0 && FileUtils.sizeOfDirectory(root) / 1024 > config.get().maxSize) {
|
||||||
.filter(Utilities::isValidBackup)
|
|
||||||
.sorted(Comparator.comparing(f -> Utilities.getFileCreationTime((File) f).get()).reversed())
|
|
||||||
.skip(config.get().backupsToKeep)
|
|
||||||
.map(f -> deleteFile(f, ctx))
|
|
||||||
.filter(b -> b).count();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.get().maxSize > 0 && FileUtils.sizeOfDirectory(root) / 1024 > config.get().maxSize) {
|
|
||||||
deletedFiles += Arrays.stream(root.listFiles())
|
deletedFiles += Arrays.stream(root.listFiles())
|
||||||
.filter(Utilities::isValidBackup)
|
.filter(Utilities::isValidBackup)
|
||||||
.sorted(Comparator.comparing(f -> Utilities.getFileCreationTime(f).get()))
|
.sorted(Comparator.comparing(f -> Utilities.getFileCreationTime(f).get()))
|
||||||
.takeWhile(f -> FileUtils.sizeOfDirectory(root) / 1024 > config.get().maxSize)
|
.takeWhile(f -> FileUtils.sizeOfDirectory(root) / 1024 > config.get().maxSize)
|
||||||
.map(f -> deleteFile(f, ctx))
|
.map(f -> deleteFile(f, ctx))
|
||||||
.filter(b -> b).count();
|
.filter(b -> b).count();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
return deletedFiles;
|
return deletedFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean deleteFile(File f, ServerCommandSource ctx) {
|
private static boolean isEmpty(Path path) {
|
||||||
if(Statics.untouchableFile.isEmpty()|| !Statics.untouchableFile.get().equals(f)) {
|
if (Files.isDirectory(path)) {
|
||||||
if(f.delete()) {
|
try (Stream<Path> entries = Files.list(path)) {
|
||||||
log.sendInfoAL(ctx, "Deleting: {}", f.getName());
|
return entries.findFirst().isEmpty();
|
||||||
return true;
|
} catch (IOException e) {
|
||||||
} else {
|
return false;
|
||||||
log.sendErrorAL(ctx, "Something went wrong while deleting: {}.", f.getName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean deleteFile(Path f, ServerCommandSource ctx) {
|
||||||
|
if(Statics.untouchableFile.isEmpty()|| !Statics.untouchableFile.get().equals(f)) {
|
||||||
|
try {
|
||||||
|
Files.delete(f);
|
||||||
|
log.sendInfoAL(ctx, "Deleting: {}", f);
|
||||||
|
} catch (IOException e) {
|
||||||
|
if(ctx.isExecutedByPlayer()) log.sendError(ctx, "Something went wrong while deleting: {}.", f);
|
||||||
|
log.error("Something went wrong while deleting: {}.", f, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -56,13 +56,12 @@ public class MakeBackupRunnable implements Runnable {
|
||||||
|
|
||||||
log.sendInfoAL(context, "Starting backup");
|
log.sendInfoAL(context, "Starting backup");
|
||||||
|
|
||||||
Path world = Utilities.getWorldFolder(context.getServer()).toPath();
|
Path world = Utilities.getWorldFolder(context.getServer());
|
||||||
|
|
||||||
log.trace("Minecraft world is: {}", world);
|
log.trace("Minecraft world is: {}", world);
|
||||||
|
|
||||||
Path outFile = Utilities
|
Path outFile = Utilities
|
||||||
.getBackupRootPath(Utilities.getLevelName(context.getServer()))
|
.getBackupRootPath(Utilities.getLevelName(context.getServer()))
|
||||||
.toPath()
|
|
||||||
.resolve(getFileName());
|
.resolve(getFileName());
|
||||||
log.trace("Outfile is: {}", outFile);
|
log.trace("Outfile is: {}", outFile);
|
||||||
|
|
||||||
|
|
|
@ -21,43 +21,15 @@ package net.szum123321.textile_backup.core.restore;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.command.ServerCommandSource;
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
import net.minecraft.util.Util;
|
|
||||||
import net.szum123321.textile_backup.core.ActionInitiator;
|
import net.szum123321.textile_backup.core.ActionInitiator;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public record RestoreContext(RestoreHelper.RestoreableFile file,
|
public record RestoreContext(RestoreHelper.RestoreableFile restoreableFile,
|
||||||
MinecraftServer server,
|
MinecraftServer server,
|
||||||
@Nullable String comment,
|
@Nullable String comment,
|
||||||
ActionInitiator initiator,
|
ActionInitiator initiator,
|
||||||
ServerCommandSource commandSource) {
|
ServerCommandSource commandSource) {
|
||||||
|
|
||||||
public RestoreHelper.RestoreableFile getFile() {
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MinecraftServer getServer() {
|
|
||||||
return server;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public String getComment() {
|
|
||||||
return comment;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionInitiator getInitiator() {
|
|
||||||
return initiator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getInitiatorUUID() {
|
|
||||||
return initiator.equals(ActionInitiator.Player) && commandSource.getEntity() != null ? commandSource.getEntity().getUuid(): Util.NIL_UUID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServerCommandSource getCommandSource() {
|
|
||||||
return commandSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class Builder {
|
public static final class Builder {
|
||||||
private RestoreHelper.RestoreableFile file;
|
private RestoreHelper.RestoreableFile file;
|
||||||
private MinecraftServer server;
|
private MinecraftServer server;
|
||||||
|
|
|
@ -28,23 +28,31 @@ import net.szum123321.textile_backup.core.ActionInitiator;
|
||||||
import net.szum123321.textile_backup.core.Utilities;
|
import net.szum123321.textile_backup.core.Utilities;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class RestoreHelper {
|
public class RestoreHelper {
|
||||||
private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME);
|
private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME);
|
||||||
private final static ConfigHelper config = ConfigHelper.INSTANCE;
|
private final static ConfigHelper config = ConfigHelper.INSTANCE;
|
||||||
|
|
||||||
public static Optional<RestoreableFile> findFileAndLockIfPresent(LocalDateTime backupTime, MinecraftServer server) {
|
public static Optional<RestoreableFile> findFileAndLockIfPresent(LocalDateTime backupTime, MinecraftServer server) {
|
||||||
File root = Utilities.getBackupRootPath(Utilities.getLevelName(server));
|
Path root = Utilities.getBackupRootPath(Utilities.getLevelName(server));
|
||||||
|
|
||||||
Optional<RestoreableFile> optionalFile = Arrays.stream(root.listFiles())
|
Optional<RestoreableFile> optionalFile;
|
||||||
.map(RestoreableFile::newInstance)
|
try (Stream<Path> stream = Files.list(root)) {
|
||||||
.flatMap(Optional::stream)
|
optionalFile = stream
|
||||||
.filter(rf -> rf.getCreationTime().equals(backupTime))
|
.map(RestoreableFile::newInstance)
|
||||||
.findFirst();
|
.flatMap(Optional::stream)
|
||||||
|
.filter(rf -> rf.getCreationTime().equals(backupTime))
|
||||||
|
.findFirst();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
Statics.untouchableFile = optionalFile.map(RestoreableFile::getFile);
|
Statics.untouchableFile = optionalFile.map(RestoreableFile::getFile);
|
||||||
|
|
||||||
|
@ -52,8 +60,8 @@ public class RestoreHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AwaitThread create(RestoreContext ctx) {
|
public static AwaitThread create(RestoreContext ctx) {
|
||||||
if(ctx.getInitiator() == ActionInitiator.Player)
|
if(ctx.initiator() == ActionInitiator.Player)
|
||||||
log.info("Backup restoration was initiated by: {}", ctx.getCommandSource().getName());
|
log.info("Backup restoration was initiated by: {}", ctx.commandSource().getName());
|
||||||
else
|
else
|
||||||
log.info("Backup restoration was initiated form Server Console");
|
log.info("Backup restoration was initiated form Server Console");
|
||||||
|
|
||||||
|
@ -69,28 +77,32 @@ public class RestoreHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<RestoreableFile> getAvailableBackups(MinecraftServer server) {
|
public static List<RestoreableFile> getAvailableBackups(MinecraftServer server) {
|
||||||
File root = Utilities.getBackupRootPath(Utilities.getLevelName(server));
|
Path root = Utilities.getBackupRootPath(Utilities.getLevelName(server));
|
||||||
|
|
||||||
return Arrays.stream(root.listFiles())
|
try (Stream<Path> stream = Files.list(root)) {
|
||||||
.filter(Utilities::isValidBackup)
|
return stream.filter(Utilities::isValidBackup)
|
||||||
.map(RestoreableFile::newInstance)
|
.map(RestoreableFile::newInstance)
|
||||||
.flatMap(Optional::stream)
|
.flatMap(Optional::stream)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Error while listing available backups", e);
|
||||||
|
return new LinkedList<>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class RestoreableFile implements Comparable<RestoreableFile> {
|
public static class RestoreableFile implements Comparable<RestoreableFile> {
|
||||||
private final File file;
|
private final Path file;
|
||||||
private final ConfigPOJO.ArchiveFormat archiveFormat;
|
private final ConfigPOJO.ArchiveFormat archiveFormat;
|
||||||
private final LocalDateTime creationTime;
|
private final LocalDateTime creationTime;
|
||||||
private final String comment;
|
private final String comment;
|
||||||
|
|
||||||
private RestoreableFile(File file) throws NoSuchElementException {
|
private RestoreableFile(Path file) throws NoSuchElementException {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
archiveFormat = Utilities.getArchiveExtension(file).orElseThrow(() -> new NoSuchElementException("Couldn't get file extension!"));
|
archiveFormat = Utilities.getArchiveExtension(file).orElseThrow(() -> new NoSuchElementException("Couldn't get restoreableFile extension!"));
|
||||||
String extension = archiveFormat.getCompleteString();
|
String extension = archiveFormat.getCompleteString();
|
||||||
creationTime = Utilities.getFileCreationTime(file).orElseThrow(() -> new NoSuchElementException("Couldn't get file creation time!"));
|
creationTime = Utilities.getFileCreationTime(file).orElseThrow(() -> new NoSuchElementException("Couldn't get restoreableFile creation time!"));
|
||||||
|
|
||||||
final String filename = file.getName();
|
final String filename = file.getFileName().toString();
|
||||||
|
|
||||||
if(filename.split("#").length > 1) {
|
if(filename.split("#").length > 1) {
|
||||||
this.comment = filename.split("#")[1].split(extension)[0];
|
this.comment = filename.split("#")[1].split(extension)[0];
|
||||||
|
@ -99,7 +111,7 @@ public class RestoreHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<RestoreableFile> newInstance(File file) {
|
public static Optional<RestoreableFile> newInstance(Path file) {
|
||||||
try {
|
try {
|
||||||
return Optional.of(new RestoreableFile(file));
|
return Optional.of(new RestoreableFile(file));
|
||||||
} catch (NoSuchElementException ignored) {}
|
} catch (NoSuchElementException ignored) {}
|
||||||
|
@ -107,7 +119,7 @@ public class RestoreHelper {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getFile() {
|
public Path getFile() {
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue