From 43407aa427d079db8d93b89d6cfbf118658fefd5 Mon Sep 17 00:00:00 2001 From: Him188 Date: Fri, 31 Jul 2020 22:49:07 +0800 Subject: [PATCH] Fix #470: Network Protocol: java.lang.IllegalStateException: returnCode = -10008 --- .../net/mamoe/mirai/qqandroid/BotImpl.kt | 3 ++- .../network/QQAndroidBotNetworkHandler.kt | 12 ++++++++- .../network/protocol/packet/PacketFactory.kt | 26 ++++++++++++++----- .../net.mamoe.mirai/event/events/bot.kt | 25 ++++++++++-------- .../network/ForceOfflineException.kt | 7 ++++- 5 files changed, 53 insertions(+), 20 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/BotImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/BotImpl.kt index 371627b97..61e3393d9 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/BotImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/BotImpl.kt @@ -82,7 +82,8 @@ internal abstract class BotImpl constructor( when (event) { is BotOfflineEvent.MsfOffline, is BotOfflineEvent.Dropped, - is BotOfflineEvent.RequireReconnect + is BotOfflineEvent.RequireReconnect, + is BotOfflineEvent.PacketFactory10008 -> { if (!_network.isActive) { // normally closed diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt index 88647bbc0..6c1e399d1 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt @@ -24,6 +24,7 @@ import net.mamoe.mirai.event.events.BotOfflineEvent import net.mamoe.mirai.event.events.BotOnlineEvent import net.mamoe.mirai.event.events.BotReloginEvent import net.mamoe.mirai.message.MessageEvent +import net.mamoe.mirai.network.ForceOfflineException import net.mamoe.mirai.network.RetryLaterException import net.mamoe.mirai.network.UnsupportedSMSLoginException import net.mamoe.mirai.network.WrongPasswordException @@ -32,6 +33,7 @@ import net.mamoe.mirai.qqandroid.contact.* import net.mamoe.mirai.qqandroid.network.protocol.data.jce.StTroopNum import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc import net.mamoe.mirai.qqandroid.network.protocol.packet.* +import net.mamoe.mirai.qqandroid.network.protocol.packet.KnownPacketFactories.PacketFactoryIllegalState10008Exception import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.GroupInfoImpl import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvcPbGetMsg import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList @@ -456,7 +458,14 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo return this.launch( start = CoroutineStart.ATOMIC ) { - input.use { parsePacket(it) } + input.use { + try { + parsePacket(it) + } catch (e: PacketFactoryIllegalState10008Exception) { + logger.warning { "Network force offline: ${e.message}" } + bot.launch { BotOfflineEvent.PacketFactory10008(bot, e).broadcast() } + } + } } } @@ -466,6 +475,7 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo * * @param input 一个完整的包的内容, 去掉开头的 int 包长度 */ + @Throws(ForceOfflineException::class) suspend fun parsePacket(input: ByteReadPacket) { generifiedParsePacket(input) } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt index 7fdceb627..d9673e574 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt @@ -37,6 +37,7 @@ import net.mamoe.mirai.qqandroid.utils.io.useBytes import net.mamoe.mirai.qqandroid.utils.io.withUse import net.mamoe.mirai.utils.* import kotlin.jvm.JvmName +import kotlin.jvm.JvmOverloads internal sealed class PacketFactory { /** @@ -176,6 +177,11 @@ internal object KnownPacketFactories { ?: IncomingFactories.firstOrNull { it.receivingCommandName == commandName } } + class PacketFactoryIllegalState10008Exception @JvmOverloads constructor( + override val message: String? = null, + override val cause: Throwable? = null + ) : RuntimeException() + // do not inline. Exceptions thrown will not be reported correctly @Suppress("UNCHECKED_CAST") suspend fun parseIncomingPacket( @@ -247,11 +253,13 @@ internal object KnownPacketFactories { bot.network.logger.debug { "Received unknown commandName: ${it.commandName}" } PacketLogger.warning { "找不到 PacketFactory" } PacketLogger.verbose { - "传递给 PacketFactory 的数据 = ${it.data.useBytes { data, length -> - data.toUHexString( - length = length - ) - }}" + "传递给 PacketFactory 的数据 = ${ + it.data.useBytes { data, length -> + data.toUHexString( + length = length + ) + } + }" } return } @@ -304,8 +312,14 @@ internal object KnownPacketFactories { input.readPacketExact(input.readInt() - 4).withUse { ssoSequenceId = readInt() PacketLogger.verbose { "sequenceId = $ssoSequenceId" } + val returnCode = readInt() - check(returnCode == 0) { "returnCode = $returnCode" } + check(returnCode == 0) { + if (returnCode == -10008) { // https://github.com/mamoe/mirai/issues/470 + throw PacketFactoryIllegalState10008Exception("returnCode = $returnCode") + } else "returnCode = $returnCode" + } + if (PacketLogger.isEnabled) { val extraData = readBytes(readInt() - 4) PacketLogger.verbose { "(sso/inner)extraData = ${extraData.toUHexString()}" } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/bot.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/bot.kt index 6e6093129..d901e1d4d 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/bot.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/bot.kt @@ -43,8 +43,7 @@ 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 /** * 被挤下线 @@ -53,9 +52,7 @@ public sealed class BotOfflineEvent : BotEvent, AbstractEvent() { public override val bot: Bot, public val title: String, public val message: String - ) : - BotOfflineEvent(), Packet, - BotPassiveEvent + ) : BotOfflineEvent(), Packet, BotPassiveEvent /** * 被服务器断开 @@ -65,9 +62,7 @@ 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 /** * 因网络问题而掉线 @@ -75,9 +70,17 @@ 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 + + /** + * 因 returnCode = -10008 等原因掉线 + */ + @MiraiInternalAPI("This is very experimental and might be changed") + @SinceMirai("1.2.0") + public data class PacketFactory10008 internal constructor( + public override val bot: Bot, + public override val cause: Throwable + ) : BotOfflineEvent(), Packet, BotPassiveEvent, CauseAware /** * 服务器主动要求更换另一个服务器 diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/ForceOfflineException.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/ForceOfflineException.kt index 930ba028b..b499454af 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/ForceOfflineException.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/ForceOfflineException.kt @@ -3,8 +3,13 @@ package net.mamoe.mirai.network import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Job import net.mamoe.mirai.Bot +import kotlin.jvm.JvmOverloads /** * 当 [Bot] 被迫下线时抛出, 作为 [Job.cancel] 的 `cause` */ -public class ForceOfflineException(public override val message: String?) : CancellationException(message) \ No newline at end of file +public class ForceOfflineException +@JvmOverloads constructor( + public override val message: String? = null, + public override val cause: Throwable? = null +) : CancellationException(message) \ No newline at end of file