diff --git a/src/main/java/net/szum123321/textile_backup/TextileBackup.java b/src/main/java/net/szum123321/textile_backup/TextileBackup.java index 5d24d56..cbd8259 100644 --- a/src/main/java/net/szum123321/textile_backup/TextileBackup.java +++ b/src/main/java/net/szum123321/textile_backup/TextileBackup.java @@ -21,6 +21,7 @@ package net.szum123321.textile_backup; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import io.github.cottonmc.cotton.config.ConfigManager; +import io.github.cottonmc.cotton.logging.ModLogger; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; @@ -30,9 +31,12 @@ import net.szum123321.textile_backup.commands.create.CleanupCommand; import net.szum123321.textile_backup.commands.create.StartBackupCommand; import net.szum123321.textile_backup.commands.permission.BlacklistCommand; import net.szum123321.textile_backup.commands.permission.WhitelistCommand; +import net.szum123321.textile_backup.commands.restore.KillRestoreCommand; import net.szum123321.textile_backup.commands.restore.ListBackupsCommand; import net.szum123321.textile_backup.commands.restore.RestoreBackupCommand; import net.szum123321.textile_backup.core.create.BackupScheduler; +import net.szum123321.textile_backup.core.restore.AwaitThread; +import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.ParameterizedMessageFactory; @@ -50,7 +54,9 @@ 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); + public static AwaitThread restoreAwaitThread; @Override public void onInitialize() { @@ -92,6 +98,7 @@ public class TextileBackup implements ModInitializer { .then(WhitelistCommand.register()) .then(RestoreBackupCommand.register()) .then(ListBackupsCommand.register()) + .then(KillRestoreCommand.register()) )); } } diff --git a/src/main/java/net/szum123321/textile_backup/commands/restore/KillRestoreCommand.java b/src/main/java/net/szum123321/textile_backup/commands/restore/KillRestoreCommand.java new file mode 100644 index 0000000..0481062 --- /dev/null +++ b/src/main/java/net/szum123321/textile_backup/commands/restore/KillRestoreCommand.java @@ -0,0 +1,22 @@ +package net.szum123321.textile_backup.commands.restore; + +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.TextileBackup; + +public class KillRestoreCommand { + public static LiteralArgumentBuilder register() { + return CommandManager.literal("kill_r") //TODO: come up with something better + .executes(ctx -> { + if(TextileBackup.restoreAwaitThread != null && TextileBackup.restoreAwaitThread.isRunning()) { + TextileBackup.restoreAwaitThread.kill(); + ctx.getSource().sendFeedback(new LiteralText("Backup restoration successfully stopped"), false); + } else { + ctx.getSource().sendFeedback(new LiteralText("Failed to stop backup restoration"), false); + } + return 1; + }); + } +} diff --git a/src/main/java/net/szum123321/textile_backup/commands/restore/ListBackupsCommand.java b/src/main/java/net/szum123321/textile_backup/commands/restore/ListBackupsCommand.java index b32ebb9..78bdb00 100644 --- a/src/main/java/net/szum123321/textile_backup/commands/restore/ListBackupsCommand.java +++ b/src/main/java/net/szum123321/textile_backup/commands/restore/ListBackupsCommand.java @@ -30,7 +30,7 @@ public class ListBackupsCommand { builder.append(iterator.next()); while(iterator.hasNext()) { - builder.append("\n"); + builder.append(",\n"); builder.append(iterator.next()); } } diff --git a/src/main/java/net/szum123321/textile_backup/commands/restore/RestoreBackupCommand.java b/src/main/java/net/szum123321/textile_backup/commands/restore/RestoreBackupCommand.java index f2160a7..aa2b37b 100644 --- a/src/main/java/net/szum123321/textile_backup/commands/restore/RestoreBackupCommand.java +++ b/src/main/java/net/szum123321/textile_backup/commands/restore/RestoreBackupCommand.java @@ -11,7 +11,9 @@ import com.mojang.brigadier.suggestion.SuggestionsBuilder; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.LiteralText; import net.szum123321.textile_backup.TextileBackup; +import net.szum123321.textile_backup.core.restore.AwaitThread; import net.szum123321.textile_backup.core.restore.RestoreHelper; import java.time.LocalDateTime; @@ -43,7 +45,16 @@ public class RestoreBackupCommand { else TextileBackup.LOGGER.info("Backup restoration was initiated form Server Console"); - RestoreHelper.create(dateTime, ctx.getSource().getMinecraftServer(), null).start(); + if(TextileBackup.restoreAwaitThread == null || !TextileBackup.restoreAwaitThread.isRunning()) { + TextileBackup.restoreAwaitThread = new AwaitThread( + TextileBackup.CONFIG.restoreDelay, + RestoreHelper.create(dateTime, ctx.getSource().getMinecraftServer(), null) + ); + + TextileBackup.restoreAwaitThread.start(); + } else if(TextileBackup.restoreAwaitThread != null && TextileBackup.restoreAwaitThread.isRunning()) { + ctx.getSource().sendFeedback(new LiteralText("Someone has already started another restoration."), false); + } return 1; } @@ -59,7 +70,16 @@ public class RestoreBackupCommand { else TextileBackup.LOGGER.info("Backup restoration was initiated form Server Console"); - RestoreHelper.create(dateTime, ctx.getSource().getMinecraftServer(), comment).start(); + if(TextileBackup.restoreAwaitThread == null || !TextileBackup.restoreAwaitThread.isRunning()) { + TextileBackup.restoreAwaitThread = new AwaitThread( + TextileBackup.CONFIG.restoreDelay, + RestoreHelper.create(dateTime, ctx.getSource().getMinecraftServer(), comment) + ); + + TextileBackup.restoreAwaitThread.start(); + } else if(TextileBackup.restoreAwaitThread != null && TextileBackup.restoreAwaitThread.isRunning()) { + ctx.getSource().sendFeedback(new LiteralText("Someone has already started another restoration."), false); + } return 1; } diff --git a/src/main/java/net/szum123321/textile_backup/core/restore/AwaitThread.java b/src/main/java/net/szum123321/textile_backup/core/restore/AwaitThread.java new file mode 100644 index 0000000..a787d69 --- /dev/null +++ b/src/main/java/net/szum123321/textile_backup/core/restore/AwaitThread.java @@ -0,0 +1,52 @@ +package net.szum123321.textile_backup.core.restore; + +import net.szum123321.textile_backup.TextileBackup; + +public class AwaitThread extends Thread { + private final int delay; + private final Runnable taskRunnable; + private boolean running; + + public AwaitThread(int delay, Runnable taskRunnable) { + this.delay = delay; + this.taskRunnable = taskRunnable; + } + + @Override + public void run() { + TextileBackup.LOGGER.info("Countdown begins..."); + + running = true; + int counter = delay * 10; // done to increase responsiveness + + + while(counter > 0) { // 𝄞 This is final count down! Tu ruru Tu, Tu Ru Tu Tu ♪ + try { + Thread.sleep(100); + counter--; + } catch (InterruptedException e) { + TextileBackup.LOGGER.info("An exception occurred while counting down", e); + } + + if(!running) + return; + } + + /* + We're leaving together, + But still it's farewell + And maybe we'll come back + */ + new Thread(taskRunnable).start(); + + running = false; + } + + public synchronized void kill() { + this.running = false; + } + + public boolean isRunning() { + return running; + } +} diff --git a/src/main/java/net/szum123321/textile_backup/core/restore/RestoreBackupRunnable.java b/src/main/java/net/szum123321/textile_backup/core/restore/RestoreBackupRunnable.java index 49a9513..33b19a6 100644 --- a/src/main/java/net/szum123321/textile_backup/core/restore/RestoreBackupRunnable.java +++ b/src/main/java/net/szum123321/textile_backup/core/restore/RestoreBackupRunnable.java @@ -48,9 +48,6 @@ public class RestoreBackupRunnable implements Runnable { @Override public void run() { - TextileBackup.LOGGER.info("Starting countdown..."); - waitDelay(); - TextileBackup.LOGGER.info("Shutting down server..."); server.stop(false); awaitServerShutdown(); @@ -100,18 +97,6 @@ public class RestoreBackupRunnable implements Runnable { TextileBackup.LOGGER.info("Done."); } - private void waitDelay() { - int delay = TextileBackup.CONFIG.restoreDelay; - - if(delay > 0) { - try { - Thread.sleep(1000 * delay); - } catch (InterruptedException e) { - TextileBackup.LOGGER.error("Exception occurred!", e); - } - } - } - private void awaitServerShutdown() { while(((LivingServer)server).isAlive()) { try {