It works! (At least now...)
parent
b81b7d27f8
commit
7c7c4c7493
|
@ -6,7 +6,7 @@ yarn_mappings=1.16.1+build.21
|
|||
loader_version=0.9.0+build.204
|
||||
|
||||
#Fabric api
|
||||
fabric_version=0.15.0+build.379-1.16.1
|
||||
fabric_version=0.16.2+build.385-1.16.1
|
||||
|
||||
# Mod Properties
|
||||
mod_version = 1.4.0
|
||||
|
|
|
@ -117,7 +117,7 @@ public class ConfigHandler {
|
|||
this.extension = extension;
|
||||
}
|
||||
|
||||
public String getExtension() {
|
||||
public String getString() {
|
||||
return extension;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,17 +26,16 @@ import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
|||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.szum123321.textile_backup.commands.BlacklistCommand;
|
||||
import net.szum123321.textile_backup.commands.CleanupCommand;
|
||||
import net.szum123321.textile_backup.commands.StartBackupCommand;
|
||||
import net.szum123321.textile_backup.commands.WhitelistCommand;
|
||||
import net.szum123321.textile_backup.core.BackupScheduler;
|
||||
import net.szum123321.textile_backup.commands.*;
|
||||
import net.szum123321.textile_backup.core.create.BackupScheduler;
|
||||
import net.szum123321.textile_backup.core.restore.RestoreHelper;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class TextileBackup implements ModInitializer {
|
||||
public static final String MOD_ID = "textile_backup";
|
||||
|
@ -46,6 +45,7 @@ public class TextileBackup implements ModInitializer {
|
|||
|
||||
public static final BackupScheduler scheduler = new BackupScheduler();
|
||||
public static ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||
public static final AtomicBoolean globalShutdownBackupFlag = new AtomicBoolean(true);
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
|
@ -85,6 +85,7 @@ public class TextileBackup implements ModInitializer {
|
|||
.then(CleanupCommand.register())
|
||||
.then(StartBackupCommand.register())
|
||||
.then(WhitelistCommand.register())
|
||||
.then(RestoreBackupCommand.register())
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
|||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.szum123321.textile_backup.core.BackupHelper;
|
||||
import net.szum123321.textile_backup.core.create.BackupHelper;
|
||||
import net.szum123321.textile_backup.core.Utilities;
|
||||
|
||||
public class CleanupCommand {
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
package net.szum123321.textile_backup.commands;
|
||||
|
||||
import com.mojang.brigadier.LiteralMessage;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.suggestion.SuggestionProvider;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
|
||||
import net.szum123321.textile_backup.TextileBackup;
|
||||
import net.szum123321.textile_backup.core.restore.RestoreHelper;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class RestoreBackupCommand {
|
||||
public static LiteralArgumentBuilder<ServerCommandSource> register() {
|
||||
return CommandManager.literal("restore")
|
||||
.then(CommandManager.argument("file", StringArgumentType.greedyString())
|
||||
.suggests(new FileSuggestionProvider())
|
||||
.executes(RestoreBackupCommand::execute));
|
||||
}
|
||||
|
||||
private static int execute(CommandContext<ServerCommandSource> ctx) {
|
||||
String arg = StringArgumentType.getString(ctx, "file");
|
||||
LocalDateTime dateTime = LocalDateTime.from(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").parse(arg));
|
||||
|
||||
if(ctx.getSource().getEntity() != null)
|
||||
TextileBackup.LOGGER.info("Backup restoration was initiated by: {}", ctx.getSource().getName());
|
||||
else
|
||||
TextileBackup.LOGGER.info("Backup restoration was initiated form Server Console");
|
||||
|
||||
new Thread(RestoreHelper.create(dateTime, ctx.getSource().getMinecraftServer())).start();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static final class FileSuggestionProvider implements SuggestionProvider<ServerCommandSource> {
|
||||
@Override
|
||||
public CompletableFuture<Suggestions> getSuggestions(CommandContext<ServerCommandSource> ctx, SuggestionsBuilder builder) throws CommandSyntaxException {
|
||||
String remaining = builder.getRemaining();
|
||||
|
||||
for(RestoreHelper.RestoreableFile file : RestoreHelper.getAvailableBackups(ctx.getSource().getMinecraftServer())) {
|
||||
String formattedCreationTime = file.getCreationTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
|
||||
if(formattedCreationTime.startsWith(remaining)) {
|
||||
if(ctx.getSource().getEntity() != null) { //was typed by player
|
||||
if(file.getComment() != null) {
|
||||
builder.suggest(formattedCreationTime, new LiteralMessage("Comment: " + file.getComment()));
|
||||
} else {
|
||||
builder.suggest(formattedCreationTime);
|
||||
}
|
||||
} else { //was typed from server console
|
||||
if(file.getComment() != null) {
|
||||
builder.suggest(file.getCreationTime() + "#" + file.getComment());
|
||||
} else {
|
||||
builder.suggest(formattedCreationTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.buildFuture();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,8 +24,8 @@ import com.mojang.brigadier.context.CommandContext;
|
|||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.szum123321.textile_backup.TextileBackup;
|
||||
import net.szum123321.textile_backup.core.BackupContext;
|
||||
import net.szum123321.textile_backup.core.BackupHelper;
|
||||
import net.szum123321.textile_backup.core.create.BackupContext;
|
||||
import net.szum123321.textile_backup.core.create.BackupHelper;
|
||||
|
||||
public class StartBackupCommand {
|
||||
public static LiteralArgumentBuilder<ServerCommandSource> register() {
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
package net.szum123321.textile_backup.core;
|
||||
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
import net.szum123321.textile_backup.ConfigHandler;
|
||||
import net.szum123321.textile_backup.TextileBackup;
|
||||
import net.szum123321.textile_backup.mixin.MinecraftServerSessionAccessor;
|
||||
|
@ -45,29 +49,63 @@ public class Utilities {
|
|||
return System.getProperty("os.name").toLowerCase().contains("win");
|
||||
}
|
||||
|
||||
public static Optional<String> getFileExtension(File f) {
|
||||
String[] parts = f.getName().split("\\.");
|
||||
public static Optional<ConfigHandler.ArchiveFormat> getFileExtension(File f) {
|
||||
return getFileExtension(f.getName());
|
||||
}
|
||||
|
||||
public static Optional<ConfigHandler.ArchiveFormat> getFileExtension(String fileName) {
|
||||
String[] parts = fileName.split("\\.");
|
||||
|
||||
switch (parts[parts.length - 1]) {
|
||||
case "zip":
|
||||
return Optional.of(ConfigHandler.ArchiveFormat.ZIP.getExtension());
|
||||
return Optional.of(ConfigHandler.ArchiveFormat.ZIP);
|
||||
case "bz2":
|
||||
return Optional.of(ConfigHandler.ArchiveFormat.BZIP2.getExtension());
|
||||
return Optional.of(ConfigHandler.ArchiveFormat.BZIP2);
|
||||
case "gz":
|
||||
return Optional.of(ConfigHandler.ArchiveFormat.GZIP.getExtension());
|
||||
return Optional.of(ConfigHandler.ArchiveFormat.GZIP);
|
||||
case "xz":
|
||||
return Optional.of(ConfigHandler.ArchiveFormat.LZMA.getExtension());
|
||||
return Optional.of(ConfigHandler.ArchiveFormat.LZMA);
|
||||
|
||||
default:
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public static File getBackupRootPath(String worldName) {
|
||||
File path = new File(TextileBackup.config.path).getAbsoluteFile();
|
||||
|
||||
if (TextileBackup.config.perWorldBackup)
|
||||
path = path.toPath().resolve(worldName).toFile();
|
||||
|
||||
if (!path.exists()) {
|
||||
try {
|
||||
path.mkdirs();
|
||||
} catch (Exception e) {
|
||||
TextileBackup.LOGGER.error("An exception occurred!", e);
|
||||
|
||||
return FabricLoader
|
||||
.getInstance()
|
||||
.getGameDirectory()
|
||||
.toPath()
|
||||
.resolve(TextileBackup.config.path)
|
||||
.toFile();
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public static File getWorldFolder(MinecraftServer server) {
|
||||
return ((MinecraftServerSessionAccessor)server)
|
||||
.getSession()
|
||||
.getWorldDirectory(RegistryKey.of(Registry.DIMENSION, DimensionType.OVERWORLD_REGISTRY_KEY.getValue()));
|
||||
}
|
||||
|
||||
public static Optional<LocalDateTime> getFileCreationTime(File file) {
|
||||
LocalDateTime creationTime = null;
|
||||
|
||||
if(getFileExtension(file).isPresent()) {
|
||||
String fileExtension = getFileExtension(file).get();
|
||||
String fileExtension = getFileExtension(file).get().getString();
|
||||
|
||||
try {
|
||||
creationTime = LocalDateTime.from(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package net.szum123321.textile_backup.core;
|
||||
package net.szum123321.textile_backup.core.create;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
|
@ -107,11 +107,12 @@ public class BackupContext {
|
|||
}
|
||||
|
||||
public enum BackupInitiator {
|
||||
Player ("Player", "by: "),
|
||||
ServerConsole ("Server Console", "from: "),
|
||||
Timer ("Timer", "by: "),
|
||||
Shutdown ("Server Shutdown", "by: "),
|
||||
Null ("Null (That shouldn't have happened)", "form: ");
|
||||
Player ("Player", "by"),
|
||||
ServerConsole ("Server Console", "from"),
|
||||
Timer ("Timer", "by"),
|
||||
Shutdown ("Server Shutdown", "by"),
|
||||
Restore ("Backup Restore", "by"),
|
||||
Null ("Null (That shouldn't have happened)", "form");
|
||||
|
||||
private final String name;
|
||||
private final String prefix;
|
||||
|
@ -126,7 +127,7 @@ public class BackupContext {
|
|||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
return prefix + ": ";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,11 +16,11 @@
|
|||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.szum123321.textile_backup.core;
|
||||
package net.szum123321.textile_backup.core.create;
|
||||
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.szum123321.textile_backup.TextileBackup;
|
||||
import net.szum123321.textile_backup.core.Utilities;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -59,7 +59,7 @@ public class BackupHelper {
|
|||
}
|
||||
|
||||
public static int executeFileLimit(ServerCommandSource ctx, String worldName) {
|
||||
File root = getBackupRootPath(worldName);
|
||||
File root = Utilities.getBackupRootPath(worldName);
|
||||
AtomicInteger deletedFiles = new AtomicInteger();
|
||||
|
||||
if (root.isDirectory() && root.exists() && root.listFiles() != null) {
|
||||
|
@ -127,28 +127,4 @@ public class BackupHelper {
|
|||
}
|
||||
|
||||
private static boolean isFileOk(File f) {return f.exists() && f.isFile(); }
|
||||
|
||||
public static File getBackupRootPath(String worldName) {
|
||||
File path = new File(TextileBackup.config.path).getAbsoluteFile();
|
||||
|
||||
if (TextileBackup.config.perWorldBackup)
|
||||
path = path.toPath().resolve(worldName).toFile();
|
||||
|
||||
if (!path.exists()) {
|
||||
try {
|
||||
path.mkdirs();
|
||||
} catch (Exception e) {
|
||||
TextileBackup.LOGGER.error("An exception occurred!", e);
|
||||
|
||||
return FabricLoader
|
||||
.getInstance()
|
||||
.getGameDirectory()
|
||||
.toPath()
|
||||
.resolve(TextileBackup.config.path)
|
||||
.toFile();
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package net.szum123321.textile_backup.core;
|
||||
package net.szum123321.textile_backup.core.create;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.szum123321.textile_backup.TextileBackup;
|
|
@ -16,19 +16,16 @@
|
|||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.szum123321.textile_backup.core;
|
||||
package net.szum123321.textile_backup.core.create;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
import net.szum123321.textile_backup.TextileBackup;
|
||||
import net.szum123321.textile_backup.compressors.LZMACompressor;
|
||||
import net.szum123321.textile_backup.compressors.ParallelBZip2Compressor;
|
||||
import net.szum123321.textile_backup.compressors.ParallelGzipCompressor;
|
||||
import net.szum123321.textile_backup.compressors.ParallelZipCompressor;
|
||||
import net.szum123321.textile_backup.mixin.MinecraftServerSessionAccessor;
|
||||
import net.szum123321.textile_backup.core.create.compressors.LZMACompressor;
|
||||
import net.szum123321.textile_backup.core.create.compressors.ParallelBZip2Compressor;
|
||||
import net.szum123321.textile_backup.core.create.compressors.ParallelGzipCompressor;
|
||||
import net.szum123321.textile_backup.core.create.compressors.ParallelZipCompressor;
|
||||
import net.szum123321.textile_backup.core.Utilities;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -49,13 +46,11 @@ public class MakeBackupRunnable implements Runnable {
|
|||
public void run() {
|
||||
Utilities.info("Starting backup", commandSource);
|
||||
|
||||
File world = ((MinecraftServerSessionAccessor)server)
|
||||
.getSession()
|
||||
.getWorldDirectory(RegistryKey.of(Registry.DIMENSION, DimensionType.OVERWORLD_REGISTRY_KEY.getValue()));
|
||||
File world = Utilities.getWorldFolder(server);
|
||||
|
||||
TextileBackup.LOGGER.trace("Minecraft world is: {}", world);
|
||||
|
||||
File outFile = BackupHelper
|
||||
File outFile = Utilities
|
||||
.getBackupRootPath(Utilities.getLevelName(server))
|
||||
.toPath()
|
||||
.resolve(getFileName())
|
||||
|
@ -118,6 +113,6 @@ public class MakeBackupRunnable implements Runnable {
|
|||
private String getFileName(){
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
return Utilities.getDateTimeFormatter().format(now) + (comment != null ? "#" + comment.replace("#", "") : "") + TextileBackup.config.format.getExtension();
|
||||
return Utilities.getDateTimeFormatter().format(now) + (comment != null ? "#" + comment.replace("#", "") : "") + TextileBackup.config.format.getString();
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package net.szum123321.textile_backup.compressors;
|
||||
package net.szum123321.textile_backup.core.create.compressors;
|
||||
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.szum123321.textile_backup.TextileBackup;
|
|
@ -1,4 +1,4 @@
|
|||
package net.szum123321.textile_backup.compressors;
|
||||
package net.szum123321.textile_backup.core.create.compressors;
|
||||
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.szum123321.textile_backup.TextileBackup;
|
|
@ -1,4 +1,4 @@
|
|||
package net.szum123321.textile_backup.compressors;
|
||||
package net.szum123321.textile_backup.core.create.compressors;
|
||||
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.szum123321.textile_backup.TextileBackup;
|
|
@ -1,4 +1,4 @@
|
|||
package net.szum123321.textile_backup.compressors;
|
||||
package net.szum123321.textile_backup.core.create.compressors;
|
||||
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.szum123321.textile_backup.TextileBackup;
|
|
@ -0,0 +1,68 @@
|
|||
package net.szum123321.textile_backup.core.restore;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.szum123321.textile_backup.TextileBackup;
|
||||
import net.szum123321.textile_backup.core.Utilities;
|
||||
import net.szum123321.textile_backup.core.restore.decompressors.GenericTarDecompressor;
|
||||
import net.szum123321.textile_backup.core.restore.decompressors.ZipDecompressor;
|
||||
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
|
||||
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
|
||||
import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class RestoreBackupRunnable implements Runnable {
|
||||
private final MinecraftServer server;
|
||||
private final File backupFile;
|
||||
|
||||
public RestoreBackupRunnable(MinecraftServer server, File backupFile) {
|
||||
this.server = server;
|
||||
this.backupFile = backupFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while(server.isRunning()) {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
TextileBackup.LOGGER.error("Exception occurred!", e);
|
||||
}
|
||||
}
|
||||
|
||||
File worldFile = Utilities.getWorldFolder(server);
|
||||
|
||||
deleteDirectory(worldFile);
|
||||
|
||||
worldFile.mkdirs();
|
||||
|
||||
switch(Utilities.getFileExtension(backupFile).get()) {
|
||||
case ZIP:
|
||||
ZipDecompressor.decompress(backupFile, worldFile);
|
||||
break;
|
||||
|
||||
case GZIP:
|
||||
GenericTarDecompressor.decompress(backupFile, worldFile, GzipCompressorInputStream.class);
|
||||
break;
|
||||
|
||||
case BZIP2:
|
||||
GenericTarDecompressor.decompress(backupFile, worldFile, BZip2CompressorInputStream.class);
|
||||
break;
|
||||
|
||||
case LZMA:
|
||||
GenericTarDecompressor.decompress(backupFile, worldFile, XZCompressorInputStream.class);
|
||||
break;
|
||||
}
|
||||
|
||||
TextileBackup.LOGGER.info("Done.");
|
||||
}
|
||||
|
||||
private static void deleteDirectory(File f) {
|
||||
if(f.isDirectory()) {
|
||||
for(File f2 : f.listFiles())
|
||||
deleteDirectory(f2);
|
||||
}
|
||||
|
||||
f.delete();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package net.szum123321.textile_backup.core.restore;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.szum123321.textile_backup.TextileBackup;
|
||||
import net.szum123321.textile_backup.core.Utilities;
|
||||
import net.szum123321.textile_backup.core.create.BackupContext;
|
||||
import net.szum123321.textile_backup.core.create.BackupHelper;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class RestoreHelper {
|
||||
public static Runnable create(LocalDateTime backupTime, MinecraftServer server) {
|
||||
server.getPlayerManager().getPlayerList()
|
||||
.forEach(serverPlayerEntity -> serverPlayerEntity.sendMessage(new LiteralText("Warning! The server is going to shut down in few moments!"), false));
|
||||
|
||||
File backupFile = Arrays.stream(Utilities.getBackupRootPath(Utilities.getLevelName(server))
|
||||
.listFiles())
|
||||
.filter(file -> Utilities.getFileCreationTime(file).isPresent())
|
||||
.filter(file -> Utilities.getFileCreationTime(file).get().equals(backupTime))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
|
||||
TextileBackup.LOGGER.info("Restoring: {}", backupFile.getName());
|
||||
|
||||
TextileBackup.globalShutdownBackupFlag.set(false);
|
||||
|
||||
BackupHelper.create(
|
||||
new BackupContext.Builder()
|
||||
.setServer(server)
|
||||
.setInitiator(BackupContext.BackupInitiator.Restore)
|
||||
.setComment("Old_World")
|
||||
.setSave()
|
||||
.build()
|
||||
).run();
|
||||
|
||||
TextileBackup.LOGGER.info("Shutting down server...");
|
||||
|
||||
server.stop(false);
|
||||
|
||||
return new RestoreBackupRunnable(server, backupFile);
|
||||
}
|
||||
|
||||
public static List<RestoreableFile> getAvailableBackups(MinecraftServer server) {
|
||||
File root = Utilities.getBackupRootPath(Utilities.getLevelName(server));
|
||||
|
||||
return Arrays.stream(root.listFiles())
|
||||
.filter(File::isFile)
|
||||
.filter(file -> Utilities.getFileExtension(file.getName()).isPresent())
|
||||
.filter(file -> Utilities.getFileCreationTime(file).isPresent())
|
||||
.map(RestoreableFile::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static class RestoreableFile {
|
||||
private final LocalDateTime creationTime;
|
||||
private final String comment;
|
||||
|
||||
protected RestoreableFile(File file) {
|
||||
String extension = Utilities.getFileExtension(file).get().getString();
|
||||
this.creationTime = Utilities.getFileCreationTime(file).get();
|
||||
|
||||
final String filename = file.getName();
|
||||
|
||||
if(filename.split("#").length > 1) {
|
||||
this.comment = filename.split("#")[1].split(extension)[0];
|
||||
} else {
|
||||
this.comment = null;
|
||||
}
|
||||
}
|
||||
|
||||
public LocalDateTime getCreationTime() {
|
||||
return creationTime;
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package net.szum123321.textile_backup.core.restore.decompressors;
|
||||
|
||||
import net.szum123321.textile_backup.TextileBackup;
|
||||
import net.szum123321.textile_backup.core.Utilities;
|
||||
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
|
||||
import org.apache.commons.compress.compressors.CompressorInputStream;
|
||||
import org.apache.commons.compress.utils.IOUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.file.Files;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
public class GenericTarDecompressor {
|
||||
public static void decompress(File archiveFile, File target, Class<? extends CompressorInputStream> DecompressorStream) {
|
||||
Instant start = Instant.now();
|
||||
|
||||
try (FileInputStream inputStream = new FileInputStream(archiveFile);
|
||||
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
|
||||
CompressorInputStream compressorInputStream = DecompressorStream.getDeclaredConstructor(InputStream.class).newInstance(bufferedInputStream);
|
||||
TarArchiveInputStream archiveInputStream = new TarArchiveInputStream(compressorInputStream)) {
|
||||
TarArchiveEntry entry;
|
||||
|
||||
while ((entry = archiveInputStream.getNextTarEntry()) != null) {
|
||||
if(!archiveInputStream.canReadEntryData(entry))
|
||||
continue;
|
||||
|
||||
File file = target.toPath().resolve(entry.getName()).toFile();
|
||||
|
||||
if(entry.isDirectory()) {
|
||||
file.mkdirs();
|
||||
} else {
|
||||
File parent = file.getParentFile();
|
||||
|
||||
if (!parent.isDirectory() && !parent.mkdirs())
|
||||
throw new IOException("Failed to create directory " + parent);
|
||||
|
||||
try (OutputStream outputStream = Files.newOutputStream(file.toPath());
|
||||
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream)) {
|
||||
IOUtils.copy(archiveInputStream, bufferedOutputStream);
|
||||
} catch (IOException e) {
|
||||
TextileBackup.LOGGER.error("An exception occurred while trying to compress file: " + file.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException | NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
|
||||
TextileBackup.LOGGER.error("An exception occurred! ", e);
|
||||
}
|
||||
|
||||
TextileBackup.LOGGER.info("Decompression took {} seconds.", Utilities.formatDuration(Duration.between(start, Instant.now())));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package net.szum123321.textile_backup.core.restore.decompressors;
|
||||
|
||||
import net.szum123321.textile_backup.TextileBackup;
|
||||
import net.szum123321.textile_backup.core.Utilities;
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
|
||||
import org.apache.commons.compress.utils.IOUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
public class ZipDecompressor {
|
||||
public static void decompress(File archiveFile, File target) {
|
||||
Instant start = Instant.now();
|
||||
|
||||
try (FileInputStream inputStream = new FileInputStream(archiveFile);
|
||||
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
|
||||
ZipArchiveInputStream zipInputStream = new ZipArchiveInputStream((bufferedInputStream))) {
|
||||
ZipArchiveEntry entry;
|
||||
|
||||
while ((entry = zipInputStream.getNextZipEntry()) != null) {
|
||||
if(!zipInputStream.canReadEntryData(entry))
|
||||
continue;
|
||||
|
||||
File file = target.toPath().resolve(entry.getName()).toFile();
|
||||
|
||||
if(entry.isDirectory()) {
|
||||
file.mkdirs();
|
||||
} else {
|
||||
File parent = file.getParentFile();
|
||||
|
||||
if (!parent.isDirectory() && !parent.mkdirs())
|
||||
throw new IOException("Failed to create directory " + parent);
|
||||
|
||||
try (OutputStream outputStream = Files.newOutputStream(file.toPath());
|
||||
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream)) {
|
||||
IOUtils.copy(zipInputStream, bufferedOutputStream);
|
||||
} catch (IOException e) {
|
||||
TextileBackup.LOGGER.error("An exception occurred while trying to compress file: " + file.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
TextileBackup.LOGGER.error("An exception occurred! ", e);
|
||||
}
|
||||
|
||||
TextileBackup.LOGGER.info("Compression took: {} seconds.", Utilities.formatDuration(Duration.between(start, Instant.now())));
|
||||
}
|
||||
}
|
|
@ -20,8 +20,8 @@ package net.szum123321.textile_backup.mixin;
|
|||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.szum123321.textile_backup.TextileBackup;
|
||||
import net.szum123321.textile_backup.core.BackupContext;
|
||||
import net.szum123321.textile_backup.core.BackupHelper;
|
||||
import net.szum123321.textile_backup.core.create.BackupContext;
|
||||
import net.szum123321.textile_backup.core.create.BackupHelper;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
|
@ -31,7 +31,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||
public abstract class MinecraftServerMixin {
|
||||
@Inject(method = "shutdown", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/server/MinecraftServer;save(ZZZ)Z"))
|
||||
public void onFinalWorldSave(CallbackInfo ci) {
|
||||
if (TextileBackup.config.shutdownBackup)
|
||||
if (TextileBackup.config.shutdownBackup && TextileBackup.globalShutdownBackupFlag.get())
|
||||
TextileBackup.executorService.submit(
|
||||
BackupHelper.create(
|
||||
new BackupContext.Builder()
|
||||
|
|
Loading…
Reference in New Issue