From e883d0c027e602348416398ba9b14d295ee6b7b4 Mon Sep 17 00:00:00 2001 From: CalMWolfs <94038482+CalMWolfs@users.noreply.github.com> Date: Thu, 17 Oct 2024 05:13:35 +1100 Subject: [PATCH] Backend: Add backup repo (#2673) Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com> --- build.gradle.kts | 8 ++ .../skyhannibuildsystem/DownloadBackupRepo.kt | 34 ++++++ .../skyhanni/data/repo/RepoManager.kt | 114 +++++++++++------- .../hannibal2/skyhanni/test/DebugCommand.kt | 28 ++--- .../utils/repopatterns/RepoPatternManager.kt | 4 +- 5 files changed, 129 insertions(+), 59 deletions(-) create mode 100644 buildSrc/src/main/kotlin/skyhannibuildsystem/DownloadBackupRepo.kt diff --git a/build.gradle.kts b/build.gradle.kts index dde5ac410ed2..31aeef427d1c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,6 +9,7 @@ import net.fabricmc.loom.task.RunGameTask import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import skyhannibuildsystem.ChangelogVerification +import skyhannibuildsystem.DownloadBackupRepo plugins { idea @@ -96,6 +97,12 @@ val headlessLwjgl by configurations.creating { isTransitive = false isVisible = false } + +val includeBackupRepo by tasks.registering(DownloadBackupRepo::class) { + this.outputDirectory.set(layout.buildDirectory.dir("downloadedRepo")) + this.branch = "main" +} + tasks.runClient { this.javaLauncher.set( javaToolchains.launcherFor { @@ -213,6 +220,7 @@ kotlin { // Tasks: tasks.processResources { + from(includeBackupRepo) inputs.property("version", version) filesMatching(listOf("mcmod.info", "fabric.mod.json")) { expand("version" to version) diff --git a/buildSrc/src/main/kotlin/skyhannibuildsystem/DownloadBackupRepo.kt b/buildSrc/src/main/kotlin/skyhannibuildsystem/DownloadBackupRepo.kt new file mode 100644 index 000000000000..f59bf34a8c10 --- /dev/null +++ b/buildSrc/src/main/kotlin/skyhannibuildsystem/DownloadBackupRepo.kt @@ -0,0 +1,34 @@ +package skyhannibuildsystem + +import org.gradle.api.DefaultTask +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.TaskAction +import java.net.URL + +// Code taken from NotEnoughUpdates +abstract class DownloadBackupRepo : DefaultTask() { + + @get:OutputDirectory + abstract val outputDirectory: DirectoryProperty + + @get:Input + abstract var branch: String + + @get:Internal + val repoFile get() = outputDirectory.get().asFile.resolve("assets/skyhanni/repo.zip") + + @TaskAction + fun downloadRepo() { + val downloadUrl = URL("https://github.com/hannibal002/SkyHanni-Repo/archive/refs/heads/$branch.zip") + val file = repoFile + file.parentFile.mkdirs() + file.outputStream().use { out -> + downloadUrl.openStream().use { inp -> + inp.copyTo(out) + } + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/repo/RepoManager.kt b/src/main/java/at/hannibal2/skyhanni/data/repo/RepoManager.kt index babbb2558def..1d81502f3f61 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/repo/RepoManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/repo/RepoManager.kt @@ -2,7 +2,6 @@ package at.hannibal2.skyhanni.data.repo import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.config.ConfigManager -import at.hannibal2.skyhanni.events.DebugDataCollectEvent import at.hannibal2.skyhanni.events.NeuRepositoryReloadEvent import at.hannibal2.skyhanni.events.RepositoryReloadEvent import at.hannibal2.skyhanni.test.command.ErrorManager @@ -26,6 +25,8 @@ import java.io.InputStreamReader import java.io.OutputStreamWriter import java.net.URL import java.nio.charset.StandardCharsets +import java.nio.file.Files +import java.nio.file.StandardCopyOption import java.util.concurrent.CompletableFuture import java.util.concurrent.atomic.AtomicBoolean import kotlin.time.Duration.Companion.minutes @@ -33,10 +34,10 @@ import kotlin.time.Duration.Companion.minutes class RepoManager(private val configLocation: File) { private val gson get() = ConfigManager.gson - private var latestRepoCommit: String? = null val repoLocation: File = File(configLocation, "repo") private var error = false private var lastRepoUpdate = SimpleTimeMark.now() + private var repoDownloadFailed = false companion object { @@ -44,6 +45,7 @@ class RepoManager(private val configLocation: File) { val successfulConstants = mutableListOf() val unsuccessfulConstants = mutableListOf() + var usingBackupRepo = false private var lastConstant: String? = null @@ -62,7 +64,11 @@ class RepoManager(private val configLocation: File) { fun loadRepoInformation() { atomicShouldManuallyReload.set(true) if (config.repoAutoUpdate) { - fetchRepository(false).thenRun(this::reloadRepository) + fetchRepository(false).thenRun { + if (repoDownloadFailed) { + switchToBackupRepo() + } + }.thenRun { reloadRepository() } } else { reloadRepository() } @@ -73,7 +79,10 @@ class RepoManager(private val configLocation: File) { fun updateRepo() { atomicShouldManuallyReload.set(true) checkRepoLocation() - fetchRepository(true).thenRun { this.reloadRepository("Repo updated successfully.") } + fetchRepository(true).thenRun { + if (unsuccessfulConstants.isNotEmpty() || usingBackupRepo) return@thenRun + this.reloadRepository("Repo updated successfully.") + } } fun reloadLocalRepo() { @@ -84,8 +93,8 @@ class RepoManager(private val configLocation: File) { private fun fetchRepository(command: Boolean): CompletableFuture { return CompletableFuture.supplyAsync { try { - val currentCommitJSON: JsonObject? = getJsonFromFile(File(configLocation, "currentCommit.json")) - latestRepoCommit = null + val currentDownloadedCommit = readCurrentCommit() + var latestRepoCommit: String? try { InputStreamReader(URL(getCommitApiUrl()).openStream()) .use { inReader -> @@ -97,13 +106,15 @@ class RepoManager(private val configLocation: File) { e, "Error while loading data from repo", "command" to command, - "currentCommitJSON" to currentCommitJSON, + "currentDownloadedCommit" to currentDownloadedCommit, ) + repoDownloadFailed = true + return@supplyAsync false } - if (latestRepoCommit == null || latestRepoCommit!!.isEmpty()) return@supplyAsync false + val file = File(configLocation, "repo") if (file.exists() && - currentCommitJSON?.get("sha")?.asString == latestRepoCommit && + currentDownloadedCommit == latestRepoCommit && unsuccessfulConstants.isEmpty() && lastRepoUpdate.passedSince() < 1.minutes ) { @@ -114,18 +125,19 @@ class RepoManager(private val configLocation: File) { return@supplyAsync false } lastRepoUpdate = SimpleTimeMark.now() - RepoUtils.recursiveDelete(repoLocation) + repoLocation.mkdirs() val itemsZip = File(repoLocation, "sh-repo-main.zip") - try { - itemsZip.createNewFile() - } catch (e: IOException) { - return@supplyAsync false - } + itemsZip.createNewFile() + val url = URL(getDownloadUrl(latestRepoCommit)) val urlConnection = url.openConnection() urlConnection.connectTimeout = 15000 urlConnection.readTimeout = 30000 + + RepoUtils.recursiveDelete(repoLocation) + repoLocation.mkdirs() + try { urlConnection.getInputStream().use { `is` -> FileUtils.copyInputStreamToFile( @@ -140,19 +152,15 @@ class RepoManager(private val configLocation: File) { "url" to url, "command" to command, ) + repoDownloadFailed = true return@supplyAsync false } RepoUtils.unzipIgnoreFirstFolder( itemsZip.absolutePath, repoLocation.absolutePath, ) - if (currentCommitJSON == null || currentCommitJSON["sha"].asString != latestRepoCommit) { - val newCurrentCommitJSON = JsonObject() - newCurrentCommitJSON.addProperty("sha", latestRepoCommit) - try { - writeJson(newCurrentCommitJSON, File(configLocation, "currentCommit.json")) - } catch (ignored: IOException) { - } + if (currentDownloadedCommit == null || currentDownloadedCommit != latestRepoCommit) { + writeCurrentCommit(latestRepoCommit) } } catch (e: Exception) { ErrorManager.logErrorWithData( @@ -160,7 +168,10 @@ class RepoManager(private val configLocation: File) { "Failed to download SkyHanni Repo", "command" to command, ) + repoDownloadFailed = true } + repoDownloadFailed = false + usingBackupRepo = false true } } @@ -203,28 +214,18 @@ class RepoManager(private val configLocation: File) { return comp } - @SubscribeEvent - fun onDebugDataCollect(event: DebugDataCollectEvent) { - event.title("Repo Status") - - if (unsuccessfulConstants.isEmpty() && successfulConstants.isNotEmpty()) { - event.addIrrelevant("Repo working fine") - return + private fun writeCurrentCommit(commit: String?) { + val newCurrentCommitJSON = JsonObject() + newCurrentCommitJSON.addProperty("sha", commit) + try { + writeJson(newCurrentCommitJSON, File(configLocation, "currentCommit.json")) + } catch (ignored: IOException) { } + } - event.addData { - add("Successful Constants (${successfulConstants.size}):") - - add("Unsuccessful Constants (${unsuccessfulConstants.size}):") - - for ((i, constant) in unsuccessfulConstants.withIndex()) { - add(" - $constant") - if (i == 5) { - add("...") - break - } - } - } + private fun readCurrentCommit(): String? { + val currentCommitJSON: JsonObject? = getJsonFromFile(File(configLocation, "currentCommit.json")) + return currentCommitJSON?.get("sha")?.asString } fun displayRepoStatus(joinEvent: Boolean) { @@ -238,6 +239,7 @@ class RepoManager(private val configLocation: File) { ).asComponent(), ) text.add("§7Repo Auto Update Value: §c${config.repoAutoUpdate}".asComponent()) + text.add("§7Backup Repo Value: §c${usingBackupRepo}".asComponent()) text.add("§7If you have Repo Auto Update turned off, please try turning that on.".asComponent()) text.add("§cUnsuccessful Constants §7(${unsuccessfulConstants.size}):".asComponent()) @@ -248,11 +250,12 @@ class RepoManager(private val configLocation: File) { } return } + val currentCommit = readCurrentCommit() if (unsuccessfulConstants.isEmpty() && successfulConstants.isNotEmpty()) { - ChatUtils.chat("Repo working fine! Commit hash: $latestRepoCommit", prefixColor = "§a") + ChatUtils.chat("Repo working fine! Commit hash: $currentCommit", prefixColor = "§a") return } - ChatUtils.chat("Repo has errors! Commit has: ${latestRepoCommit ?: "null"}", prefixColor = "§c") + ChatUtils.chat("Repo has errors! Commit hash: $currentCommit", prefixColor = "§c") if (successfulConstants.isNotEmpty()) ChatUtils.chat( "Successful Constants §7(${successfulConstants.size}):", prefixColor = "§a", @@ -348,4 +351,27 @@ class RepoManager(private val configLocation: File) { resetRepositoryLocation() } } + + // Code taken from NotEnoughUpdates + private fun switchToBackupRepo() { + usingBackupRepo = true + println("Attempting to switch to backup repo") + + try { + repoLocation.mkdirs() + val destinationFile = File(repoLocation, "sh-repo-main.zip").apply { createNewFile() } + val destinationPath = destinationFile.toPath() + + val inputStream = RepoManager::class.java.classLoader.getResourceAsStream("assets/skyhanni/repo.zip") + ?: throw IOException("Failed to find backup repo") + + Files.copy(inputStream, destinationPath, StandardCopyOption.REPLACE_EXISTING) + RepoUtils.unzipIgnoreFirstFolder(destinationPath.toAbsolutePath().toString(), repoLocation.absolutePath) + writeCurrentCommit("backup-repo") + + println("Successfully switched to backup repo") + } catch (e: Exception) { + ErrorManager.logErrorWithData(e, "Failed to switch to backup repo") + } + } } diff --git a/src/main/java/at/hannibal2/skyhanni/test/DebugCommand.kt b/src/main/java/at/hannibal2/skyhanni/test/DebugCommand.kt index 76b729ae76bd..f464a66ce191 100644 --- a/src/main/java/at/hannibal2/skyhanni/test/DebugCommand.kt +++ b/src/main/java/at/hannibal2/skyhanni/test/DebugCommand.kt @@ -30,15 +30,14 @@ object DebugCommand { if (search.equalsIgnoreColor("all")) { "search for everything:" } else "search '$search':" - } else "no search specified, only showing interesting stuff:" + } else "no search specified, only showing interesting stuff:", ) val event = DebugDataCollectEvent(list, search) // calling default debug stuff player(event) - repoAutoUpdate(event) - repoLocation(event) + repoData(event) globalRender(event) skyblockStatus(event) profileName(event) @@ -144,20 +143,21 @@ object DebugCommand { } } - private fun repoAutoUpdate(event: DebugDataCollectEvent) { - event.title("Repo Auto Update") - if (SkyHanniMod.feature.dev.repo.repoAutoUpdate) { - event.addIrrelevant("normal enabled") - } else { - event.addData("The repo does not auto update because auto update is disabled!") + private fun repoData(event: DebugDataCollectEvent) { + event.title("Repo Information") + event.addIrrelevant { + add(" repoAutoUpdate: ${SkyHanniMod.feature.dev.repo.repoAutoUpdate}") + add(" usingBackupRepo: ${RepoManager.usingBackupRepo}") + add(" repoLocation: '${RepoManager.getRepoLocation()}'") + if (RepoManager.unsuccessfulConstants.isNotEmpty()) { + add(" unsuccessful constants:") + for (constant in RepoManager.unsuccessfulConstants) { + add(" - $constant") + } + } } } - private fun repoLocation(event: DebugDataCollectEvent) { - event.title("Repo Location") - event.addIrrelevant("repo location: '${RepoManager.getRepoLocation()}'") - } - private fun player(event: DebugDataCollectEvent) { event.title("Player") event.addIrrelevant { diff --git a/src/main/java/at/hannibal2/skyhanni/utils/repopatterns/RepoPatternManager.kt b/src/main/java/at/hannibal2/skyhanni/utils/repopatterns/RepoPatternManager.kt index 57a5852a3a81..505793300559 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/repopatterns/RepoPatternManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/repopatterns/RepoPatternManager.kt @@ -4,6 +4,7 @@ import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.config.ConfigManager import at.hannibal2.skyhanni.config.features.dev.RepoPatternConfig +import at.hannibal2.skyhanni.data.repo.RepoManager import at.hannibal2.skyhanni.events.ConfigLoadEvent import at.hannibal2.skyhanni.events.LorenzEvent import at.hannibal2.skyhanni.events.RepositoryReloadEvent @@ -78,7 +79,8 @@ object RepoPatternManager { } } - val localLoading: Boolean get() = config.forceLocal.get() || (!insideTest && PlatformUtils.isDevEnvironment) + private val localLoading: Boolean + get() = config.forceLocal.get() || (!insideTest && PlatformUtils.isDevEnvironment) || RepoManager.usingBackupRepo private val logger = LogManager.getLogger("SkyHanni")