Browse Source

Fix the problem that login() function never returns

Him188 6 years ago
parent
commit
2a37904021

+ 17 - 4
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt

@@ -17,6 +17,7 @@ import net.mamoe.mirai.utils.BotConfiguration
 import net.mamoe.mirai.utils.DefaultLogger
 import net.mamoe.mirai.utils.MiraiLogger
 import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail
+import net.mamoe.mirai.utils.io.logStacktrace
 import kotlin.coroutines.CoroutineContext
 import kotlin.coroutines.coroutineContext
 import kotlin.jvm.JvmOverloads
@@ -75,7 +76,8 @@ suspend inline fun Bot(qq: Long, password: String): Bot = Bot(qq.toUInt(), passw
  */
 class Bot(val account: BotAccount, val logger: MiraiLogger, context: CoroutineContext) : CoroutineScope {
     private val supervisorJob = SupervisorJob(context[Job])
-    override val coroutineContext: CoroutineContext = context + supervisorJob
+    override val coroutineContext: CoroutineContext =
+        context + supervisorJob + CoroutineExceptionHandler { _, e -> e.logStacktrace("An exception was thrown under a coroutine of Bot") }
 
     constructor(qq: UInt, password: String, context: CoroutineContext) : this(BotAccount(qq, password), context)
     constructor(account: BotAccount, context: CoroutineContext) : this(account, DefaultLogger("Bot(" + account.id + ")"), context)
@@ -116,10 +118,10 @@ class Bot(val account: BotAccount, val logger: MiraiLogger, context: CoroutineCo
      * 然后重新启动并尝试登录
      */
     @JvmOverloads // shouldn't be suspend!! This function MUST NOT inherit the context from the caller because the caller(NetworkHandler) is going to close
-    fun reinitializeNetworkHandlerAsync(
+    suspend fun reinitializeNetworkHandler(
         configuration: BotConfiguration,
         cause: Throwable? = null
-    ): Deferred<LoginResult> = async {
+    ): LoginResult {
         logger.info("Initializing BotNetworkHandler")
         try {
             if (::network.isInitialized) {
@@ -129,9 +131,20 @@ class Bot(val account: BotAccount, val logger: MiraiLogger, context: CoroutineCo
             logger.error("Cannot close network handler", e)
         }
         network = TIMBotNetworkHandler(coroutineContext + configuration, this@Bot)
-        network.login()
+
+        return network.login()
     }
 
+    /**
+     * [关闭][BotNetworkHandler.close]网络处理器, 取消所有运行在 [BotNetworkHandler] 下的协程.
+     * 然后重新启动并尝试登录
+     */
+    @JvmOverloads // shouldn't be suspend!! This function MUST NOT inherit the context from the caller because the caller(NetworkHandler) is going to close
+    fun reinitializeNetworkHandlerAsync(
+        configuration: BotConfiguration,
+        cause: Throwable? = null
+    ): Deferred<LoginResult> = async { reinitializeNetworkHandler(configuration, cause) }
+
     /**
      * Bot 联系人管理.
      *

+ 3 - 3
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt

@@ -70,13 +70,13 @@ suspend inline fun Bot.login(noinline configuration: BotConfiguration.() -> Unit
     contract {
         callsInPlace(configuration, InvocationKind.EXACTLY_ONCE)
     }
-    return this.reinitializeNetworkHandlerAsync(BotConfiguration().apply(configuration)).await()
+    return this.reinitializeNetworkHandler(BotConfiguration().apply(configuration))
 }
 
 /**
  * 使用默认的配置 ([BotConfiguration.Default]) 登录, 返回登录结果
  */
-suspend inline fun Bot.login(): LoginResult = this.reinitializeNetworkHandlerAsync(BotConfiguration.Default).await()
+suspend inline fun Bot.login(): LoginResult = this.reinitializeNetworkHandler(BotConfiguration.Default)
 
 /**
  * 使用默认的配置 ([BotConfiguration.Default]) 登录, 返回 [this]
@@ -91,7 +91,7 @@ suspend inline fun Bot.alsoLogin(noinline configuration: BotConfiguration.() ->
     contract {
         callsInPlace(configuration, InvocationKind.EXACTLY_ONCE)
     }
-    this.reinitializeNetworkHandlerAsync(BotConfiguration().apply(configuration)).await().requireSuccess()
+    this.reinitializeNetworkHandler(BotConfiguration().apply(configuration)).requireSuccess()
     return this
 }
 

+ 17 - 35
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt

@@ -58,8 +58,6 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
 
     private var heartbeatJob: Job? = null
 
-    private lateinit var userContext: CoroutineContext
-
     override suspend fun addHandler(temporaryPacketHandler: TemporaryPacketHandler<*, *>) {
         handlersLock.withLock {
             temporaryPacketHandlers.add(temporaryPacketHandler)
@@ -68,7 +66,6 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
     }
 
     override suspend fun login(): LoginResult {
-        userContext = coroutineContext
         return withContext(this.coroutineContext) {
             TIMProtocol.SERVER_IP.sortedBy { Random.nextInt() }.forEach { ip ->
                 bot.logger.info("Connecting server $ip")
@@ -97,10 +94,6 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
     override lateinit var session: BotSession
 
     //private | internal
-    private fun onLoggedIn() {
-        session = BotSession(sessionKey, socket)
-        bot.logger.info("Successfully logged in")
-    }
 
     private var sessionKey: SessionKey by Delegates.notNull()
 
@@ -379,12 +372,10 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
                 }
 
                 is TouchPacket.TouchResponse.Redirection -> {
-                    withContext(userContext) {
-                        socket.close()
-                        bot.logger.info("Redirecting to ${packet.serverIP}")
-                        socket = BotSocketAdapter(packet.serverIP!!)
-                        loginResult.complete(socket.resendTouch())
-                    }
+                    socket.close()
+                    bot.logger.info("Redirecting to ${packet.serverIP}")
+                    socket = BotSocketAdapter(packet.serverIP!!)
+                    loginResult.complete(socket.resendTouch())
                 }
 
                 is SubmitPasswordPacket.LoginResponse.Failed -> {
@@ -417,14 +408,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
 
                     if (packet.unknownBoolean) {
                         this.captchaSectionId = 1
-                        socket.sendPacket(
-                            CaptchaPacket.RequestTransmission(
-                                bot.qqAccount,
-                                this.token0825,
-                                this.captchaSectionId++,
-                                packet.token00BA
-                            )
-                        )
+                        socket.sendPacket(CaptchaPacket.RequestTransmission(bot.qqAccount, this.token0825, this.captchaSectionId++, packet.token00BA))
                     }
                 }
 
@@ -457,17 +441,13 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
                             socket.sendPacket(CaptchaPacket.Submit(bot.qqAccount, token0825, code, packet.captchaToken))
                         }
                     } else {
-                        socket.sendPacket(
-                            CaptchaPacket.RequestTransmission(bot.qqAccount, token0825, captchaSectionId++, packet.token00BA)
-                        )
+                        socket.sendPacket(CaptchaPacket.RequestTransmission(bot.qqAccount, token0825, captchaSectionId++, packet.token00BA))
                     }
                 }
 
                 is SubmitPasswordPacket.LoginResponse.Success -> {
                     this.sessionResponseDecryptionKey = packet.sessionResponseDecryptionKey
-                    socket.sendPacket(
-                        RequestSessionPacket(bot.qqAccount, socket.serverIp, packet.token38, packet.token88, packet.encryptionKey)
-                    )
+                    socket.sendPacket(RequestSessionPacket(bot.qqAccount, socket.serverIp, packet.token38, packet.token88, packet.encryptionKey))
                 }
 
                 //是ClientPasswordSubmissionPacket之后服务器回复的可能之一
@@ -493,6 +473,15 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
                     sessionKey = packet.sessionKey
                     bot.logger.info("sessionKey = ${sessionKey.value.toUHexString()}")
 
+                    setOnlineStatus(OnlineStatus.ONLINE)//required
+                }
+
+                is ChangeOnlineStatusPacket.ChangeOnlineStatusResponse -> {
+                    BotLoginSucceedEvent(bot).broadcast()
+
+
+                    session = BotSession(sessionKey, socket)
+
                     val configuration = currentBotConfiguration()
                     heartbeatJob = [email protected] {
                         while (socket.isOpen) {
@@ -514,15 +503,8 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
                         }
                     }
 
+                    bot.logger.info("Successfully logged in")
                     loginResult.complete(LoginResult.SUCCESS)
-
-                    setOnlineStatus(OnlineStatus.ONLINE)//required
-                }
-
-                is ChangeOnlineStatusPacket.ChangeOnlineStatusResponse -> {
-                    BotLoginSucceedEvent(bot).broadcast()
-
-                    onLoggedIn()
                     this.close()//The LoginHandler is useless since then
                 }
             }

+ 4 - 2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/LoginResult.kt

@@ -113,7 +113,8 @@ inline fun LoginResult.requireSuccess(lazyMessage: (LoginResult) -> String) {
  * 检查 [this] 为 [LoginResult.SUCCESS].
  * 失败则 [error]
  */
-fun LoginResult.requireSuccess() = requireSuccess { "Login failed: $this" }
+@Suppress("NOTHING_TO_INLINE")
+inline fun LoginResult.requireSuccess() = requireSuccess { "Login failed: $this" }
 
 /**
  * 检查 [this] 为 [LoginResult.SUCCESS].
@@ -121,7 +122,8 @@ fun LoginResult.requireSuccess() = requireSuccess { "Login failed: $this" }
  *
  * @return 成功时 [Unit], 失败时 `null`
  */
-fun LoginResult.requireSuccessOrNull(): Unit? = if (this == SUCCESS) Unit else null
+@Suppress("NOTHING_TO_INLINE")
+inline fun LoginResult.requireSuccessOrNull(): Unit? = if (this == SUCCESS) Unit else null
 
 /**
  * 返回 [this] 是否为 [LoginResult.SUCCESS].

+ 1 - 0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/DebugUtil.kt

@@ -12,6 +12,7 @@ internal object DebugLogger : MiraiLogger by DefaultLogger("Packet Debug")
 
 internal fun Throwable.logStacktrace(message: String? = null) = DebugLogger.error(message, this)
 
+@PublishedApi
 internal fun debugPrintln(any: Any?) = DebugLogger.debug(any)
 
 @Deprecated("Low efficiency, only for debug purpose", ReplaceWith("this"))