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 许可证的约束, 可以在以下链接找到该许可证.
* 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 {

View File

@ -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<N : BotNetworkHandler> constructor(
@OptIn(ExperimentalTime::class)
@Suppress("unused")
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) {
// bot closed
return@subscribeAlways
@ -110,30 +114,6 @@ internal abstract class AbstractBot<N : BotNetworkHandler> 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<N : BotNetworkHandler> 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()}" }
}
}
}