From 7dd7f489941a8415a882901c9cc5643a828fdb0e Mon Sep 17 00:00:00 2001 From: Him188 Date: Fri, 8 Jan 2021 12:03:42 +0800 Subject: [PATCH] Don't catch Error while reconnecting and sending packet, fix #824 --- .../commonMain/kotlin/contact/NormalMember.kt | 5 +- .../src/commonMain/kotlin/StandardUtils.kt | 63 ++++++++++++++++++- .../src/commonMain/kotlin/AbstractBot.kt | 4 +- .../kotlin/network/QQAndroidClient.kt | 8 +-- 4 files changed, 69 insertions(+), 11 deletions(-) diff --git a/mirai-core-api/src/commonMain/kotlin/contact/NormalMember.kt b/mirai-core-api/src/commonMain/kotlin/contact/NormalMember.kt index 5c156341f..b9d306cb6 100644 --- a/mirai-core-api/src/commonMain/kotlin/contact/NormalMember.kt +++ b/mirai-core-api/src/commonMain/kotlin/contact/NormalMember.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 Mamoe Technologies and contributors. + * 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. @@ -26,9 +26,6 @@ import kotlin.time.ExperimentalTime * * 群成员可能也是好友, 但他们在对象类型上不同. * 群成员可以通过 [asFriend] 得到相关好友对象. - * - * ## 相关的操作 - * [Member.isFriend] 判断此成员是否为好友 */ public interface NormalMember : Member { /** diff --git a/mirai-core-utils/src/commonMain/kotlin/StandardUtils.kt b/mirai-core-utils/src/commonMain/kotlin/StandardUtils.kt index 0460e448a..2ace34a81 100644 --- a/mirai-core-utils/src/commonMain/kotlin/StandardUtils.kt +++ b/mirai-core-utils/src/commonMain/kotlin/StandardUtils.kt @@ -46,6 +46,32 @@ public inline fun retryCatching( return Result.failure(exception!!) } +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "RESULT_CLASS_IN_RETURN_TYPE") +@kotlin.internal.InlineOnly +@kotlin.internal.LowPriorityInOverloadResolution +public inline fun retryCatchingExceptions( + n: Int, + except: KClass? = null, + block: (count: Int, lastException: Throwable?) -> R +): Result { + require(n >= 0) { + "param n for retryCatching must not be negative" + } + var exception: Throwable? = null + repeat(n) { + try { + return Result.success(block(it, exception)) + } catch (e: Exception) { + if (except?.isInstance(e) == true) { + return Result.failure(e) + } + exception?.addSuppressed(e) + exception = e + } + } + return Result.failure(exception!!) +} + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "RESULT_CLASS_IN_RETURN_TYPE") @kotlin.internal.InlineOnly @@ -70,4 +96,39 @@ public inline fun retryCatching( } } return Result.failure(exception!!) -} \ No newline at end of file +} + +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "RESULT_CLASS_IN_RETURN_TYPE") +@kotlin.internal.InlineOnly +public inline fun retryCatchingExceptions( + n: Int, + except: KClass? = null, + block: () -> R +): Result { + require(n >= 0) { + "param n for retryCatching must not be negative" + } + var exception: Throwable? = null + repeat(n) { + try { + return Result.success(block()) + } catch (e: Exception) { + if (except?.isInstance(e) == true) { + return Result.failure(e) + } + exception?.addSuppressed(e) + exception = e + } + } + return Result.failure(exception!!) +} + +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "RESULT_CLASS_IN_RETURN_TYPE") +@kotlin.internal.InlineOnly +public inline fun runCatchingExceptions(block: () -> R): Result { + return try { + Result.success(block()) + } catch (e: Exception) { + Result.failure(e) + } +} diff --git a/mirai-core/src/commonMain/kotlin/AbstractBot.kt b/mirai-core/src/commonMain/kotlin/AbstractBot.kt index 4f4de85d8..945c068b6 100644 --- a/mirai-core/src/commonMain/kotlin/AbstractBot.kt +++ b/mirai-core/src/commonMain/kotlin/AbstractBot.kt @@ -164,7 +164,7 @@ internal abstract class AbstractBot constructor( private inner class Reconnect { suspend fun reconnect(event: BotOfflineEvent): Boolean { while (true) { - retryCatching( + retryCatchingExceptions( configuration.reconnectionRetryTimes, except = LoginFailedException::class ) { tryCount, _ -> @@ -229,7 +229,7 @@ internal abstract class AbstractBot constructor( } private suspend fun doInit() { - retryCatching(5) { count, lastException -> + retryCatchingExceptions(5) { count, lastException -> if (count != 0) { if (!isActive) { logger.error("Cannot init due to fatal error") diff --git a/mirai-core/src/commonMain/kotlin/network/QQAndroidClient.kt b/mirai-core/src/commonMain/kotlin/network/QQAndroidClient.kt index 6ccb92f8a..66de9bf80 100644 --- a/mirai-core/src/commonMain/kotlin/network/QQAndroidClient.kt +++ b/mirai-core/src/commonMain/kotlin/network/QQAndroidClient.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 Mamoe Technologies and contributors. + * 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. @@ -133,11 +133,11 @@ internal open class QQAndroidClient( if (bot.client.serverList.isEmpty()) { bot.client.serverList.addAll(DefaultServerList) } - retryCatching(bot.client.serverList.size, except = LoginFailedException::class) { + retryCatchingExceptions(bot.client.serverList.size, except = LoginFailedException::class) l@{ val pair = bot.client.serverList[0] - kotlin.runCatching { + runCatchingExceptions { block(pair.first, pair.second) - return@retryCatching + return@l }.getOrElse { bot.client.serverList.remove(pair) if (it !is LoginFailedException) {