Skip to content

Commit

Permalink
add: AutomaticBackup
Browse files Browse the repository at this point in the history
  • Loading branch information
sakurawald committed Jul 13, 2024
1 parent 48fa9eb commit 3db5571
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 61 deletions.
13 changes: 11 additions & 2 deletions src/main/java/io/github/sakurawald/Fuji.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.github.sakurawald.config.handler.ConfigHandler;
import io.github.sakurawald.module.ModuleManager;
import io.github.sakurawald.module.common.service.AutomaticBackup;
import io.github.sakurawald.util.LogUtil;
import io.github.sakurawald.util.ScheduleUtil;
import net.fabricmc.api.ModInitializer;
Expand All @@ -13,7 +14,7 @@

import java.nio.file.Path;

// TODO: placeholder module (placeholder api)
// TODO: placeholder module (refactor main stats to use placeholder manager -> local + luckperms metas)

// TODO: specific command module
// TODO: add native shell support specific command
Expand All @@ -24,6 +25,7 @@
// TODO: player nickname / prefix / suffix
// TODO: nickname module

// TODO: refactor command facility (selector)
// TODO: command warmup module
// TODO: /spawn module
// TODO: /tppos module
Expand All @@ -36,7 +38,11 @@
// TODO: condense module
// TODO: use aop style
// TODO: a program to generate module reference DAG

// TODO: powertool module
// TODO: refactor chat module to use prefix/suffix metas
// TODO: refactor system-message module -> transform, supress
// TODO: refactor home module to support metas
// TODO: add anti build module -> place, use, break, piston. (facility: alert, permission, black/white list)

