mirror of
				https://github.com/packwiz/packwiz-installer.git
				synced 2025-11-04 12:34:31 +01:00 
			
		
		
		
	WIP task system with lazy evaluation
This commit is contained in:
		@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,3 @@
 | 
			
		||||
package link.infra.packwiz.installer.task
 | 
			
		||||
 | 
			
		||||
data class CacheKey<T>(val key: String, val version: Int)
 | 
			
		||||
@@ -0,0 +1,22 @@
 | 
			
		||||
package link.infra.packwiz.installer.task
 | 
			
		||||
 | 
			
		||||
import kotlin.reflect.KProperty
 | 
			
		||||
 | 
			
		||||
class CacheManager {
 | 
			
		||||
	class CacheValue<T> {
 | 
			
		||||
		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 <T> get(cacheKey: CacheKey<T>): CacheValue<T> {
 | 
			
		||||
		return CacheValue()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								src/main/kotlin/link/infra/packwiz/installer/task/Task.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/main/kotlin/link/infra/packwiz/installer/task/Task.kt
									
									
									
									
									
										Normal file
									
								
							@@ -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<T>(protected val ctx: TaskContext): TaskInput<T> {
 | 
			
		||||
	// TODO: lazy wrapper for fallible results
 | 
			
		||||
	// TODO: multithreaded fanout subclass/helper
 | 
			
		||||
 | 
			
		||||
	protected fun <T> wasUpdated(value: KMutableProperty0<T>, newValue: T): Boolean {
 | 
			
		||||
		if (value.get() == newValue) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		value.set(newValue)
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -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<T>(val result: T, val upToDate: Boolean)
 | 
			
		||||
@@ -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()
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,29 @@
 | 
			
		||||
package link.infra.packwiz.installer.task
 | 
			
		||||
 | 
			
		||||
import kotlin.reflect.KProperty
 | 
			
		||||
 | 
			
		||||
interface TaskInput<T> {
 | 
			
		||||
	/**
 | 
			
		||||
	 * 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 <T> raw(value: T): TaskInput<T> {
 | 
			
		||||
			return object: TaskInput<T> {
 | 
			
		||||
				override val value = value
 | 
			
		||||
				override val upToDate: Boolean
 | 
			
		||||
					get() = false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -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)
 | 
			
		||||
@@ -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<PackwizV1PackFile>(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<Hash>("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<String, String>? = 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
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user