Fix #470: Network Protocol: java.lang.IllegalStateException: returnCode = -10008

This commit is contained in:
Him188 2020-07-31 22:49:07 +08:00
parent 9a9ff4a58e
commit 43407aa427
5 changed files with 53 additions and 20 deletions

View File

@ -82,7 +82,8 @@ internal abstract class BotImpl<N : BotNetworkHandler> constructor(
when (event) { when (event) {
is BotOfflineEvent.MsfOffline, is BotOfflineEvent.MsfOffline,
is BotOfflineEvent.Dropped, is BotOfflineEvent.Dropped,
is BotOfflineEvent.RequireReconnect is BotOfflineEvent.RequireReconnect,
is BotOfflineEvent.PacketFactory10008
-> { -> {
if (!_network.isActive) { if (!_network.isActive) {
// normally closed // normally closed

View File

@ -24,6 +24,7 @@ import net.mamoe.mirai.event.events.BotOfflineEvent
import net.mamoe.mirai.event.events.BotOnlineEvent import net.mamoe.mirai.event.events.BotOnlineEvent
import net.mamoe.mirai.event.events.BotReloginEvent import net.mamoe.mirai.event.events.BotReloginEvent
import net.mamoe.mirai.message.MessageEvent import net.mamoe.mirai.message.MessageEvent
import net.mamoe.mirai.network.ForceOfflineException
import net.mamoe.mirai.network.RetryLaterException import net.mamoe.mirai.network.RetryLaterException
import net.mamoe.mirai.network.UnsupportedSMSLoginException import net.mamoe.mirai.network.UnsupportedSMSLoginException
import net.mamoe.mirai.network.WrongPasswordException 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.jce.StTroopNum
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc 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.*
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.GroupInfoImpl
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvcPbGetMsg import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvcPbGetMsg
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList
@ -456,7 +458,14 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
return this.launch( return this.launch(
start = CoroutineStart.ATOMIC 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 包长度 * @param input 一个完整的包的内容, 去掉开头的 int 包长度
*/ */
@Throws(ForceOfflineException::class)
suspend fun parsePacket(input: ByteReadPacket) { suspend fun parsePacket(input: ByteReadPacket) {
generifiedParsePacket<Packet>(input) generifiedParsePacket<Packet>(input)
} }

View File

@ -37,6 +37,7 @@ import net.mamoe.mirai.qqandroid.utils.io.useBytes
import net.mamoe.mirai.qqandroid.utils.io.withUse import net.mamoe.mirai.qqandroid.utils.io.withUse
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
import kotlin.jvm.JvmOverloads
internal sealed class PacketFactory<TPacket : Packet?> { internal sealed class PacketFactory<TPacket : Packet?> {
/** /**
@ -176,6 +177,11 @@ internal object KnownPacketFactories {
?: IncomingFactories.firstOrNull { it.receivingCommandName == commandName } ?: 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 // do not inline. Exceptions thrown will not be reported correctly
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
suspend fun <T : Packet?> parseIncomingPacket( suspend fun <T : Packet?> parseIncomingPacket(
@ -247,11 +253,13 @@ internal object KnownPacketFactories {
bot.network.logger.debug { "Received unknown commandName: ${it.commandName}" } bot.network.logger.debug { "Received unknown commandName: ${it.commandName}" }
PacketLogger.warning { "找不到 PacketFactory" } PacketLogger.warning { "找不到 PacketFactory" }
PacketLogger.verbose { PacketLogger.verbose {
"传递给 PacketFactory 的数据 = ${it.data.useBytes { data, length -> "传递给 PacketFactory 的数据 = ${
it.data.useBytes { data, length ->
data.toUHexString( data.toUHexString(
length = length length = length
) )
}}" }
}"
} }
return return
} }
@ -304,8 +312,14 @@ internal object KnownPacketFactories {
input.readPacketExact(input.readInt() - 4).withUse { input.readPacketExact(input.readInt() - 4).withUse {
ssoSequenceId = readInt() ssoSequenceId = readInt()
PacketLogger.verbose { "sequenceId = $ssoSequenceId" } PacketLogger.verbose { "sequenceId = $ssoSequenceId" }
val returnCode = readInt() 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) { if (PacketLogger.isEnabled) {
val extraData = readBytes(readInt() - 4) val extraData = readBytes(readInt() - 4)
PacketLogger.verbose { "(sso/inner)extraData = ${extraData.toUHexString()}" } PacketLogger.verbose { "(sso/inner)extraData = ${extraData.toUHexString()}" }

View File

@ -43,8 +43,7 @@ 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, ) : BotOfflineEvent(), BotActiveEvent, CauseAware
CauseAware
/** /**
* 被挤下线 * 被挤下线
@ -53,9 +52,7 @@ public sealed class BotOfflineEvent : BotEvent, AbstractEvent() {
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
/** /**
* 被服务器断开 * 被服务器断开
@ -65,9 +62,7 @@ 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
/** /**
* 因网络问题而掉线 * 因网络问题而掉线
@ -75,9 +70,17 @@ 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(), ) : BotOfflineEvent(), Packet, BotPassiveEvent, CauseAware
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
/** /**
* 服务器主动要求更换另一个服务器 * 服务器主动要求更换另一个服务器

View File

@ -3,8 +3,13 @@ package net.mamoe.mirai.network
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import kotlin.jvm.JvmOverloads
/** /**
* [Bot] 被迫下线时抛出, 作为 [Job.cancel] `cause` * [Bot] 被迫下线时抛出, 作为 [Job.cancel] `cause`
*/ */
public class ForceOfflineException(public override val message: String?) : CancellationException(message) public class ForceOfflineException
@JvmOverloads constructor(
public override val message: String? = null,
public override val cause: Throwable? = null
) : CancellationException(message)