diff options
author | Aaron <51387595+AzureAaron@users.noreply.github.com> | 2024-02-27 15:44:55 -0500 |
---|---|---|
committer | Aaron <51387595+AzureAaron@users.noreply.github.com> | 2024-02-27 15:45:09 -0500 |
commit | a087eb62b5a79e3f5b05676ce9cbd70c89c8ba9e (patch) | |
tree | 8010f762f883a10cd9c8e283e9332ca579b2f3c4 /src/main/java/de/hysky/skyblocker/config/ImageRepoLoader.java | |
parent | 6f16df3f8049e27fa0d52a335c152d47aaf10428 (diff) | |
download | Skyblocker-a087eb62b5a79e3f5b05676ce9cbd70c89c8ba9e.tar.gz Skyblocker-a087eb62b5a79e3f5b05676ce9cbd70c89c8ba9e.tar.bz2 Skyblocker-a087eb62b5a79e3f5b05676ce9cbd70c89c8ba9e.zip |
Image Repo Loader
Diffstat (limited to 'src/main/java/de/hysky/skyblocker/config/ImageRepoLoader.java')
-rw-r--r-- | src/main/java/de/hysky/skyblocker/config/ImageRepoLoader.java | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/src/main/java/de/hysky/skyblocker/config/ImageRepoLoader.java b/src/main/java/de/hysky/skyblocker/config/ImageRepoLoader.java new file mode 100644 index 00000000..0591cd96 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/config/ImageRepoLoader.java @@ -0,0 +1,144 @@ +package de.hysky.skyblocker.config; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.concurrent.CompletableFuture; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import org.slf4j.Logger; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.mojang.logging.LogUtils; +import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.utils.FileUtils; +import de.hysky.skyblocker.utils.Http; + +public class ImageRepoLoader { + private static final Logger LOGGER = LogUtils.getLogger(); + static final Path REPO_DIRECTORY = SkyblockerMod.CONFIG_DIR.resolve("image-repo"); + private static final String BRANCH_INFO = "https://api.github.com/repos/SkyblockerMod/Skyblocker-Assets/branches/images"; + private static final String REPO_DOWNLOAD = "https://github.com/SkyblockerMod/Skyblocker-Assets/archive/refs/heads/images.zip"; + private static final String PLACEHOLDER_HASH = "None!"; + + public static void init() { + update(0); + } + + /** + * Attempts to update/load the image repository, if any errors are encountered it will try 3 times. + */ + private static void update(int retries) { + CompletableFuture.runAsync(() -> { + if (retries < 3) { + try { + long start = System.currentTimeMillis(); + //Retrieve the saved commit hash + String savedCommitHash = checkSavedCommitData(); + + //Fetch the latest commit data + JsonObject response = JsonParser.parseString(Http.sendGetRequest(BRANCH_INFO)).getAsJsonObject(); + String latestCommitHash = response.getAsJsonObject("commit").get("sha").getAsString(); + + //Download the repository if there was a new commit + if (!savedCommitHash.equals(latestCommitHash)) { + InputStream in = Http.downloadContent(REPO_DOWNLOAD); + + //Delete all directories to clear potentially now unused/old files + //TODO change this to only delete periodically? + deleteDirectories(); + + try (ZipInputStream zis = new ZipInputStream(in)) { + ZipEntry entry; + + while ((entry = zis.getNextEntry()) != null) { + Path outputFile = REPO_DIRECTORY.resolve(entry.getName()); + + if (entry.isDirectory()) { + Files.createDirectories(outputFile); + } else { + Files.createDirectories(outputFile.getParent()); + Files.copy(zis, outputFile, StandardCopyOption.REPLACE_EXISTING); + } + } + } + + writeCommitData(latestCommitHash); + + long end = System.currentTimeMillis(); + LOGGER.info("[Skyblocker] Successfully updated the Image Respository in {} ms! {} → {}", end - start, savedCommitHash, latestCommitHash); + } else { + LOGGER.info("[Skyblocker] The Image Respository is up to date!"); + } + } catch (Exception e) { + LOGGER.error("[Skyblocker] Error while downloading image repo on attempt {}!", retries, e); + update(retries + 1); + } + } + }); + } + + /** + * @return The stored hash or the {@link #PLACEHOLDER_HASH}. + */ + private static String checkSavedCommitData() throws IOException { + Path file = REPO_DIRECTORY.resolve("image_repo.json"); + + if (Files.exists(file)) { + try (BufferedReader reader = Files.newBufferedReader(file)) { + CommitData commitData = CommitData.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)).result().orElseThrow(); + + return commitData.commit(); + } + } + + return PLACEHOLDER_HASH; + } + + /** + * Writes the {@code newHash} into a file to be used to check for repo updates. + * + * @implNote Checking whether the directory exists or not isn't needed as this is called after all files are written successfully. + */ + private static void writeCommitData(String newHash) throws IOException { + Path file = REPO_DIRECTORY.resolve("image_repo.json"); + CommitData commitData = new CommitData(newHash, System.currentTimeMillis()); + + try (BufferedWriter writer = Files.newBufferedWriter(file)) { + SkyblockerMod.GSON.toJson(CommitData.CODEC.encodeStart(JsonOps.INSTANCE, commitData).result().orElseThrow(), writer); + } + } + + /** + * Deletes all directories (not files) inside of the {@link #REPO_DIRECTORY} + * @throws IOException + */ + private static void deleteDirectories() throws IOException { + Files.list(REPO_DIRECTORY) + .filter(Files::isDirectory) + .forEach(dir -> { + try { + FileUtils.recursiveDelete(dir); + } catch (Exception e) { + LOGGER.error("[Skyblocker] Encountered an exception while deleting a directory! Path: {}", dir.toAbsolutePath(), e); + } + }); + } + + record CommitData(String commit, long lastUpdated) { + static final Codec<CommitData> CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.STRING.fieldOf("commit").forGetter(CommitData::commit), + Codec.LONG.fieldOf("lastUpdated").forGetter(CommitData::lastUpdated)) + .apply(instance, CommitData::new)); + } +} |