Просмотр исходного кода

[core] Fix `bot.close`, ensure network is also closed, fix recursion problems. Fix #2266

Him188 3 лет назад
Родитель
Сommit
7fd3234ff3

+ 4 - 0
mirai-core/src/commonMain/kotlin/AbstractBot.kt

@@ -110,6 +110,10 @@ internal abstract class AbstractBot constructor(
     override fun close(cause: Throwable?) {
         if (!this.isActive) return
 
+        if (networkInitialized) {
+            network.close(cause)
+        }
+
         if (cause == null) {
             supervisorJob.cancel()
         } else {

+ 2 - 0
mirai-core/src/commonMain/kotlin/QQAndroidBot.kt

@@ -77,8 +77,10 @@ internal open class QQAndroidBot constructor(
 
     val client get() = components[SsoProcessor].client
 
+    private val closing = atomic(false)
     override fun close(cause: Throwable?) {
         if (!this.isActive) return
+        if (!closing.compareAndSet(false, true)) return
 
         if (networkInitialized) {
             runBlocking {

+ 17 - 0
mirai-core/src/commonTest/kotlin/network/impl/common/BotLifecycleTest.kt

@@ -15,11 +15,13 @@ import kotlinx.coroutines.CoroutineName
 import kotlinx.coroutines.SupervisorJob
 import kotlinx.coroutines.isActive
 import kotlinx.coroutines.job
+import kotlinx.coroutines.test.runTest
 import net.mamoe.mirai.internal.MockBot
 import net.mamoe.mirai.internal.network.components.EventDispatcher
 import net.mamoe.mirai.internal.network.components.SsoProcessor
 import net.mamoe.mirai.internal.network.framework.AbstractCommonNHTest
 import net.mamoe.mirai.internal.network.framework.components.TestSsoProcessor
+import net.mamoe.mirai.internal.network.handler.NetworkHandler
 import net.mamoe.mirai.internal.network.handler.NetworkHandler.State.*
 import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacket
 import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc
@@ -127,6 +129,21 @@ internal class BotLifecycleTest : AbstractCommonNHTest() {
         assertFalse { network.isActive }
     }
 
+    @Test // #2266
+    fun `no StackOverflowError on Bot close`() = runTest {
+        assertTrue { network.isActive }
+        bot.login()
+        assertTrue { network.isActive }
+        overrideComponents[SsoProcessor] = object : TestSsoProcessor(bot) {
+            override suspend fun logout(handler: NetworkHandler) {
+                bot.close()
+            }
+        }
+        bot.close()
+        network.assertState(CLOSED)
+        assertFalse { network.isActive }
+    }
+
 
     @Test
     fun `isOnline returns false if network not initialized`() = runBlockingUnit {