Support refreshing instance in NetworkHandlerSelector

This commit is contained in:
Him188 2021-05-31 15:03:12 +08:00
parent 8c0f245da1
commit 00e2d2b77f
4 changed files with 28 additions and 10 deletions

View File

@ -46,6 +46,12 @@ internal abstract class AbstractKeepAliveNetworkHandlerSelector<H : NetworkHandl
final override fun getResumedInstance(): H? = current.value
final override tailrec fun tryResumeInstanceOrCreate(): H {
getResumedInstance()?.let { return it }
refreshInstance()
return tryResumeInstanceOrCreate()
}
final override suspend fun awaitResumeInstance(): H = awaitResumeInstanceImpl(0)
private tailrec suspend fun awaitResumeInstanceImpl(attempted: Int): H {
@ -73,13 +79,17 @@ internal abstract class AbstractKeepAliveNetworkHandlerSelector<H : NetworkHandl
}
}
} else {
synchronized(this) { // avoid concurrent `createInstance()`
if (getResumedInstance() == null) this.current.compareAndSet(null, createInstance())
}
refreshInstance()
awaitResumeInstanceImpl(attempted) // directly retry, does not count for attempts.
}
}
protected open fun refreshInstance() {
synchronized(this) { // avoid concurrent `createInstance()`
if (getResumedInstance() == null) this.current.compareAndSet(null, createInstance())
}
}
companion object {
@JvmField
var DEFAULT_MAX_ATTEMPTS =

View File

@ -23,6 +23,11 @@ internal interface NetworkHandlerSelector<H : NetworkHandler> {
*/
fun getResumedInstance(): H?
/**
* Returns the currently alive [NetworkHandler] or creates a new one.
*/
fun tryResumeInstanceOrCreate(): H
/**
* Returns an alive [NetworkHandler], or suspends the coroutine until the connection has been made again.
*

View File

@ -10,7 +10,7 @@
package net.mamoe.mirai.internal.network.handler.selector
import kotlinx.coroutines.*
import kotlinx.coroutines.selects.SelectClause1
import kotlinx.coroutines.channels.ReceiveChannel
import net.mamoe.mirai.internal.network.handler.NetworkHandler
import net.mamoe.mirai.internal.network.handler.NetworkHandler.State
import net.mamoe.mirai.internal.network.handler.NetworkHandlerContext
@ -44,10 +44,9 @@ internal class SelectorNetworkHandler(
}
override val state: State
get() = selector.getResumedInstance()?.state ?: State.INITIALIZED
override val onStateChanged: SelectClause1<State>
get() = selector.getResumedInstance()?.onStateChanged
?: scope.async { instance().state }.onAwait
get() = selector.tryResumeInstanceOrCreate().state
override val stateChannel: ReceiveChannel<State>
get() = selector.tryResumeInstanceOrCreate().stateChannel
override suspend fun resumeConnection() {
instance() // the selector will resume connection for us.

View File

@ -47,12 +47,16 @@ internal open class TestNetworkHandler(
}
}
}
override fun toString(): String {
return "TestState($correspondingState)"
}
}
@OptIn(TestOnly::class)
fun setState(correspondingState: NetworkHandler.State) {
fun setState(correspondingState: NetworkHandler.State): TestState? {
// `null` means ignore checks. All test states have same type TestState.
setStateImpl(null) { TestState(correspondingState) }
return setStateImpl(null) { TestState(correspondingState) }
}
private val initialState = TestState(NetworkHandler.State.INITIALIZED)