aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/moe/nea/notenoughupdates/repo
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/moe/nea/notenoughupdates/repo')
-rw-r--r--src/main/kotlin/moe/nea/notenoughupdates/repo/ItemCache.kt5
-rw-r--r--src/main/kotlin/moe/nea/notenoughupdates/repo/RepoDownloadManager.kt121
-rw-r--r--src/main/kotlin/moe/nea/notenoughupdates/repo/RepoManager.kt31
3 files changed, 147 insertions, 10 deletions
diff --git a/src/main/kotlin/moe/nea/notenoughupdates/repo/ItemCache.kt b/src/main/kotlin/moe/nea/notenoughupdates/repo/ItemCache.kt
index aa93fec..893b1c0 100644
--- a/src/main/kotlin/moe/nea/notenoughupdates/repo/ItemCache.kt
+++ b/src/main/kotlin/moe/nea/notenoughupdates/repo/ItemCache.kt
@@ -4,6 +4,7 @@ import com.mojang.serialization.Dynamic
import io.github.moulberry.repo.IReloadable
import io.github.moulberry.repo.NEURepository
import io.github.moulberry.repo.data.NEUItem
+import moe.nea.notenoughupdates.NotEnoughUpdates
import moe.nea.notenoughupdates.util.LegacyTagParser
import moe.nea.notenoughupdates.util.appendLore
import net.minecraft.nbt.CompoundTag
@@ -37,7 +38,7 @@ object ItemCache : IReloadable {
2975
).value as CompoundTag
} catch (e: Exception) {
- e.printStackTrace()
+ NotEnoughUpdates.logger.error("Failed to datafixer an item", e)
isFlawless = false
null
}
@@ -46,7 +47,7 @@ object ItemCache : IReloadable {
val oldItemTag = get10809CompoundTag()
val modernItemTag = oldItemTag.transformFrom10809ToModern()
?: return ItemStack(Items.PAINTING).apply {
- setHoverName(Component.literal(this@asItemStackNow.displayName))
+ hoverName = Component.literal(this@asItemStackNow.displayName)
appendLore(listOf(Component.literal("Exception rendering item: $skyblockItemId")))
}
val itemInstance = ItemStack.of(modernItemTag)
diff --git a/src/main/kotlin/moe/nea/notenoughupdates/repo/RepoDownloadManager.kt b/src/main/kotlin/moe/nea/notenoughupdates/repo/RepoDownloadManager.kt
index 47b2878..977c035 100644
--- a/src/main/kotlin/moe/nea/notenoughupdates/repo/RepoDownloadManager.kt
+++ b/src/main/kotlin/moe/nea/notenoughupdates/repo/RepoDownloadManager.kt
@@ -1,17 +1,122 @@
package moe.nea.notenoughupdates.repo
+import io.ktor.client.call.*
+import io.ktor.client.request.*
+import io.ktor.client.statement.*
+import io.ktor.utils.io.jvm.nio.*
+import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.Dispatchers.IO
+import kotlinx.coroutines.withContext
+import kotlinx.serialization.Serializable
import moe.nea.notenoughupdates.NotEnoughUpdates
+import moe.nea.notenoughupdates.NotEnoughUpdates.logger
+import moe.nea.notenoughupdates.util.iterate
+import java.io.IOException
+import java.nio.file.Files
+import java.nio.file.Path
+import java.nio.file.StandardOpenOption
+import java.util.zip.ZipInputStream
+import kotlin.io.path.*
+
object RepoDownloadManager {
val repoSavedLocation = NotEnoughUpdates.DATA_DIR.resolve("repo-extracted")
- val repoMetadataLocation = NotEnoughUpdates.DATA_DIR.resolve("loaded-repo.json")
-
- data class RepoMetadata(
- var latestCommit: String,
- var user: String,
- var repository: String,
- var branch: String,
- )
+ val repoMetadataLocation = NotEnoughUpdates.DATA_DIR.resolve("loaded-repo-sha.txt")
+
+ val user = "NotEnoughUpdates"
+ val repo = "NotEnoughUpdates-REPO"
+ val branch = "dangerous"
+
+ private fun loadSavedVersionHash(): String? =
+ if (repoSavedLocation.exists()) {
+ if (repoMetadataLocation.exists()) {
+ try {
+ repoMetadataLocation.readText().trim()
+ } catch (e: IOException) {
+ null
+ }
+ } else {
+ null
+ }
+ } else null
+
+ private fun saveVersionHash(versionHash: String) {
+ latestSavedVersionHash = versionHash
+ repoMetadataLocation.writeText(versionHash)
+ }
+
+ var latestSavedVersionHash: String? = loadSavedVersionHash()
+ private set
+
+ @Serializable
+ private class GithubCommitsResponse(val sha: String)
+
+ private suspend fun requestLatestGithubSha(): String? {
+ val response =
+ NotEnoughUpdates.httpClient.get("https://api.github.com/repos/$user/$repo/commits/$branch")
+ if (response.status.value != 200) {
+ return null
+ }
+ return response.body<GithubCommitsResponse>().sha
+ }
+
+ private suspend fun downloadGithubArchive(url: String): Path = withContext(IO) {
+ val response = NotEnoughUpdates.httpClient.get(url)
+ val targetFile = Files.createTempFile("notenoughupdates-repo", ".zip")
+ val outputChannel = Files.newByteChannel(targetFile, StandardOpenOption.CREATE, StandardOpenOption.WRITE)
+ response.bodyAsChannel().copyTo(outputChannel)
+ targetFile
+ }
+
+ /**
+ * Downloads the latest repository from github, setting [latestSavedVersionHash].
+ * @return true, if an update was performed, false, otherwise (no update needed, or wasn't able to complete update)
+ */
+ suspend fun downloadUpdate(): Boolean = withContext(CoroutineName("Repo Update Check")) {
+ val latestSha = requestLatestGithubSha()
+ if (latestSha == null) {
+ logger.warn("Could not request github API to retrieve latest REPO sha.")
+ return@withContext false
+ }
+ val currentSha = loadSavedVersionHash()
+ if (latestSha != currentSha) {
+ val requestUrl = "https://github.com/$user/$repo/archive/$latestSha.zip"
+ logger.info("Planning to upgrade repository from $currentSha to $latestSha from $requestUrl")
+ val zipFile = downloadGithubArchive(requestUrl)
+ logger.info("Download repository zip file to $zipFile. Deleting old repository")
+ withContext(IO) { repoSavedLocation.deleteIfExists() }
+ logger.info("Extracting new repository")
+ withContext(IO) { extractNewRepository(zipFile) }
+ logger.info("Repository loaded on disk.")
+ saveVersionHash(latestSha)
+ return@withContext true
+ } else {
+ logger.debug("Repository on latest sha $currentSha. Not performing update")
+ return@withContext false
+ }
+ }
+
+ private fun extractNewRepository(zipFile: Path) {
+ repoSavedLocation.createDirectories()
+ ZipInputStream(zipFile.inputStream()).use { cis ->
+ while (true) {
+ val entry = cis.nextEntry ?: break
+ if (entry.isDirectory) continue
+ val extractedLocation =
+ repoSavedLocation.resolve(
+ entry.name.substringAfter('/', missingDelimiterValue = "")
+ )
+ if (repoSavedLocation !in extractedLocation.iterate { it.parent }) {
+ logger.error("Not Enough Updates detected an invalid zip file. This is a potential security risk, please report this in the Moulberry discord.")
+ throw RuntimeException("Not Enough Updates detected an invalid zip file. This is a potential security risk, please report this in the Moulberry discord.")
+ }
+ extractedLocation.parent.createDirectories()
+ cis.copyTo(extractedLocation.outputStream())
+ cis.closeEntry()
+ }
+ }
+ }
+
}
diff --git a/src/main/kotlin/moe/nea/notenoughupdates/repo/RepoManager.kt b/src/main/kotlin/moe/nea/notenoughupdates/repo/RepoManager.kt
new file mode 100644
index 0000000..f3d53e8
--- /dev/null
+++ b/src/main/kotlin/moe/nea/notenoughupdates/repo/RepoManager.kt
@@ -0,0 +1,31 @@
+package moe.nea.notenoughupdates.repo
+
+import io.github.moulberry.repo.NEURepository
+import kotlinx.coroutines.launch
+import moe.nea.notenoughupdates.NotEnoughUpdates
+import moe.nea.notenoughupdates.NotEnoughUpdates.logger
+import net.minecraft.client.Minecraft
+import net.minecraft.network.protocol.game.ClientboundUpdateRecipesPacket
+
+object RepoManager {
+
+
+ val neuRepo: NEURepository = NEURepository.of(RepoDownloadManager.repoSavedLocation).apply {
+ registerReloadListener(ItemCache)
+ registerReloadListener {
+ if (Minecraft.getInstance().connection?.handleUpdateRecipes(ClientboundUpdateRecipesPacket(mutableListOf())) == null) {
+ logger.warn("Failed to issue a ClientboundUpdateRecipesPacket (to reload REI). This may lead to an outdated item list.")
+ }
+ }
+ }
+
+
+ fun launchAsyncUpdate() {
+ NotEnoughUpdates.coroutineScope.launch {
+ if (RepoDownloadManager.downloadUpdate()) {
+ neuRepo.reload()
+ }
+ }
+ }
+
+}