fix: handle more network errors, and large refactors
This commit is contained in:
parent
ce8425d6a7
commit
8c0bff3bc4
8 changed files with 286 additions and 169 deletions
|
|
@ -0,0 +1,48 @@
|
|||
package moe.lava.banksia.util
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import moe.lava.banksia.error
|
||||
|
||||
class CacheMap<K, V>(
|
||||
coroutineScope: CoroutineScope,
|
||||
val expiryMinutes: Int = 5,
|
||||
private val innerMap: MutableMap<K, V> = mutableMapOf()
|
||||
) : MutableMap<K, V> by innerMap {
|
||||
val keyExpiries = mutableMapOf<K, Int>()
|
||||
var counter = 0
|
||||
|
||||
init {
|
||||
coroutineScope.launch {
|
||||
while (true) {
|
||||
delay(60000)
|
||||
counter += 1
|
||||
keyExpiries
|
||||
.filterValues { expiry -> expiry >= counter }
|
||||
.keys
|
||||
.forEach { key ->
|
||||
innerMap.remove(key)
|
||||
keyExpiries.remove(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun put(key: K, value: V): V? {
|
||||
keyExpiries.put(key, counter + expiryMinutes + 1)
|
||||
return innerMap.put(key, value)
|
||||
}
|
||||
|
||||
override fun putAll(from: Map<out K, V>) {
|
||||
keyExpiries.putAll(from.map { it.key to (counter + expiryMinutes + 1) })
|
||||
innerMap.putAll(from)
|
||||
}
|
||||
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
|
||||
get() {
|
||||
error("CacheMap", ".entries accessed, cloning..", IllegalStateException())
|
||||
return this.entries.toMutableSet()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package moe.lava.banksia.util
|
||||
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.AbstractFlow
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.FlowCollector
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import moe.lava.banksia.log
|
||||
import kotlin.experimental.ExperimentalTypeInference
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class LoopFlow<T>(private val block: suspend FlowCollector<T>.() -> Unit) : AbstractFlow<T>() {
|
||||
private var delayMs: Long = 5000
|
||||
private var init: (suspend FlowCollector<T>.() -> Unit)? = null
|
||||
private var waiter: (suspend () -> Unit)? = null
|
||||
|
||||
override suspend fun collectSafely(collector: FlowCollector<T>) {
|
||||
init?.invoke(collector)
|
||||
while (true) {
|
||||
waiter?.invoke()
|
||||
collector.block()
|
||||
delay(delayMs)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun <T> Flow<T>.delayFor(delay: Long) = apply {
|
||||
@Suppress("UnusedFlow")
|
||||
if (this is LoopFlow)
|
||||
this.delayMs = delay;
|
||||
else
|
||||
throw IllegalStateException()
|
||||
}
|
||||
|
||||
fun <T> Flow<T>.initWith(block: suspend FlowCollector<T>.() -> Unit) = apply {
|
||||
@Suppress("UnusedFlow")
|
||||
if (this is LoopFlow)
|
||||
this.init = block;
|
||||
else
|
||||
throw IllegalStateException()
|
||||
}
|
||||
|
||||
fun <T> Flow<T>.waitFor(waiter: suspend () -> Unit) = apply {
|
||||
@Suppress("UnusedFlow")
|
||||
if (this is LoopFlow)
|
||||
this.waiter = waiter;
|
||||
else
|
||||
throw IllegalStateException()
|
||||
}
|
||||
|
||||
fun <T> Flow<T>.waitUntilSubscribed(other: MutableStateFlow<*>) = waitFor {
|
||||
val blocked = other.subscriptionCount.value == 0
|
||||
if (blocked)
|
||||
log("LoopFlow", "blocking flow")
|
||||
other.subscriptionCount.first { it > 0 }
|
||||
if (blocked)
|
||||
log("LoopFlow", "unblocking flow")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTypeInference::class)
|
||||
fun <T> loopFlow(@BuilderInference block: suspend FlowCollector<T>.() -> Unit) = LoopFlow(block)
|
||||
Loading…
Add table
Add a link
Reference in a new issue