public class Fuji implements ModInitializer {
public static final String MOD_ID = "fuji";
Expand All @@ -46,6 +52,9 @@ public class Fuji implements ModInitializer {

@Override
public void onInitialize() {
/* backup */
AutomaticBackup.backup();

/* modules */
ModuleManager.initializeModules();
ServerLifecycleEvents.SERVER_STARTED.register(server -> ModuleManager.reportModules());
Expand Down
50 changes: 27 additions & 23 deletions src/main/java/io/github/sakurawald/config/model/ConfigModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@ public class Quartz {
public String logger_level = "WARN";
}

public Backup backup = new Backup();
public class Backup {
@Documentation("How many backup should we keep?")
public int max_slots = 15;
@Documentation("""
The list of `path resolver` to skip
""")
public List<String> skip = new ArrayList<>() {
{
this.add("head");
}
};
}

}

@Documentation("""
Expand Down Expand Up @@ -113,6 +127,16 @@ public class Modules {
public Anvil anvil = new Anvil();
public GrindStone grindstone = new GrindStone();
public StoneCutter stonecutter = new StoneCutter();
public Bed bed = new Bed();
public Sit sit = new Sit();
public CommandAlias command_alias = new CommandAlias();
public CommandRewrite command_rewrite = new CommandRewrite();
public Loom loom = new Loom();
public Cartography cartography = new Cartography();
public Smithing smithing = new Smithing();
public World world = new World();
public Realname realname = new Realname();
public Protect protect = new Protect();

@Documentation("""
This module adds another 3 worlds called `resource world`: resrouce_overworld, resource_nether, resource_the_end .
Expand Down Expand Up @@ -869,16 +893,12 @@ public class StoneCutter {
public boolean enable = false;
}

public Bed bed = new Bed();

@Documentation("This module provides `/bed` command, which teleports the player to his bed.")
public class Bed {

public boolean enable = false;
}

public Sit sit = new Sit();

@Documentation("""
This module provides `/sit` command, and the ability to sit by right-click any chair.
""")
Expand All @@ -893,8 +913,6 @@ public class Sit {
public boolean no_opaque_block_above = false;
}

public CommandAlias command_alias = new CommandAlias();

@Documentation("""
This module provides command alias.
Expand All @@ -911,8 +929,6 @@ public class CommandAlias {
};
}

public CommandRewrite command_rewrite = new CommandRewrite();

@Documentation("""
This module provides command rewrite, so that you can use `regex language` to rewrite the `command line` a player issued.
""")
Expand All @@ -926,59 +942,47 @@ public class CommandRewrite {

}

public Loom loom = new Loom();

@Documentation("This module provides `/loom` command.")
public class Loom {
public boolean enable = false;
}

public Cartography cartography = new Cartography();

@Documentation("This module provides `/cartography` command.")
public class Cartography {
public boolean enable = false;
}

public Smithing smithing = new Smithing();

@Documentation("This module provides `/smithing` command.")
public class Smithing {
public boolean enable = false;
}

public World world = new World();

@Documentation("This module provides `/world` command, which teleport the player to target dimension.")
public class World {
public boolean enable = false;

}

public Realname realname = new Realname();

@Documentation("This module provides `/realname` command.")
public class Realname {
public boolean enable = false;

}

public Protect protect = new Protect();

@Documentation("""
This module provides damage-cancel by permission.
For performance considered:
1. This module only check damage_type inside this checklist.
2. The permission is checked by cache.
You can query damage_type list in minecraft using `/damage @r 1 <damage_type>`
For example,
If you want to protect all the players from fall damage, you should do:
1. add `minecraft:fall` into the `damage_type_checklist`.
2. grant the permission for players: `/lp group default permission set fuji.protect.minecraft:fall`
If you grant permission `/lp group default permission set fuji.protect.*`, then it means cancel
all the damage types inside the `damage_type_checklist`.
""")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package io.github.sakurawald.module.common.service;

import io.github.sakurawald.Fuji;
import io.github.sakurawald.config.Configs;
import io.github.sakurawald.util.FileUtil;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

@Slf4j
@UtilityClass
public class AutomaticBackup {

public static final Path BACKUP_PATH = Fuji.CONFIG_PATH.resolve("backup");

private static boolean skipPath(Path dir) {
for (String other : Configs.configHandler.model().common.backup.skip) {
if (dir.equals(Fuji.CONFIG_PATH.resolve(other))) return true;
}

return false;
}

private static List<File> getInputFiles() {
List<File> files = new ArrayList<>();
try {
Files.walkFileTree(Fuji.CONFIG_PATH, new SimpleFileVisitor<>() {

@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
if (BACKUP_PATH.equals(dir)) return FileVisitResult.SKIP_SUBTREE;
if (skipPath(dir)) return FileVisitResult.SKIP_SUBTREE;

return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
files.add(file.toFile());
return FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
throw new RuntimeException(e);
}

return files;
}

private static void trimBackup() {
List<Path> latestFiles = FileUtil.getLatestFiles(BACKUP_PATH);
Iterator<Path> iterator = latestFiles.iterator();
while (iterator.hasNext() && latestFiles.size() > Configs.configHandler.model().common.backup.max_slots - 1) {
iterator.next().toFile().delete();
iterator.remove();
}
}

private static File getOutputFile() {
String fileName = System.currentTimeMillis() + ".zip";
return BACKUP_PATH.resolve(fileName).toFile();
}

private static void newBackup() {
BACKUP_PATH.toFile().mkdirs();
FileUtil.compressFiles(getInputFiles(), getOutputFile());
}

public static void backup() {
trimBackup();
newBackup();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.github.sakurawald.config.Configs;
import io.github.sakurawald.module.initializer.ModuleInitializer;
import io.github.sakurawald.util.CommandUtil;
import io.github.sakurawald.util.FileUtil;
import io.github.sakurawald.util.MessageUtil;
import lombok.SneakyThrows;
import net.minecraft.command.CommandRegistryAccess;
Expand All @@ -22,17 +23,13 @@
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import net.minecraft.world.level.storage.LevelStorage;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveOutputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class WorldDownloaderInitializer extends ModuleInitializer {
Expand Down Expand Up @@ -131,45 +128,22 @@ public File compressRegionFile(ServerPlayerEntity player) {

/* compress file */
String regionName = "r." + regionX + "." + regionZ + ".mca";
File[] input = {
new File(worldDirectory, "region" + File.separator + regionName),
new File(worldDirectory, "poi" + File.separator + regionName),
new File(worldDirectory, "entities" + File.separator + regionName)
List<File> input = new ArrayList<>() {
{
this.add(new File(worldDirectory, "region" + File.separator + regionName));
this.add(new File(worldDirectory, "poi" + File.separator + regionName));
this.add(new File(worldDirectory, "entities" + File.separator + regionName));
}
};
File output;
try {
output = Files.createTempFile(regionName + "#", ".zip").toFile();
compressFiles(input, output);
FileUtil.compressFiles(input, output);
} catch (IOException e) {
throw new RuntimeException(e);
}
Fuji.LOGGER.info("Generate region file: {}", output.getAbsolutePath());
return output;
}

@SneakyThrows
public void compressFiles(File[] input, File output) {
try (FileOutputStream fos = new FileOutputStream(output);
ArchiveOutputStream archiveOut = new ZipArchiveOutputStream(fos)) {
for (File file : input) {
if (file.isFile() && file.exists()) {
ArchiveEntry entry = new ZipArchiveEntry(file, getEntryName(file));
archiveOut.putArchiveEntry(entry);
try (FileInputStream fis = new FileInputStream(file)) {
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) > 0) {
archiveOut.write(buffer, 0, len);
}
}
archiveOut.closeArchiveEntry();
}
}
}
}

private String getEntryName(File file) {
return file.getParentFile().getName() + File.separator + file.getName();
}

}
4 changes: 4 additions & 0 deletions src/main/java/io/github/sakurawald/util/DateUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ public class DateUtil {

private static final SimpleDateFormat STANDARD_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

public static String getCurrentDate() {
return toStandardDateFormat(System.currentTimeMillis());
}

public static String toStandardDateFormat(long timeMillis) {
return STANDARD_DATE_FORMAT.format(timeMillis);
}
Expand Down
Loading

0 comments on commit 3db5571

Please sign in to comment.