diff --git a/build.gradle.kts b/build.gradle.kts index 64b6723..0ba42d5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -35,6 +35,7 @@ dependencies { implementation("com.squareup.okio:okio:3.0.0") implementation(kotlin("stdlib-jdk8")) implementation("com.squareup.okhttp3:okhttp:4.9.3") + implementation("com.michael-bull.kotlin-result:kotlin-result:1.1.14") } application { diff --git a/src/main/kotlin/link/infra/packwiz/installer/target/path/PackwizPath.kt b/src/main/kotlin/link/infra/packwiz/installer/target/path/PackwizPath.kt index 37e5023..b7a1fe6 100644 --- a/src/main/kotlin/link/infra/packwiz/installer/target/path/PackwizPath.kt +++ b/src/main/kotlin/link/infra/packwiz/installer/target/path/PackwizPath.kt @@ -88,6 +88,8 @@ class PackwizPath(path: String, base: Base) { * @throws RequestException */ fun source(path: String, clientHolder: ClientHolder): BufferedSource + + operator fun div(path: String) = PackwizPath(path, this) } interface SinkableBase: Base { diff --git a/src/main/kotlin/link/infra/packwiz/installer/task/CacheKey.kt b/src/main/kotlin/link/infra/packwiz/installer/task/CacheKey.kt new file mode 100644 index 0000000..df5af1c --- /dev/null +++ b/src/main/kotlin/link/infra/packwiz/installer/task/CacheKey.kt @@ -0,0 +1,3 @@ +package link.infra.packwiz.installer.task + +data class CacheKey(val key: String, val version: Int) \ No newline at end of file diff --git a/src/main/kotlin/link/infra/packwiz/installer/task/CacheManager.kt b/src/main/kotlin/link/infra/packwiz/installer/task/CacheManager.kt new file mode 100644 index 0000000..9fa75a3 --- /dev/null +++ b/src/main/kotlin/link/infra/packwiz/installer/task/CacheManager.kt @@ -0,0 +1,22 @@ +package link.infra.packwiz.installer.task + +import kotlin.reflect.KProperty + +class CacheManager { + class CacheValue { + operator fun getValue(thisVal: Any?, property: KProperty<*>): T { + TODO("Not yet implemented") + } + + operator fun setValue(thisVal: Any?, property: KProperty<*>, value: T) { + TODO("Not yet implemented") + } + + } + + operator fun get(cacheKey: CacheKey): CacheValue { + return CacheValue() + } + + +} \ No newline at end of file diff --git a/src/main/kotlin/link/infra/packwiz/installer/task/Task.kt b/src/main/kotlin/link/infra/packwiz/installer/task/Task.kt new file mode 100644 index 0000000..80c92b1 --- /dev/null +++ b/src/main/kotlin/link/infra/packwiz/installer/task/Task.kt @@ -0,0 +1,20 @@ +package link.infra.packwiz.installer.task + +import kotlin.reflect.KMutableProperty0 + +// TODO: task processing on 1 background thread; actual resolving of values calls out to a thread group +// TODO: progress bar is updated from each of these tasks +// TODO: have everything be lazy so there's no need to determine task ordering upfront? a bit like rust async - task results must be queried to occur + +abstract class Task(protected val ctx: TaskContext): TaskInput { + // TODO: lazy wrapper for fallible results + // TODO: multithreaded fanout subclass/helper + + protected fun wasUpdated(value: KMutableProperty0, newValue: T): Boolean { + if (value.get() == newValue) { + return false + } + value.set(newValue) + return true + } +} \ No newline at end of file diff --git a/src/main/kotlin/link/infra/packwiz/installer/task/TaskCombinedResult.kt b/src/main/kotlin/link/infra/packwiz/installer/task/TaskCombinedResult.kt new file mode 100644 index 0000000..1ef5160 --- /dev/null +++ b/src/main/kotlin/link/infra/packwiz/installer/task/TaskCombinedResult.kt @@ -0,0 +1,6 @@ +package link.infra.packwiz.installer.task + +/** + * An object for storing results where result and upToDate are calculated simultaneously + */ +data class TaskCombinedResult(val result: T, val upToDate: Boolean) \ No newline at end of file diff --git a/src/main/kotlin/link/infra/packwiz/installer/task/TaskContext.kt b/src/main/kotlin/link/infra/packwiz/installer/task/TaskContext.kt new file mode 100644 index 0000000..0a7cb06 --- /dev/null +++ b/src/main/kotlin/link/infra/packwiz/installer/task/TaskContext.kt @@ -0,0 +1,12 @@ +package link.infra.packwiz.installer.task + +import link.infra.packwiz.installer.target.ClientHolder + +class TaskContext { + // TODO: thread pools, protocol roots + // TODO: cache management + + val cache = CacheManager() + + val clients = ClientHolder() +} \ No newline at end of file diff --git a/src/main/kotlin/link/infra/packwiz/installer/task/TaskInput.kt b/src/main/kotlin/link/infra/packwiz/installer/task/TaskInput.kt new file mode 100644 index 0000000..9d2ffc2 --- /dev/null +++ b/src/main/kotlin/link/infra/packwiz/installer/task/TaskInput.kt @@ -0,0 +1,29 @@ +package link.infra.packwiz.installer.task + +import kotlin.reflect.KProperty + +interface TaskInput { + /** + * The value of this task input. May be lazily evaluated; must be threadsafe. + */ + val value: T + + /** + * True if the effective value of this input has changed since the task was last run. + * Doesn't require evaluation of the input value; should use cached data if possible. + * May be lazily evaluated; must be threadsafe. + */ + val upToDate: Boolean + + operator fun getValue(thisVal: Any?, property: KProperty<*>): T = value + + companion object { + fun raw(value: T): TaskInput { + return object: TaskInput { + override val value = value + override val upToDate: Boolean + get() = false + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/link/infra/packwiz/installer/task/formats/packwizv1/PackwizV1PackFile.kt b/src/main/kotlin/link/infra/packwiz/installer/task/formats/packwizv1/PackwizV1PackFile.kt new file mode 100644 index 0000000..d01ff3c --- /dev/null +++ b/src/main/kotlin/link/infra/packwiz/installer/task/formats/packwizv1/PackwizV1PackFile.kt @@ -0,0 +1,6 @@ +package link.infra.packwiz.installer.task.formats.packwizv1 + +import link.infra.packwiz.installer.metadata.hash.Hash +import link.infra.packwiz.installer.target.path.PackwizPath + +data class PackwizV1PackFile(val name: String, val indexPath: PackwizPath, val indexHash: Hash) diff --git a/src/main/kotlin/link/infra/packwiz/installer/task/formats/packwizv1/PackwizV1PackTomlTask.kt b/src/main/kotlin/link/infra/packwiz/installer/task/formats/packwizv1/PackwizV1PackTomlTask.kt new file mode 100644 index 0000000..846a4e9 --- /dev/null +++ b/src/main/kotlin/link/infra/packwiz/installer/task/formats/packwizv1/PackwizV1PackTomlTask.kt @@ -0,0 +1,47 @@ +package link.infra.packwiz.installer.task.formats.packwizv1 + +import com.google.gson.annotations.SerializedName +import com.moandjiezana.toml.Toml +import link.infra.packwiz.installer.metadata.hash.Hash +import link.infra.packwiz.installer.metadata.hash.HashUtils +import link.infra.packwiz.installer.target.path.PackwizPath +import link.infra.packwiz.installer.task.CacheKey +import link.infra.packwiz.installer.task.Task +import link.infra.packwiz.installer.task.TaskCombinedResult +import link.infra.packwiz.installer.task.TaskContext + +class PackwizV1PackTomlTask(ctx: TaskContext, val path: PackwizPath): Task(ctx) { + // TODO: make hierarchically defined by caller? - then changing the pack format type doesn't leave junk in the cache + private var cache by ctx.cache[CacheKey("packwiz.v1.packtoml.hash", 1)] + + private class PackFile { + var name: String? = null + var index: IndexFileLoc? = null + + class IndexFileLoc { + var file: String? = null + @SerializedName("hash-format") + var hashFormat: String? = null + var hash: String? = null + } + + var versions: Map? = null + } + + private val internalResult by lazy { + // TODO: query, parse JSON + val packFile = Toml().read(path.source(ctx.clients).inputStream()).to(PackFile::class.java) + + val resolved = PackwizV1PackFile(packFile.name ?: throw RuntimeException("Name required"), // TODO: better exception handling + path.resolve(packFile.index?.file ?: throw RuntimeException("File required")), + HashUtils.getHash(packFile.index?.hashFormat ?: throw RuntimeException("Hash format required"), + packFile.index?.hash ?: throw RuntimeException("Hash required")) + ) + val hash = HashUtils.getHash("sha256", "whatever was just read") + + TaskCombinedResult(resolved, wasUpdated(::cache, hash)) + } + + override val value by internalResult::result + override val upToDate by internalResult::upToDate +} \ No newline at end of file diff --git a/src/main/resources/META-INF/LICENSES.md b/src/main/resources/META-INF/LICENSES.md index a412b3b..1afe3fa 100644 --- a/src/main/resources/META-INF/LICENSES.md +++ b/src/main/resources/META-INF/LICENSES.md @@ -9,6 +9,7 @@ packwiz-installer itself is under the MIT license ([Source](https://github.com/p - Jetbrains Annotations 13.0: Apache 2.0 ([Source](https://github.com/JetBrains/java-annotations)) - Kotlin Standard Library 1.6.10: Apache 2.0 ([Source](https://github.com/JetBrains/kotlin)) - toml4j 0.7.2: MIT ([Source](https://github.com/mwanji/toml4j)) + ## Associated notices