mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-28 02:57:39 +00:00
Improve Rx pipeline
This commit is contained in:
parent
b2e6ba3c4a
commit
c15f80b33f
@ -6,6 +6,7 @@ import com.topjohnwu.magisk.data.database.RepoDao
|
|||||||
import com.topjohnwu.magisk.data.network.GithubApiServices
|
import com.topjohnwu.magisk.data.network.GithubApiServices
|
||||||
import com.topjohnwu.magisk.model.entity.module.Repo
|
import com.topjohnwu.magisk.model.entity.module.Repo
|
||||||
import io.reactivex.Flowable
|
import io.reactivex.Flowable
|
||||||
|
import io.reactivex.Single
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
import se.ansman.kotshi.JsonSerializable
|
import se.ansman.kotshi.JsonSerializable
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -18,19 +19,11 @@ class RepoUpdater(
|
|||||||
private val api: GithubApiServices,
|
private val api: GithubApiServices,
|
||||||
private val repoDB: RepoDao
|
private val repoDB: RepoDao
|
||||||
) {
|
) {
|
||||||
private lateinit var cached: MutableSet<String>
|
|
||||||
|
|
||||||
private val dateFormat: SimpleDateFormat
|
private fun loadRepos(repos: List<GithubRepoInfo>, cached: MutableSet<String>) =
|
||||||
get() {
|
Flowable.fromIterable(repos).map {
|
||||||
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US)
|
|
||||||
format.timeZone = TimeZone.getTimeZone("UTC")
|
|
||||||
return format
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadRepos(repos: List<GithubRepoInfo>) = Flowable.fromIterable(repos)
|
|
||||||
.parallel().runOn(Schedulers.io()).map {
|
|
||||||
it.id to dateFormat.parse(it.pushed_at)!!
|
it.id to dateFormat.parse(it.pushed_at)!!
|
||||||
}.map {
|
}.parallel().runOn(Schedulers.io()).map {
|
||||||
// Skip submission
|
// Skip submission
|
||||||
if (it.first == "submission")
|
if (it.first == "submission")
|
||||||
return@map
|
return@map
|
||||||
@ -42,26 +35,29 @@ class RepoUpdater(
|
|||||||
}.getOrElse { Timber.e(it) }
|
}.getOrElse { Timber.e(it) }
|
||||||
}.sequential()
|
}.sequential()
|
||||||
|
|
||||||
private fun loadPage(page: Int, etag: String = ""): Flowable<Unit> =
|
private fun loadPage(
|
||||||
api.fetchRepos(page, etag).flatMap {
|
cached: MutableSet<String>,
|
||||||
|
page: Int = 1,
|
||||||
|
etag: String = ""
|
||||||
|
): Flowable<Unit> = api.fetchRepos(page, etag).flatMap {
|
||||||
it.error()?.also { throw it }
|
it.error()?.also { throw it }
|
||||||
it.response()?.run {
|
it.response()?.run {
|
||||||
if (code() == HttpURLConnection.HTTP_NOT_MODIFIED)
|
if (code() == HttpURLConnection.HTTP_NOT_MODIFIED)
|
||||||
throw CachedException()
|
return@run Flowable.error<Unit>(CachedException)
|
||||||
|
|
||||||
if (page == 1)
|
if (page == 1)
|
||||||
repoDB.etagKey = headers()[Const.Key.ETAG_KEY].orEmpty().trimEtag()
|
repoDB.etagKey = headers()[Const.Key.ETAG_KEY].orEmpty().trimEtag()
|
||||||
|
|
||||||
val flow = loadRepos(body()!!)
|
val flow = loadRepos(body()!!, cached)
|
||||||
if (headers()[Const.Key.LINK_KEY].orEmpty().contains("next")) {
|
if (headers()[Const.Key.LINK_KEY].orEmpty().contains("next")) {
|
||||||
flow.mergeWith(loadPage(page + 1))
|
flow.mergeWith(loadPage(cached, page + 1))
|
||||||
} else {
|
} else {
|
||||||
flow
|
flow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun forcedReload() = Flowable.fromIterable(cached)
|
private fun forcedReload(cached: MutableSet<String>) = Flowable.fromIterable(cached)
|
||||||
.parallel().runOn(Schedulers.io()).map {
|
.parallel().runOn(Schedulers.io()).map {
|
||||||
runCatching {
|
runCatching {
|
||||||
Repo(it).update()
|
Repo(it).update()
|
||||||
@ -70,22 +66,29 @@ class RepoUpdater(
|
|||||||
|
|
||||||
private fun String.trimEtag() = substring(indexOf('\"'), lastIndexOf('\"') + 1)
|
private fun String.trimEtag() = substring(indexOf('\"'), lastIndexOf('\"') + 1)
|
||||||
|
|
||||||
operator fun invoke(forced: Boolean = false) : Flowable<Unit> {
|
operator fun invoke(forced: Boolean = false) : Single<Unit> {
|
||||||
cached = Collections.synchronizedSet(HashSet(repoDB.repoIDSet))
|
val cached = Collections.synchronizedSet(HashSet(repoDB.repoIDSet))
|
||||||
return loadPage(1, repoDB.etagKey).doOnComplete {
|
return loadPage(cached, etag = repoDB.etagKey).doOnComplete {
|
||||||
repoDB.removeRepos(cached.toList())
|
repoDB.removeRepos(cached.toList())
|
||||||
cached.clear()
|
|
||||||
}.onErrorResumeNext { it: Throwable ->
|
}.onErrorResumeNext { it: Throwable ->
|
||||||
cached.clear()
|
|
||||||
if (it is CachedException) {
|
if (it is CachedException) {
|
||||||
if (forced) forcedReload() else Flowable.empty()
|
if (forced)
|
||||||
|
return@onErrorResumeNext forcedReload(cached)
|
||||||
} else {
|
} else {
|
||||||
Flowable.error(it)
|
Timber.e(it)
|
||||||
}
|
}
|
||||||
|
Flowable.empty()
|
||||||
|
}.collect({}, {_, _ -> })
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val dateFormat: SimpleDateFormat =
|
||||||
|
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US).apply {
|
||||||
|
timeZone = TimeZone.getTimeZone("UTC")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CachedException : Exception()
|
object CachedException : Exception()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonSerializable
|
@JsonSerializable
|
||||||
|
@ -63,9 +63,7 @@ class ModuleViewModel(
|
|||||||
.toList()
|
.toList()
|
||||||
.map { it to itemsInstalled.calculateDiff(it) }
|
.map { it to itemsInstalled.calculateDiff(it) }
|
||||||
.doOnSuccessUi { itemsInstalled.update(it.first, it.second) }
|
.doOnSuccessUi { itemsInstalled.update(it.first, it.second) }
|
||||||
.toFlowable()
|
|
||||||
.flatMap { repoUpdater(force) }
|
.flatMap { repoUpdater(force) }
|
||||||
.collect({}, {_, _ -> })
|
|
||||||
.flattenAsFlowable { repoDB.repos }
|
.flattenAsFlowable { repoDB.repos }
|
||||||
.map { RepoRvItem(it) }
|
.map { RepoRvItem(it) }
|
||||||
.toList()
|
.toList()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user