From d349c19c2e32705dfbd2576e3ce52dfdc6792df4 Mon Sep 17 00:00:00 2001 From: sandtechnology <20417547+sandtechnology@users.noreply.github.com> Date: Fri, 25 Jun 2021 20:29:28 +0800 Subject: [PATCH] StatSvc.SimpleGet: Decode the resp (#1241) * StatSvc.SimpleGet: Decode the resp * Close network on `StatSvc.SimpleGet.Response.Error` * Use new `IncomingPacket` Co-authored-by: Him188 --- .../network/handler/NetworkHandlerSupport.kt | 2 +- .../protocol/data/proto/StatSvcSimpleGet.kt | 26 +++++++++++++++++++ .../network/protocol/packet/login/StatSvc.kt | 26 ++++++++++++++++--- .../impl/netty/NettyBotLifecycleTest.kt | 18 +++++++++++++ 4 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 mirai-core/src/commonMain/kotlin/network/protocol/data/proto/StatSvcSimpleGet.kt diff --git a/mirai-core/src/commonMain/kotlin/network/handler/NetworkHandlerSupport.kt b/mirai-core/src/commonMain/kotlin/network/handler/NetworkHandlerSupport.kt index 3b3f4ace1..d07b336cd 100644 --- a/mirai-core/src/commonMain/kotlin/network/handler/NetworkHandlerSupport.kt +++ b/mirai-core/src/commonMain/kotlin/network/handler/NetworkHandlerSupport.kt @@ -76,7 +76,7 @@ internal abstract class NetworkHandlerSupport( ) } } - launch { + launch(start = CoroutineStart.UNDISPATCHED) { try { packetHandler.handlePacket(packet) } catch (e: Throwable) { // do not pass it to CoroutineExceptionHandler for a more controllable behavior. diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/StatSvcSimpleGet.kt b/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/StatSvcSimpleGet.kt new file mode 100644 index 000000000..1c708da8d --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/StatSvcSimpleGet.kt @@ -0,0 +1,26 @@ +/* + * 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. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +package net.mamoe.mirai.internal.network.protocol.data.proto; + +import kotlinx.serialization.Serializable +import kotlinx.serialization.protobuf.ProtoNumber +import net.mamoe.mirai.internal.utils.io.ProtoBuf + + +internal class StatSvcSimpleGet { + @Serializable + internal class RspBody( + @JvmField @ProtoNumber(1) val errorCode: Int = 0, + @JvmField @ProtoNumber(2) val errmsg: String = "", + @JvmField @ProtoNumber(3) val helloInterval: Int = 0, + @JvmField @ProtoNumber(4) val clientip: String = "", + @JvmField @ProtoNumber(5) val clientBatteyGetInterval: Int = 0 + ) : ProtoBuf +} diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt index eec4df725..2d9a7d620 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt @@ -30,9 +30,11 @@ import net.mamoe.mirai.internal.message.contextualBugReportException import net.mamoe.mirai.internal.network.* import net.mamoe.mirai.internal.network.components.ContactCacheService import net.mamoe.mirai.internal.network.components.ContactUpdater +import net.mamoe.mirai.internal.network.impl.netty.HeartbeatFailedException import net.mamoe.mirai.internal.network.protocol.data.jce.* import net.mamoe.mirai.internal.network.protocol.data.proto.Oidb0x769 import net.mamoe.mirai.internal.network.protocol.data.proto.StatSvcGetOnline +import net.mamoe.mirai.internal.network.protocol.data.proto.StatSvcSimpleGet import net.mamoe.mirai.internal.network.protocol.packet.* import net.mamoe.mirai.internal.utils.NetworkType import net.mamoe.mirai.internal.utils._miraiContentToString @@ -95,8 +97,14 @@ internal class StatSvc { } internal object SimpleGet : OutgoingPacketFactory("StatSvc.SimpleGet") { - internal object Response : Packet { - override fun toString(): String = "Response(SimpleGet.Response)" + internal sealed interface Response : Packet { + object Success : Response { + override fun toString(): String = "SimpleGet.Response.Success" + } + + class Error(val code: Int, val msg: String) : Response { + override fun toString(): String = "SimpleGet.Response.Error(code=$code,msg=$msg)" + } } operator fun invoke( @@ -113,7 +121,19 @@ internal class StatSvc { } override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response { - return Response + readProtoBuf(StatSvcSimpleGet.RspBody.serializer()).let { + return if (it.errorCode == 0) { + Response.Success + } else { + Response.Error(it.errorCode, it.errmsg) + } + } + } + + override suspend fun QQAndroidBot.handle(packet: Response) { + if (packet is Response.Error) { + network.close(HeartbeatFailedException("StatSvc.SimpleGet", IllegalStateException(packet.toString()))) + } } } diff --git a/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyBotLifecycleTest.kt b/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyBotLifecycleTest.kt index 7697b09ac..f52f65bc9 100644 --- a/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyBotLifecycleTest.kt +++ b/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyBotLifecycleTest.kt @@ -17,6 +17,8 @@ import net.mamoe.mirai.internal.network.components.EventDispatcher import net.mamoe.mirai.internal.network.components.SsoProcessor import net.mamoe.mirai.internal.network.framework.components.TestSsoProcessor import net.mamoe.mirai.internal.network.handler.NetworkHandler.State.* +import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacket +import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc import net.mamoe.mirai.internal.test.runBlockingUnit import net.mamoe.mirai.supervisorJob import org.junit.jupiter.api.Test @@ -106,4 +108,20 @@ internal class NettyBotLifecycleTest : AbstractNettyNHTest() { bot.closeAndJoin() assertFalse { network.isActive } } + + @Test + fun `network closed on SimpleGet Error`() = runBlockingUnit { + assertTrue { network.isActive } + bot.login() + assertTrue { network.isActive } + network.collectReceived( + IncomingPacket( + commandName = StatSvc.SimpleGet.commandName, + sequenceId = 1, + data = StatSvc.SimpleGet.Response.Error(1, "test error"), + ) + ) + assertFalse { network.isActive } + network.assertState(CLOSED) // we do not use selector in this test so it will be CLOSED. It will recover (reconnect) instead in real. + } } \ No newline at end of file