Add BotOfflineEvent.reconnect, support auto-reconnect control.

AbstractBot.offlineListener is now MONITOR
This commit is contained in:
Him188 2021-01-05 20:23:00 +08:00
parent 44053ae85f
commit 95e6ca4c7a
2 changed files with 61 additions and 36 deletions

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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] 离线. * [Bot] 离线.
*/ */
public sealed class BotOfflineEvent : BotEvent, AbstractEvent() { public sealed class BotOfflineEvent : BotEvent, AbstractEvent() {
/**
* `true` 时会尝试重连. [BotOfflineEvent.Force] 默认为 `false`, 其他默认为 `true`.
*/
public open val reconnect: Boolean get() = true
/** /**
* 主动离线. 主动广播这个事件也可以让 [Bot] 关闭. * 主动离线. 主动广播这个事件也可以让 [Bot] 关闭.
@ -41,16 +45,20 @@ public sealed class BotOfflineEvent : BotEvent, AbstractEvent() {
public data class Active( public data class Active(
public override val bot: Bot, public override val bot: Bot,
public override val cause: Throwable? 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 data class Force internal constructor(
public override val bot: Bot, public override val bot: Bot,
public val title: String, public val title: String,
public val message: String public val message: String,
) : BotOfflineEvent(), Packet, BotPassiveEvent ) : 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 data class MsfOffline internal constructor(
public override val bot: Bot, public override val bot: Bot,
public override val cause: Throwable? 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 data class Dropped internal constructor(
public override val bot: Bot, public override val bot: Bot,
public override val cause: Throwable? public override val cause: Throwable?
) : BotOfflineEvent(), Packet, BotPassiveEvent, CauseAware ) : BotOfflineEvent(), Packet, BotPassiveEvent, CauseAware {
override var reconnect: Boolean = true
}
/** /**
* returnCode = -10008 等原因掉线 * returnCode = -10008 等原因掉线
@ -77,7 +89,9 @@ public sealed class BotOfflineEvent : BotEvent, AbstractEvent() {
val returnCode: Int, val returnCode: Int,
public override val bot: Bot, public override val bot: Bot,
public override val cause: Throwable 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 @MiraiInternalApi
public data class RequireReconnect internal constructor( public data class RequireReconnect internal constructor(
public override val bot: Bot public override val bot: Bot
) : BotOfflineEvent(), Packet, ) : BotOfflineEvent(), Packet, BotPassiveEvent {
BotPassiveEvent override var reconnect: Boolean = true
}
@MiraiExperimentalApi @MiraiExperimentalApi
public interface CauseAware { public interface CauseAware {

View File

@ -23,6 +23,7 @@ import kotlinx.coroutines.sync.Mutex
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.OtherClientList import net.mamoe.mirai.contact.OtherClientList
import net.mamoe.mirai.event.* 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.BotEvent
import net.mamoe.mirai.event.events.BotOfflineEvent import net.mamoe.mirai.event.events.BotOfflineEvent
import net.mamoe.mirai.event.events.BotReloginEvent import net.mamoe.mirai.event.events.BotReloginEvent
@ -91,7 +92,10 @@ internal abstract class AbstractBot<N : BotNetworkHandler> constructor(
@OptIn(ExperimentalTime::class) @OptIn(ExperimentalTime::class)
@Suppress("unused") @Suppress("unused")
private val offlineListener: Listener<BotOfflineEvent> = private val offlineListener: Listener<BotOfflineEvent> =
this@AbstractBot.eventChannel.subscribeAlways(concurrency = Listener.ConcurrencyKind.LOCKED) { event -> this@AbstractBot.eventChannel.subscribeAlways(
priority = MONITOR,
concurrency = Listener.ConcurrencyKind.LOCKED
) { event ->
if (!event.bot.isActive) { if (!event.bot.isActive) {
// bot closed // bot closed
return@subscribeAlways return@subscribeAlways
@ -110,30 +114,6 @@ internal abstract class AbstractBot<N : BotNetworkHandler> constructor(
return@subscribeAlways return@subscribeAlways
}*/ }*/
when (event) { 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 -> { is BotOfflineEvent.Active -> {
val cause = event.cause val cause = event.cause
val msg = if (cause == null) { val msg = if (cause == null) {
@ -146,7 +126,37 @@ internal abstract class AbstractBot<N : BotNetworkHandler> constructor(
} }
is BotOfflineEvent.Force -> { is BotOfflineEvent.Force -> {
bot.logger.info { "Connection occupied by another android device: ${event.message}" } 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()}" }
} }
} }
} }