Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend: Add backup repo #2673

Merged
merged 18 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down
34 changes: 34 additions & 0 deletions buildSrc/src/main/kotlin/skyhannibuildsystem/DownloadBackupRepo.kt
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
}
114 changes: 70 additions & 44 deletions src/main/java/at/hannibal2/skyhanni/data/repo/RepoManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -26,24 +25,27 @@ 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

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 {

private val config get() = SkyHanniMod.feature.dev.repo

val successfulConstants = mutableListOf<String>()
val unsuccessfulConstants = mutableListOf<String>()
var usingBackupRepo = false

private var lastConstant: String? = null

Expand All @@ -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()
}
Expand All @@ -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() {
Expand All @@ -84,8 +93,8 @@ class RepoManager(private val configLocation: File) {
private fun fetchRepository(command: Boolean): CompletableFuture<Boolean> {
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 ->
Expand All @@ -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
) {
Expand All @@ -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(
Expand All @@ -140,27 +152,26 @@ 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(
e,
"Failed to download SkyHanni Repo",
"command" to command,
)
repoDownloadFailed = true
}
repoDownloadFailed = false
usingBackupRepo = false
true
}
}
Expand Down Expand Up @@ -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) {
Expand All @@ -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())

Expand All @@ -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",
Expand Down Expand Up @@ -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")
}
}
}
28 changes: 14 additions & 14 deletions src/main/java/at/hannibal2/skyhanni/test/DebugCommand.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")

Expand Down
Loading