mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-21 10:42:25 +08:00
Add AbstractKeepAliveNetworkHandlerSelectorTest
This commit is contained in:
parent
382c351e08
commit
90f5e27b5f
@ -27,7 +27,8 @@ import java.util.concurrent.CancellationException
|
||||
* Immutable context for [NetworkHandler]
|
||||
*/
|
||||
internal interface NetworkHandlerContext {
|
||||
val bot: QQAndroidBot
|
||||
val bot: QQAndroidBot // // TODO: 2021/4/16 this is bad, making it difficult to write unit tests.
|
||||
// however migration requires a major change.
|
||||
|
||||
val logger: MiraiLogger
|
||||
val ssoContext: SsoContext
|
||||
|
@ -10,7 +10,9 @@
|
||||
package net.mamoe.mirai.internal.network.handler
|
||||
|
||||
import kotlinx.atomicfu.atomic
|
||||
import net.mamoe.mirai.internal.network.handler.NetworkHandler.State
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
|
||||
/**
|
||||
* A proxy to [NetworkHandler] that delegates calls to instance returned by [NetworkHandlerSelector.awaitResumeInstance].
|
||||
@ -26,8 +28,8 @@ internal class SelectorNetworkHandler(
|
||||
) : NetworkHandler {
|
||||
private suspend inline fun instance(): NetworkHandler = selector.awaitResumeInstance()
|
||||
|
||||
override val state: NetworkHandler.State
|
||||
get() = selector.getResumedInstance()?.state ?: NetworkHandler.State.INITIALIZED
|
||||
override val state: State
|
||||
get() = selector.getResumedInstance()?.state ?: State.INITIALIZED
|
||||
|
||||
override suspend fun resumeConnection() {
|
||||
instance() // the selector will resume connection for us.
|
||||
@ -80,6 +82,11 @@ internal interface NetworkHandlerSelector<H : NetworkHandler> {
|
||||
internal abstract class AbstractKeepAliveNetworkHandlerSelector<H : NetworkHandler> : NetworkHandlerSelector<H> {
|
||||
private val current = atomic<H?>(null)
|
||||
|
||||
@TestOnly
|
||||
internal fun setCurrent(h: H) {
|
||||
current.value = h
|
||||
}
|
||||
|
||||
protected abstract fun createInstance(): H
|
||||
|
||||
final override fun getResumedInstance(): H? = current.value
|
||||
@ -89,14 +96,16 @@ internal abstract class AbstractKeepAliveNetworkHandlerSelector<H : NetworkHandl
|
||||
val current = getResumedInstance()
|
||||
return if (current != null) {
|
||||
when (current.state) {
|
||||
NetworkHandler.State.OK -> current
|
||||
NetworkHandler.State.CLOSED -> {
|
||||
State.CLOSED -> {
|
||||
this.current.compareAndSet(current, null) // invalidate the instance and try again.
|
||||
awaitResumeInstance()
|
||||
awaitResumeInstance() // will create new instance.
|
||||
}
|
||||
else -> {
|
||||
current.resumeConnection() // try to advance state.
|
||||
awaitResumeInstance()
|
||||
State.CONNECTING,
|
||||
State.CONNECTION_LOST,
|
||||
State.INITIALIZED,
|
||||
State.OK -> {
|
||||
current.resumeConnection()
|
||||
return current
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -77,7 +77,8 @@ internal class ServerList(
|
||||
|157.255.13.77:14000, 120.232.18.27:443,
|
||||
|183.3.235.162:14000, 163.177.89.195:443, 183.232.94.44:80,
|
||||
|203.205.255.224:8080, 203.205.255.221:8080""".trimMargin()
|
||||
.split(", ", "\n").filterNot(String::isBlank)
|
||||
.splitToSequence(",").filterNot(String::isBlank)
|
||||
.map { it.trim() }
|
||||
.map {
|
||||
val host = it.substringBefore(':')
|
||||
val port = it.substringAfter(':').toInt()
|
||||
|
@ -25,15 +25,15 @@ import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
|
||||
import net.mamoe.mirai.internal.utils.crypto.TEA
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.network.*
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.BotConfiguration.MiraiProtocol
|
||||
import net.mamoe.mirai.utils.DeviceInfo
|
||||
import net.mamoe.mirai.utils.LoginSolver
|
||||
import net.mamoe.mirai.utils.info
|
||||
import net.mamoe.mirai.utils.withExceptionCollector
|
||||
import java.io.File
|
||||
|
||||
internal interface SsoContext {
|
||||
var client: QQAndroidClient
|
||||
val configuration: BotConfiguration
|
||||
val loginSessionAware: LoginSessionAware get() = client
|
||||
val accountSecrets: AccountSecrets get() = client
|
||||
}
|
||||
|
||||
internal class SsoController(
|
||||
@ -42,7 +42,7 @@ internal class SsoController(
|
||||
) {
|
||||
@Throws(LoginFailedException::class)
|
||||
suspend fun login() = withExceptionCollector {
|
||||
if (bot.client.wLoginSigInfoInitialized) {
|
||||
if (ssoContext.accountSecrets.wLoginSigInfoInitialized) {
|
||||
kotlin.runCatching {
|
||||
fastLogin()
|
||||
}.onFailure { e ->
|
||||
@ -181,6 +181,7 @@ internal class SsoController(
|
||||
|
||||
}
|
||||
|
||||
@Suppress("unused") // false positive
|
||||
internal fun initClient() {
|
||||
val device = configuration.deviceInfo?.invoke(bot) ?: DeviceInfo.random()
|
||||
ssoContext.client = QQAndroidClient(
|
||||
@ -188,7 +189,7 @@ internal class SsoController(
|
||||
device = device,
|
||||
accountSecrets = loadSecretsFromCacheOrCreate(device)
|
||||
).apply {
|
||||
_bot = bot
|
||||
_bot = this@SsoController.bot
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,7 +202,7 @@ internal class SsoController(
|
||||
// TODO: 2021/4/14 extract a cache service
|
||||
|
||||
private val cacheDir: File by lazy {
|
||||
configuration.workingDir.resolve(bot.configuration.cacheDir).apply { mkdirs() }
|
||||
configuration.workingDir.resolve(ssoContext.configuration.cacheDir).apply { mkdirs() }
|
||||
}
|
||||
private val accountSecretsFile: File by lazy {
|
||||
cacheDir.resolve("account.secrets")
|
||||
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.network.handler
|
||||
|
||||
import net.mamoe.mirai.internal.network.handler.NetworkHandler.State
|
||||
import net.mamoe.mirai.internal.test.runBlockingUnit
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.test.*
|
||||
import kotlin.time.seconds
|
||||
|
||||
private class TestSelector(val createInstance0: () -> NetworkHandler) :
|
||||
AbstractKeepAliveNetworkHandlerSelector<NetworkHandler>() {
|
||||
val createInstanceCount = AtomicInteger(0)
|
||||
override fun createInstance(): NetworkHandler {
|
||||
createInstanceCount.incrementAndGet()
|
||||
return this.createInstance0()
|
||||
}
|
||||
}
|
||||
|
||||
internal class AbstractKeepAliveNetworkHandlerSelectorTest {
|
||||
|
||||
private fun createHandler() = TestNetworkHandler(TestNetworkHandlerContext())
|
||||
|
||||
@Test
|
||||
fun `can initialize instance`() {
|
||||
val selector = TestSelector { createHandler() }
|
||||
runBlockingUnit(timeout = 3.seconds) { selector.awaitResumeInstance() }
|
||||
assertNotNull(selector.getResumedInstance())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `no redundant initialization`() {
|
||||
val selector = TestSelector {
|
||||
fail("initialize called")
|
||||
}
|
||||
val handler = createHandler()
|
||||
selector.setCurrent(handler)
|
||||
assertSame(handler, selector.getResumedInstance())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `initialize another when closed`() {
|
||||
val selector = TestSelector {
|
||||
createHandler()
|
||||
}
|
||||
val handler = createHandler()
|
||||
selector.setCurrent(handler)
|
||||
assertSame(handler, selector.getResumedInstance())
|
||||
handler.setState(State.CLOSED)
|
||||
runBlockingUnit(timeout = 3.seconds) { selector.awaitResumeInstance() }
|
||||
assertEquals(1, selector.createInstanceCount.get())
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.network.handler
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import net.mamoe.mirai.internal.MockBot
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.network.handler.impl.NetworkHandlerSupport
|
||||
import net.mamoe.mirai.internal.network.net.protocol.SsoContext
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.utils.BotConfiguration
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
|
||||
internal class TestNetworkHandlerContext(
|
||||
override val bot: QQAndroidBot = MockBot(),
|
||||
override val logger: MiraiLogger = MiraiLogger.create("Test"),
|
||||
override val ssoContext: SsoContext = bot,
|
||||
override val configuration: BotConfiguration = bot.configuration
|
||||
) : NetworkHandlerContext
|
||||
|
||||
internal open class TestNetworkHandler(
|
||||
context: NetworkHandlerContext,
|
||||
) : NetworkHandlerSupport(context) {
|
||||
@Suppress("EXPOSED_SUPER_CLASS")
|
||||
internal open inner class TestState(
|
||||
correspondingState: NetworkHandler.State
|
||||
) : BaseStateImpl(correspondingState) {
|
||||
val resumeDeferred = CompletableDeferred<Unit>()
|
||||
val resumeCount = AtomicInteger(0)
|
||||
val onResume get() = resumeDeferred.onJoin
|
||||
|
||||
override suspend fun resumeConnection() {
|
||||
resumeCount.incrementAndGet()
|
||||
resumeDeferred.complete(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun setState(correspondingState: NetworkHandler.State) {
|
||||
setState { TestState(correspondingState) }
|
||||
}
|
||||
|
||||
private val initialState = TestState(NetworkHandler.State.INITIALIZED)
|
||||
override fun initialState(): BaseStateImpl = initialState
|
||||
|
||||
val sendPacket get() = ConcurrentLinkedQueue<OutgoingPacket>()
|
||||
|
||||
override suspend fun sendPacketImpl(packet: OutgoingPacket) {
|
||||
sendPacket.add(packet)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user