implement fileystem asset manager

3
Timo Bryant 2024-01-02 22:50:52 +01:00
parent 949f87800a
commit 4ae5c3bf58
5 changed files with 93 additions and 1 deletions

View File

@ -1,3 +1,5 @@
dependencies { dependencies {
api(project(":libraries:core-api")) api(project(":libraries:core-api"))
// used for contentType
api("io.ktor:ktor-http-jvm:2.3.7")
} }

View File

@ -0,0 +1,83 @@
package de.itkl.assetmanager.implementation
import de.itkl.assetmanager.interfaces.AssetManager
import de.itkl.assetmanager.interfaces.Assets
import de.itkl.core_api.interfaces.Resource
import de.itkl.core_api.interfaces.ResourceFactory
import io.github.oshai.kotlinlogging.KotlinLogging
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.stream.consumeAsFlow
import kotlinx.coroutines.withContext
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.io.path.deleteExisting
import kotlin.io.path.exists
import kotlin.io.path.outputStream
private val Log = KotlinLogging.logger { }
class FilesystemAssetManager : AssetManager {
override suspend fun assets(name: String): Assets {
val path = createAssetsPath(name)
withContext(Dispatchers.IO) {
Files.createDirectories(path)
}
return FilesystemAssets(path)
}
override suspend fun delete(name: String) {
val path = createAssetsPath(name)
withContext(Dispatchers.IO) {
Files.delete(path)
}
}
private fun createAssetsPath(name: String): Path {
return Paths.get("$name.assets.d").toAbsolutePath()
}
}
class FilesystemAssets(private val baseDir: Path) : Assets, KoinComponent {
private val resourceFactory by inject<ResourceFactory>()
override suspend fun store(resource: Resource) {
val destination = baseDir.resolve(resource.filename)
resource.read().use { source ->
destination.outputStream().use {output ->
withContext(Dispatchers.IO) {
source.copyTo(output)
}
}
}
}
override suspend fun retrieve(name: String): Resource? {
val destination = baseDir.resolve(name)
if (!destination.exists()) {
return null
}
val resource = resourceFactory.file(destination)
return resource
}
override suspend fun delete(name: String) {
val destination = baseDir.resolve(name)
withContext(Dispatchers.IO) {
destination.deleteExisting()
}
}
override suspend fun collect(collector: FlowCollector<Resource>) {
val flow = withContext(Dispatchers.IO) {
Files.list(baseDir).consumeAsFlow()
}
.map { path -> resourceFactory.file(path) }
collector.emitAll(flow)
}
}

View File

@ -1,4 +1,5 @@
package de.itkl.assetmanager.interfaces package de.itkl.assetmanager.interfaces
interface AssetManager { interface AssetManager {
fun assets(name: String): Assets suspend fun assets(name: String): Assets
suspend fun delete(name: String)
} }

View File

@ -15,6 +15,7 @@ interface Resource {
val file: File? val file: File?
val path: Path? val path: Path?
fun read(): InputStream fun read(): InputStream
} }
/** /**

View File

@ -5,10 +5,15 @@ import de.itkl.core_api.implementation.ProgressResource
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
import java.io.File import java.io.File
import java.nio.file.Path
class ResourceFactory : KoinComponent { class ResourceFactory : KoinComponent {
private val progressBarFactory by inject<ProgressBarFactory>() private val progressBarFactory by inject<ProgressBarFactory>()
fun file(path: Path): Resource {
return file(path.toFile())
}
fun file(file: File): Resource { fun file(file: File): Resource {
val resource = FileResource(file) val resource = FileResource(file)
return ProgressResource(resource, progressBarFactory) return ProgressResource(resource, progressBarFactory)