From 076cd4997d8f37554473809fcf00098d6ce2e75e Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 25 Apr 2021 11:34:54 +0800 Subject: [PATCH] BotOfflineEventMonitor --- .../src/commonMain/kotlin/event/events/bot.kt | 13 --- .../src/commonMain/kotlin/QQAndroidBot.kt | 4 + .../components/BotOfflineEventMonitor.kt | 108 ++++++++++++++++++ 3 files changed, 112 insertions(+), 13 deletions(-) create mode 100644 mirai-core/src/commonMain/kotlin/network/components/BotOfflineEventMonitor.kt diff --git a/mirai-core-api/src/commonMain/kotlin/event/events/bot.kt b/mirai-core-api/src/commonMain/kotlin/event/events/bot.kt index 67846cbe4..5bc5ba41a 100644 --- a/mirai-core-api/src/commonMain/kotlin/event/events/bot.kt +++ b/mirai-core-api/src/commonMain/kotlin/event/events/bot.kt @@ -84,19 +84,6 @@ public sealed class BotOfflineEvent : BotEvent, AbstractEvent() { override var reconnect: Boolean = true } - /** - * 因 returnCode = -10008 等原因掉线 - */ - @MiraiInternalApi("This is very experimental and might be changed") - @Deprecated("Deprecated with no replacement", level = DeprecationLevel.ERROR) - public data class PacketFactoryErrorCode @MiraiInternalApi public constructor( - val returnCode: Int, - public override val bot: Bot, - public override val cause: Throwable - ) : BotOfflineEvent(), Packet, BotPassiveEvent, CauseAware { - override var reconnect: Boolean = true - } - /** * 服务器主动要求更换另一个服务器 */ diff --git a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt index 005fd12b1..0b94eb1e0 100644 --- a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt +++ b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt @@ -112,6 +112,9 @@ internal open class QQAndroidBot constructor( } } }, + StateChangedObserver(State.OK) { new -> + components[BotOfflineEventMonitor].attachJob(bot, new) + }, debugConfiguration.stateObserver ).safe(logger) } @@ -126,6 +129,7 @@ internal open class QQAndroidBot constructor( set(HeartbeatProcessor, HeartbeatProcessorImpl()) set(KeyRefreshProcessor, KeyRefreshProcessorImpl(networkLogger)) set(ConfigPushProcessor, ConfigPushProcessorImpl(networkLogger)) + set(BotOfflineEventMonitor, BotOfflineEventMonitorImpl()) set(BotInitProcessor, BotInitProcessorImpl(bot, components, bot.logger)) set(ContactCacheService, ContactCacheServiceImpl(bot)) diff --git a/mirai-core/src/commonMain/kotlin/network/components/BotOfflineEventMonitor.kt b/mirai-core/src/commonMain/kotlin/network/components/BotOfflineEventMonitor.kt new file mode 100644 index 000000000..071dc9901 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/network/components/BotOfflineEventMonitor.kt @@ -0,0 +1,108 @@ +/* + * 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.components + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch +import net.mamoe.mirai.event.ConcurrencyKind +import net.mamoe.mirai.event.EventPriority +import net.mamoe.mirai.event.events.BotOfflineEvent +import net.mamoe.mirai.event.subscribeAlways +import net.mamoe.mirai.internal.QQAndroidBot +import net.mamoe.mirai.internal.asQQAndroidBot +import net.mamoe.mirai.internal.network.component.ComponentKey +import net.mamoe.mirai.utils.castOrNull +import net.mamoe.mirai.utils.info +import net.mamoe.mirai.utils.toHumanReadableString +import kotlin.time.measureTime + +internal interface BotOfflineEventMonitor { + companion object : ComponentKey + + fun attachJob(bot: QQAndroidBot, scope: CoroutineScope) +} + +internal class BotOfflineEventMonitorImpl : BotOfflineEventMonitor { + override fun attachJob(bot: QQAndroidBot, scope: CoroutineScope) { + bot.eventChannel.parentScope(scope).subscribeAlways( + ::onEvent, + priority = EventPriority.MONITOR, + concurrency = ConcurrencyKind.LOCKED, + ) + } + + // TODO: 2021/4/25 Review BotOfflineEventMonitor + private suspend fun onEvent(event: BotOfflineEvent) { + val bot = event.bot.asQQAndroidBot() + val network = bot.network + if ( + !event.bot.isActive // bot closed + // || _isConnecting // bot 还在登入 // TODO: 2021/4/14 处理还在登入? + ) { + // Close network to avoid endless reconnection while network is ok + // https://github.com/mamoe/mirai/issues/894 + kotlin.runCatching { network.close(null) } + return + } + /* + if (network.areYouOk() && event !is BotOfflineEvent.Force && event !is BotOfflineEvent.MsfOffline) { + // network 运行正常 + return@subscribeAlways + }*/ + when (event) { + is BotOfflineEvent.Active -> { + val cause = event.cause + val msg = if (cause == null) "" else " with exception: $cause" + bot.logger.info("Bot is closed manually $msg", cause) + network.close(null) + } + is BotOfflineEvent.Force -> { + bot.logger.info { "Connection occupied by another android device: ${event.message}" } + if (event.reconnect) { + bot.logger.info { "Reconnecting..." } + // delay(3000) + } else { + network.close(null) + } + } + is BotOfflineEvent.MsfOffline, + is BotOfflineEvent.Dropped, + is BotOfflineEvent.RequireReconnect, + -> { + // nothing to do + } + } + + if (event.reconnect) { + if (!network.isOk()) { + // normally closed + return + } + + val causeMessage = event.castOrNull()?.cause?.toString() ?: event.toString() + bot.logger.info { "Connection lost, retrying login ($causeMessage)." } + + bot.launch { + val success: Boolean + val time = measureTime { + success = kotlin.runCatching { + bot.login() + }.isSuccess // resume connection + } + + if (success) { + bot.logger.info { "Reconnected successfully in ${time.toHumanReadableString()}." } + } + } + } + } + +}