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 a3ffca114..4c2c7e9aa 100644 --- a/mirai-core-api/src/commonMain/kotlin/event/events/bot.kt +++ b/mirai-core-api/src/commonMain/kotlin/event/events/bot.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. @@ -34,6 +34,10 @@ public data class BotOnlineEvent internal constructor( * [Bot] 离线. */ public sealed class BotOfflineEvent : BotEvent, AbstractEvent() { + /** + * 为 `true` 时会尝试重连. 仅 [BotOfflineEvent.Force] 默认为 `false`, 其他默认为 `true`. + */ + public open val reconnect: Boolean get() = true /** * 主动离线. 主动广播这个事件也可以让 [Bot] 关闭. @@ -41,16 +45,20 @@ public sealed class BotOfflineEvent : BotEvent, AbstractEvent() { public data class Active( public override val bot: Bot, public override val cause: Throwable? - ) : BotOfflineEvent(), BotActiveEvent, CauseAware + ) : BotOfflineEvent(), BotActiveEvent, CauseAware { + override val reconnect: Boolean get() = false + } /** - * 被挤下线 + * 被挤下线. 默认不会自动重连. 可将 [reconnect] 改为 `true` 以重连. */ public data class Force internal constructor( public override val bot: Bot, public val title: String, - public val message: String - ) : BotOfflineEvent(), Packet, BotPassiveEvent + public val message: String, + ) : BotOfflineEvent(), Packet, BotPassiveEvent { + override var reconnect: Boolean = false + } /** * 被服务器断开 @@ -59,7 +67,9 @@ public sealed class BotOfflineEvent : BotEvent, AbstractEvent() { public data class MsfOffline internal constructor( public override val bot: Bot, public override val cause: Throwable? - ) : BotOfflineEvent(), Packet, BotPassiveEvent, CauseAware + ) : BotOfflineEvent(), Packet, BotPassiveEvent, CauseAware { + override var reconnect: Boolean = true + } /** * 因网络问题而掉线 @@ -67,7 +77,9 @@ public sealed class BotOfflineEvent : BotEvent, AbstractEvent() { public data class Dropped internal constructor( public override val bot: Bot, public override val cause: Throwable? - ) : BotOfflineEvent(), Packet, BotPassiveEvent, CauseAware + ) : BotOfflineEvent(), Packet, BotPassiveEvent, CauseAware { + override var reconnect: Boolean = true + } /** * 因 returnCode = -10008 等原因掉线 @@ -77,7 +89,9 @@ public sealed class BotOfflineEvent : BotEvent, AbstractEvent() { val returnCode: Int, public override val bot: Bot, public override val cause: Throwable - ) : BotOfflineEvent(), Packet, BotPassiveEvent, CauseAware + ) : BotOfflineEvent(), Packet, BotPassiveEvent, CauseAware { + override var reconnect: Boolean = true + } /** * 服务器主动要求更换另一个服务器 @@ -85,8 +99,9 @@ public sealed class BotOfflineEvent : BotEvent, AbstractEvent() { @MiraiInternalApi public data class RequireReconnect internal constructor( public override val bot: Bot - ) : BotOfflineEvent(), Packet, - BotPassiveEvent + ) : BotOfflineEvent(), Packet, BotPassiveEvent { + override var reconnect: Boolean = true + } @MiraiExperimentalApi public interface CauseAware { diff --git a/mirai-core/src/commonMain/kotlin/AbstractBot.kt b/mirai-core/src/commonMain/kotlin/AbstractBot.kt index 02cf89f61..0e5732182 100644 --- a/mirai-core/src/commonMain/kotlin/AbstractBot.kt +++ b/mirai-core/src/commonMain/kotlin/AbstractBot.kt @@ -23,6 +23,7 @@ import kotlinx.coroutines.sync.Mutex import net.mamoe.mirai.Bot import net.mamoe.mirai.contact.OtherClientList import net.mamoe.mirai.event.* +import net.mamoe.mirai.event.Listener.EventPriority.MONITOR import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.event.events.BotOfflineEvent import net.mamoe.mirai.event.events.BotReloginEvent @@ -91,7 +92,10 @@ internal abstract class AbstractBot constructor( @OptIn(ExperimentalTime::class) @Suppress("unused") private val offlineListener: Listener = - this@AbstractBot.eventChannel.subscribeAlways(concurrency = Listener.ConcurrencyKind.LOCKED) { event -> + this@AbstractBot.eventChannel.subscribeAlways( + priority = MONITOR, + concurrency = Listener.ConcurrencyKind.LOCKED + ) { event -> if (!event.bot.isActive) { // bot closed return@subscribeAlways @@ -110,30 +114,6 @@ internal abstract class AbstractBot constructor( return@subscribeAlways }*/ when (event) { - is BotOfflineEvent.MsfOffline, - is BotOfflineEvent.Dropped, - is BotOfflineEvent.RequireReconnect, - is BotOfflineEvent.PacketFactoryErrorCode - -> { - if (!_network.isActive) { - // normally closed - return@subscribeAlways - } - bot.logger.info { "Connection lost, retrying login" } - - bot.asQQAndroidBot().client.run { - if (serverList.isEmpty()) { - serverList.addAll(DefaultServerList) - } else serverList.removeAt(0) - } - - val success: Boolean - val time = measureTime { success = Reconnect().reconnect(event) } - - if (success) { - logger.info { "Reconnected successfully in ${time.toHumanReadableString()}" } - } - } is BotOfflineEvent.Active -> { val cause = event.cause val msg = if (cause == null) { @@ -146,7 +126,37 @@ internal abstract class AbstractBot constructor( } is BotOfflineEvent.Force -> { bot.logger.info { "Connection occupied by another android device: ${event.message}" } - bot.cancel(ForceOfflineException("Connection occupied by another android device: ${event.message}")) + if (!event.reconnect) { + bot.cancel(ForceOfflineException("Connection occupied by another android device: ${event.message}")) + } + } + is BotOfflineEvent.MsfOffline, + is BotOfflineEvent.Dropped, + is BotOfflineEvent.RequireReconnect, + is BotOfflineEvent.PacketFactoryErrorCode + -> { + // nothing to do + } + } + + if (event.reconnect) { + if (!_network.isActive) { + // normally closed + return@subscribeAlways + } + bot.logger.info { "Connection lost, retrying login" } + + bot.asQQAndroidBot().client.run { + if (serverList.isEmpty()) { + serverList.addAll(DefaultServerList) + } else serverList.removeAt(0) + } + + val success: Boolean + val time = measureTime { success = Reconnect().reconnect(event) } + + if (success) { + logger.info { "Reconnected successfully in ${time.toHumanReadableString()}" } } } }