91 lines
2.4 KiB
Kotlin
91 lines
2.4 KiB
Kotlin
package audio.funkwhale.ffa.repositories
|
|
|
|
import android.content.Context
|
|
import audio.funkwhale.ffa.model.CacheItem
|
|
import audio.funkwhale.ffa.utils.AppContext
|
|
import audio.funkwhale.ffa.utils.FFACache
|
|
import kotlinx.coroutines.CoroutineScope
|
|
import kotlinx.coroutines.Dispatchers.IO
|
|
import kotlinx.coroutines.Job
|
|
import kotlinx.coroutines.flow.Flow
|
|
import kotlinx.coroutines.flow.collect
|
|
import kotlinx.coroutines.flow.flow
|
|
import kotlinx.coroutines.flow.flowOn
|
|
import kotlinx.coroutines.flow.map
|
|
import java.io.BufferedReader
|
|
import kotlin.math.ceil
|
|
|
|
interface Upstream<D> {
|
|
fun fetch(size: Int = 0): Flow<Repository.Response<D>>
|
|
}
|
|
|
|
abstract class Repository<D : Any, C : CacheItem<D>> {
|
|
protected val scope: CoroutineScope = CoroutineScope(Job() + IO)
|
|
|
|
enum class Origin(val origin: Int) {
|
|
Cache(0b01),
|
|
Network(0b10)
|
|
}
|
|
|
|
data class Response<D>(val origin: Origin, val data: List<D>, val page: Int, val hasMore: Boolean)
|
|
|
|
abstract val context: Context?
|
|
abstract val cacheId: String?
|
|
abstract val upstream: Upstream<D>
|
|
|
|
open fun cache(data: List<D>): C? = null
|
|
protected open fun uncache(json: String): C? = null
|
|
|
|
fun fetch(
|
|
upstreams: Int = Origin.Cache.origin and Origin.Network.origin,
|
|
size: Int = 0
|
|
): Flow<Response<D>> = flow {
|
|
if (Origin.Cache.origin and upstreams == upstreams) fromCache().collect { emit(it) }
|
|
if (Origin.Network.origin and upstreams == upstreams) fromNetwork(size).collect { emit(it) }
|
|
}
|
|
|
|
private fun fromCache() = flow {
|
|
cacheId?.let { cacheId ->
|
|
FFACache.getLine(context, cacheId)?.let { line ->
|
|
uncache(line)?.let { cache ->
|
|
return@flow emit(
|
|
Response(
|
|
Origin.Cache,
|
|
cache.data,
|
|
ceil(cache.data.size / AppContext.PAGE_SIZE.toDouble()).toInt(),
|
|
false
|
|
)
|
|
)
|
|
}
|
|
}
|
|
|
|
return@flow emit(Response(Origin.Cache, listOf(), 1, false))
|
|
}
|
|
}.flowOn(IO)
|
|
|
|
private fun fromNetwork(size: Int): Flow<Response<D>> = flow {
|
|
upstream
|
|
.fetch(size)
|
|
.map { response ->
|
|
Response(
|
|
Origin.Network,
|
|
onDataFetched(response.data),
|
|
response.page,
|
|
response.hasMore
|
|
)
|
|
}
|
|
.collect { response ->
|
|
emit(
|
|
Response(
|
|
Origin.Network,
|
|
response.data,
|
|
response.page,
|
|
response.hasMore
|
|
)
|
|
)
|
|
}
|
|
}
|
|
|
|
protected open fun onDataFetched(data: List<D>) = data
|
|
}
|