From 63a4d5f3b9f124dad43616c64de2b352582d6ca8 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 2 Feb 2020 16:02:17 +0800 Subject: [PATCH] New PacketFactory structure --- .../network/QQAndroidBotNetworkHandler.kt | 11 +- .../qqandroid/network/protocol/README.md | 116 ----------- .../protocol/packet/IncomingPacketFactory.kt | 2 + .../protocol/packet/OutgoingPacketAndroid.kt | 186 ++++-------------- .../network/protocol/packet/PacketFactory.kt | 149 ++++++++------ .../packet/chat/image/ImageDownPacket.kt | 10 +- .../packet/chat/image/ImageUpPacket.kt | 12 +- .../packet/chat/receive/MessageSvc.kt | 27 ++- .../chat/receive/OnlinePush.PbPushGroupMsg.kt | 10 +- .../protocol/packet/list/FriendListPacket.kt | 9 +- .../protocol/packet/login/ConfigPushSvc.kt | 24 +-- .../protocol/packet/login/LoginPacket.kt | 9 +- .../network/protocol/packet/login/StatSvc.kt | 4 +- .../protocol/packet/login/TransEmpPacket.kt | 2 +- .../androidPacketTests/serverToClient.kt | 7 +- .../net.mamoe.mirai/utils/MiraiLogger.kt | 130 ++++++++---- 16 files changed, 290 insertions(+), 418 deletions(-) delete mode 100644 mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/README.md create mode 100644 mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/IncomingPacketFactory.kt 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 8d7533a92..24c67ce07 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 @@ -104,7 +104,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } override suspend fun init() { - delay(5000) + // delay(5000) this@QQAndroidBotNetworkHandler.subscribeAlways { if (this@QQAndroidBotNetworkHandler.bot == this.bot) { @@ -126,7 +126,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler 20, 0, 0 - ).sendAndExpect() + ).sendAndExpect(timeoutMillis = 1000) totalFriendCount = data.totalFriendCount data.friendList.forEach { @@ -150,7 +150,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler bot.logger.info("开始加载组信息") val troopData = FriendList.GetTroopListSimplify( bot.client - ).sendAndExpect() + ).sendAndExpect(timeoutMillis = 1000) println(troopData.contentToString()) } catch (e: Exception) { bot.logger.info("加载组信息失败|一般这是由于加载过于频繁导致/将以热加载方式加载群列表") @@ -235,7 +235,10 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler bot.logger.info("Received packet: $packet") packetFactory?.run { - bot.handle(packet) + when (this) { + is OutgoingPacketFactory

-> bot.handle(packet) + is IncomingPacketFactory

-> bot.handle(packet, sequenceId)?.sendWithoutExpect() + } } } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/README.md b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/README.md deleted file mode 100644 index 2af31c4eb..000000000 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/README.md +++ /dev/null @@ -1,116 +0,0 @@ -# QQAndroid Protocol - -## Overview - -Note: `head` and `body` functions do nothing. They just work as -notations - -PseudoCode: -``` -OutgoingPacket { - int head.size + body.size + 4 - head { - int 0x0A - byte 0x02 - int extra data size + 4 - byte[] extra data // initially={} - byte 0 - int uinAccount.length + 4 - byte[] uinAccount // =qqNumber.toString() - } - body { // encrypted by `ByteArray(16)` when login, after which by sessionKey - SSOPacket { - int head.size + 4 - head { - int sequenceId - int subAppId - int subAppId - hex "01 00 00 00 00 00 00 00 00 00 01 00" // unknown values - int extraData.size + 4 - byte[] extraData // empty when login - int commandName.length + 4 - byte[] commandName // e.g. wtlogin.login - int 4 + 4 - int 0x02B05B8B - int imei.length + 4 - byte[] imei - int 0 + 4 - short ksid.length + 2 - byte[] ksid - int 0 + 4 - } - - int body.size + 4 - body { - OicqRequestPacket { - head { - byte 2 // head flag - short 27 + 2 + remaining.length - ushort client.protocolVersion // const 8001 - ushort commandId // e.g. 0x0810 - ushort 0x0001 - uint client.uin - byte 3 // const - ubyte encryptMethod.value // [EncryptMethod] - byte 0 // const - int 2 // const - int client.appClientVersion - int 0 // const - } - - body { - // only write one of the following two structures!! - - // if encryption method is ECDH - EncryptionMethodECDH { - head { - byte 1 - byte 1 - byte[] privateKey // random key - short 258 - short [ECDH.publicKey].size // always 49 - byte[] [ECDH.publicKey] - } - - body { - // real body - } - } - - // if encryption method is SessionKey - EncryptionMethodSessionKey { - head { - byte 1 - byte if (currentLoginState == 2) 3 else 2 - fully key - short 258 // const - short 0 - } - - body { - // real body - } - } - } - tail { - byte 3 // tail flag - } - } - } - } - } -} -``` - -## Packet bodies - -### LoginPacket - SubCommand 9 -**TO BE UPDATED** - -PseudoCode: -``` -short 9 // subCommand -tlvList { - -} -``` diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/IncomingPacketFactory.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/IncomingPacketFactory.kt new file mode 100644 index 000000000..ed8da7ddf --- /dev/null +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/IncomingPacketFactory.kt @@ -0,0 +1,2 @@ +package net.mamoe.mirai.qqandroid.network.protocol.packet + diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt index e8d8f7060..757956aad 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt @@ -12,10 +12,6 @@ import net.mamoe.mirai.utils.io.writeHex import net.mamoe.mirai.utils.io.writeIntLVPacket import net.mamoe.mirai.utils.io.writeQQ -/** - * 待发送给服务器的数据包. 它代表着一个 [ByteReadPacket]. - * 只有最终的包才会被包装为 [OutgoingPacket]. - */ internal class OutgoingPacket constructor( name: String?, val commandName: String, @@ -31,25 +27,11 @@ internal val KEY_16_ZEROS = ByteArray(16) internal val EMPTY_BYTE_ARRAY = ByteArray(0) /** - * 最外层的包. 结构适用于登录之后的过程. - * - * 在 QQ 中这个被以 JNI 实现: * com.tencent.qphone.base.util.CodecWarpper#encodeRequest(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, byte[], int, int, java.lang.String, byte, byte, byte, byte[], byte[], boolean) - * - * **Packet structure** - * int remaining.length + 4 - * int 0x0B - * byte 0x01 - * int sequenceId - * byte 0 - * int uinAccount.length + 4 - * byte[] uinAccount - * - * byte[] body encrypted by 16 zero */ @Deprecated("危险", level = DeprecationLevel.ERROR) @UseExperimental(MiraiInternalAPI::class) -internal inline fun PacketFactory<*>.buildOutgoingPacket( +internal inline fun OutgoingPacketFactory<*>.buildOutgoingPacket( client: QQAndroidClient, bodyType: Byte = 1, // 1: PB? name: String? = this.commandName, @@ -76,11 +58,8 @@ internal inline fun PacketFactory<*>.buildOutgoingPacket( }) } -/** - * buildOutgoingPacket 与 writeUniPacket 的 fast-path - */ @UseExperimental(MiraiInternalAPI::class) -internal inline fun PacketFactory<*>.buildOutgoingUniPacket( +internal inline fun OutgoingPacketFactory<*>.buildOutgoingUniPacket( client: QQAndroidClient, bodyType: Byte = 1, // 1: PB? name: String? = this.commandName, @@ -110,6 +89,37 @@ internal inline fun PacketFactory<*>.buildOutgoingUniPacket( }) } + +@UseExperimental(MiraiInternalAPI::class) +internal inline fun IncomingPacketFactory<*>.buildResponseUniPacket( + client: QQAndroidClient, + bodyType: Byte = 1, // 1: PB? + name: String? = this.responseCommandName, + commandName: String = this.responseCommandName, + key: ByteArray = client.wLoginSigInfo.d2Key, + extraData: ByteReadPacket = BRP_STUB, + sequenceId: Int = client.nextSsoSequenceId(), + body: BytePacketBuilder.(sequenceId: Int) -> Unit +): OutgoingPacket { + return OutgoingPacket(name, commandName, sequenceId, buildPacket { + writeIntLVPacket(lengthOffset = { it + 4 }) { + writeInt(0x0B) + writeByte(bodyType) + writeInt(sequenceId) + writeByte(0) + client.uin.toString().let { + writeInt(it.length + 4) + writeStringUtf8(it) + } + encryptAndWrite(key) { + writeUniPacket(commandName, client.outgoingPacketUnknownValue, extraData) { + body(sequenceId) + } + } + } + }) +} + @UseExperimental(MiraiInternalAPI::class) internal inline fun BytePacketBuilder.writeUniPacket( commandName: String, @@ -140,25 +150,10 @@ internal inline fun BytePacketBuilder.writeUniPacket( /** - * 最外层的包. 结构适用于登录. - * - * 在 QQ 中这个被以 JNI 实现: * com.tencent.qphone.base.util.CodecWarpper#encodeRequest(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, byte[], int, int, java.lang.String, byte, byte, byte, byte[], byte[], boolean) - * - * **Packet structure** - * int remaining.length + 4 - * int 0x0A - * byte 0x02 - * int extra data size + 4 - * byte[] extra data - * byte 0 - * int uinAccount.length + 4 - * byte[] uinAccount - * - * byte[] body encrypted by 16 zero */ @UseExperimental(MiraiInternalAPI::class) -internal inline fun PacketFactory<*>.buildLoginOutgoingPacket( +internal inline fun OutgoingPacketFactory<*>.buildLoginOutgoingPacket( client: QQAndroidClient, bodyType: Byte, extraData: ByteArray = EMPTY_BYTE_ARRAY, @@ -193,30 +188,6 @@ internal inline fun PacketFactory<*>.buildLoginOutgoingPacket( private inline val BRP_STUB get() = ByteReadPacket.Empty -/** - * The second outermost packet for login - * - * int headRemaining.size+4 - * int sequenceId - * int subAppId - * int subAppId - * hex "01 00 00 00 00 00 00 00 00 00 01 00" // unknown values - * int extraData.size+4 - * byte[] extraData - * int commandName.length+4 - * byte[] commandName - * int 4+4 - * int 0x02B05B8B - * int imei.length+4 - * byte[] imei - * int 0+4 - * int ksid.length+4 - * byte[] ksid - * int 0+4 - * - * int bodyRemaining.size+4 - * byte[] body() - */ @UseExperimental(MiraiInternalAPI::class) internal inline fun BytePacketBuilder.writeSsoPacket( client: QQAndroidClient, @@ -266,26 +237,6 @@ internal inline fun BytePacketBuilder.writeSsoPacket( writeIntLVPacket(lengthOffset = { it + 4 }, builder = body) } - -/** - * Writes a request packet - * This is the innermost packet structure - * - * **Packet Structure** - * byte 2 // head flag - * short 27 + 2 + remaining.length - * ushort client.protocolVersion // const 8001 - * ushort 0x0001 - * uint client.uin - * byte 3 // const - * ubyte encryptMethod.value // [EncryptMethod] - * byte 0 // const - * int 2 // const - * int client.appClientVersion - * int 0 // const - * bodyBlock() - * byte 3 // tail - */ @UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class) internal fun BytePacketBuilder.writeOicqRequestPacket( client: QQAndroidClient, @@ -294,8 +245,6 @@ internal fun BytePacketBuilder.writeOicqRequestPacket( bodyBlock: BytePacketBuilder.() -> Unit ) { val body = encryptMethod.makeBody(client, bodyBlock) - // writeIntLVPacket(lengthOffset = { it + 4 }) { - // Head writeByte(0x02) // head writeShort((27 + 2 + body.remaining).toShort()) // orthodox algorithm writeShort(client.protocolVersion) @@ -309,72 +258,7 @@ internal fun BytePacketBuilder.writeOicqRequestPacket( writeInt(client.appClientVersion) writeInt(0) // constp_always_0 - // Body writePacket(body) - // Tail writeByte(0x03) // tail - // } -} - - -/* -00 00 01 64 -00 00 00 0A -02 -00 00 00 04 -00 - -00 00 00 0E -31 39 39 34 37 30 31 30 32 31 - -// encrypted with 16zero -F8 22 FC 39 2E 93 D7 73 A9 75 A2 D4 67 D2 C4 0D F1 02 1F A5 74 8F D8 0E 8E 86 AF 4F 4A A9 C7 74 56 71 B9 03 FC B3 DE A0 F3 14 B7 E9 54 3B 22 F0 24 10 BD 52 88 FC F3 58 66 6C B9 DB 4D 45 2C EF DE 2C C9 E1 1B 27 C7 E2 EF 38 6A 7E 8B 52 3A F4 93 40 E1 A9 ED 10 C3 A3 7E 64 17 02 8F 5C 01 92 72 C7 B8 E0 E1 A5 AF 0B 27 D0 05 C1 33 37 77 37 6D 96 0B B4 1F 41 98 42 35 2C 2A 00 E4 ED E8 C6 42 C4 F4 FD 13 39 D8 E8 19 50 E9 49 06 37 CA CF 42 C3 DD B5 DC B0 E9 87 83 6E 77 AE B6 5C F5 0D 6A 08 67 D0 61 B0 86 39 F7 2E AF E7 B7 C5 F4 42 40 A1 E1 A9 90 55 26 BD C6 03 73 73 BF A2 0A 3F E6 D3 8D B3 69 63 81 83 1E F1 72 5D FA FC 5E 65 B9 C1 FE 77 A8 50 80 F1 A5 DF E0 C4 96 1D 21 CD 5B 70 62 35 51 B5 37 1F 0B 4A 6D 97 92 D0 33 2B 56 11 CB 54 E5 6A A4 B9 97 04 B3 4B 27 A6 61 B7 77 5C C0 D1 6B 98 1C 7A 7B 57 28 3B 80 3B 81 88 69 D2 1C 91 B8 4A DE 0F FD A2 82 F8 3B F6 61 90 84 EF 4A 17 B6 30 1D 09 62 11 C7 BB 00 76 8E 0D 48 1B 11 F4 90 7A 13 0F 09 2B 4E 2F BE FD D9 57 07 18 29 4C 52 23 2E AE - -//decrypted: -00 00 00 C1 - 00 01 4E 6A - 20 02 ED BD - 20 02 ED BD - 01 00 00 00 00 00 00 00 00 00 01 00 - 00 00 00 4C - B8 12 0D E1 DA 19 AF D3 EB 36 76 BD 42 08 F6 DC A5 35 69 C0 8F F2 75 28 B4 CE 09 C9 B7 86 E3 5A 14 D1 0D CA 5D D4 CB 16 77 8B 32 8D 81 3B 3F D9 52 13 77 03 D3 F7 0E CD 7B 21 95 D2 59 CE 0C 31 D6 F1 38 2A FA 82 AD 60 - 00 00 00 14 - 47 72 61 79 55 69 6E 50 72 6F 2E 43 68 65 63 6B // serviceCommand - 00 00 00 08 - 02 B0 5B 8B - 00 00 00 13 - 38 35 38 34 31 34 33 36 39 32 31 31 39 39 33 - 00 00 00 04 - 00 22 - 7C 34 35 34 30 30 31 32 32 38 34 33 37 35 39 30 7C 41 38 2E 32 2E 30 2E 32 37 66 36 65 61 39 36 00 00 00 04 - -00 00 00 7A // UniPacket - 10 - 03 2C - 3C 42 00 01 4E 69 56 22 4B 51 51 2E 43 6F 6E 66 69 67 53 65 72 76 69 63 65 2E 43 6F 6E 66 69 67 53 65 72 76 61 6E 74 4F 62 6A 66 09 43 6C 69 65 6E 74 52 65 71 7D 00 00 35 08 00 01 06 03 72 65 71 1D 00 00 29 0A 12 20 02 ED BD 26 0A 31 39 39 34 37 30 31 30 32 31 36 00 46 12 31 30 31 31 30 33 30 38 33 38 34 36 30 36 32 30 34 32 0B 8C 98 0C A8 0C - - */ -/* -00 00 00 FC -00 00 00 0B -01 // packet type? -00 01 50 DE -00 - -00 00 00 0E -31 39 39 34 37 30 31 30 32 31 - -4E 32 1B 0F 07 DC 39 FE 14 78 ED 32 60 C4 07 31 9D CD 1A E0 C4 F6 21 6B EA 52 A4 F4 C1 D2 AF FB 17 5A C4 15 BC 35 BC 45 58 B6 11 19 DA AF 12 91 B5 A0 5D E4 FD 5A 49 1A 55 71 45 89 6F 3A 09 E6 32 F4 96 4A BB B2 EE 35 B9 39 63 5B FF E3 F0 94 69 67 99 64 A2 03 23 D0 F7 74 81 D1 20 F8 20 E6 F3 5B E6 C2 A2 25 6F 90 C5 DA CB D2 08 9D 5D 83 47 F3 27 3F 41 19 E5 9A C0 F2 05 70 B2 C5 DC F9 F1 6D 2A E9 92 84 9C 8D 98 04 E8 A1 3B 40 F2 71 60 9F 2C D8 6A CD 6B F5 2B 12 68 C7 9C 6B 0E D2 F7 16 40 47 72 3D 6A AF 36 2E 43 0C 96 28 C7 A6 B1 04 3B 29 F6 8B A4 E0 47 1A 3D 51 32 C7 AF A5 7E FD F7 50 FC 81 3D 13 45 60 6B 8D F4 A6 9B E7 46 D4 1E 9B 2C 00 D0 24 2F 0E 44 29 43 A8 F6 25 - - */ -/* -00 00 01 04 -00 00 00 0B -01 -00 01 50 CE -00 - -00 00 00 0E 31 39 39 34 37 30 31 30 32 31 D2 D5 37 8A 3C 47 B1 84 E2 94 B2 AF BF 14 70 4D 73 17 BB 38 BE 82 73 DF A2 87 E0 0A 7A BA 8A 81 71 77 1D E1 71 7F B7 C1 66 1D 8C 3D 41 4F 51 09 6A B7 B7 7B 88 28 A6 5A AB 7E 40 25 9B C8 35 9C C6 E2 3A 5F 94 1D 70 0F D7 89 4D 41 6B 7A 29 A2 70 77 3D F8 1D 32 65 D7 D8 D1 6D 13 42 9C 0C 72 DB 48 95 4B 66 EF B9 E6 E4 C1 3B 2C 36 B0 D7 3F E2 85 C8 2A 8C 65 0F 0B 1C F1 A7 C7 E1 1F 0C 32 F5 08 14 AA 5A 43 CD 8E A8 82 14 24 97 63 F0 53 79 4E 33 8D 5F 1C F8 1C 89 3B 39 44 CC A7 63 5F FC BF 87 42 89 2D A5 F4 BC B2 69 49 54 DD AE E6 3F A2 A2 98 DC 3B D4 A2 27 10 F2 06 42 93 C5 30 4A D4 FA F5 BA A5 B2 4B 56 45 59 94 CA 4C 4B 17 55 C7 23 AF F0 8B E5 DC 3A 1B B6 A7 2E 10 BB 9A E7 70 54 BA F5 4B 70 91 - - */ \ No newline at end of file +} \ No newline at end of file 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 622c7b062..cc1e30ba7 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 @@ -5,8 +5,6 @@ import kotlinx.io.pool.useInstance import net.mamoe.mirai.data.Packet import net.mamoe.mirai.event.Subscribable import net.mamoe.mirai.qqandroid.QQAndroidBot -import net.mamoe.mirai.qqandroid.io.serialization.loadAs -import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.OnlinePush import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList @@ -24,19 +22,31 @@ import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract import kotlin.jvm.JvmName + +internal sealed class PacketFactory { + /** + * 筛选从服务器接收到的包时的 commandName + */ + abstract val receivingCommandName: String +} + /** - * 一种数据包的处理工厂. 它可以解密解码服务器发来的这个包, 也可以编码加密要发送给服务器的这个包 + * 一种客户端主动发送的数据包的处理工厂. + * 它必须是由客户端主动发送, 产生一个 sequenceId, 然后服务器以相同的 sequenceId 返回. + * 必须在 [KnownPacketFactories] 中注册工厂, 否则将不能收到回复. * 应由一个 `object` 实现, 且实现 `operator fun invoke` 或按 subCommand 或其意义命名的函数来构造 [OutgoingPacket] * * @param TPacket 服务器回复包解析结果 */ @UseExperimental(ExperimentalUnsignedTypes::class) -internal abstract class PacketFactory( +internal abstract class OutgoingPacketFactory( /** * 命令名. 如 `wtlogin.login`, `ConfigPushSvc.PushDomain` */ val commandName: String -) { +) : PacketFactory() { + final override val receivingCommandName: String get() = commandName + /** * **解码**服务器的回复数据包. 返回的包若是 [Subscribable], 则会 broadcast. */ @@ -48,34 +58,81 @@ internal abstract class PacketFactory( open suspend fun QQAndroidBot.handle(packet: TPacket) {} } +/** + * 处理服务器发来的包的工厂. + * 这个工厂可以在 [handle] 时回复一个 commandId 为 [responseCommandName] 的包, 也可以不回复. + * 必须先到 [KnownPacketFactories] 中注册工厂, 否则不能处理. + */ +internal abstract class IncomingPacketFactory( + /** + * 接收自服务器的包的 commandName + */ + override val receivingCommandName: String, + /** + * 要返回给服务器的包的 commandName + */ + val responseCommandName: String = "" +) : PacketFactory() { + /** + * **解码**服务器的回复数据包. 返回的包若是 [Subscribable], 则会 broadcast. + */ + abstract suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): TPacket + + /** + * 处理解码后的包, 返回一个 [OutgoingPacket] 以发送给服务器, 返回 null 则不作处理. + */ + open suspend fun QQAndroidBot.handle(packet: TPacket, sequenceId: Int): OutgoingPacket? { + return null + } +} + @JvmName("decode0") -private suspend inline fun

PacketFactory

.decode(bot: QQAndroidBot, packet: ByteReadPacket): P = packet.decode(bot) +private suspend inline fun

OutgoingPacketFactory

.decode(bot: QQAndroidBot, packet: ByteReadPacket): P = packet.decode(bot) + +@JvmName("decode1") +private suspend inline fun

IncomingPacketFactory

.decode(bot: QQAndroidBot, packet: ByteReadPacket, sequenceId: Int): P = + packet.decode(bot, sequenceId) internal val DECRYPTER_16_ZERO = ByteArray(16) internal typealias PacketConsumer = suspend (packetFactory: PacketFactory, packet: T, commandName: String, ssoSequenceId: Int) -> Unit +/** + * 数据包相关的调试输出. + * 它默认是关闭的. + */ @PublishedApi internal val PacketLogger: MiraiLoggerWithSwitch = DefaultLogger("Packet").withSwitch(false) +/** + * 已知的数据包工厂列表. + */ @UseExperimental(ExperimentalUnsignedTypes::class) -internal object KnownPacketFactories : List> by mutableListOf( - LoginPacket, - StatSvc.Register, - OnlinePush.PbPushGroupMsg, - MessageSvc.PushNotify, - MessageSvc.PbGetMsg, - MessageSvc.PushForceOffline, - MessageSvc.PbSendMsg, - FriendList.GetFriendGroupList, - FriendList.GetTroopListSimplify, - ConfigPushSvc.PushReq -) { +internal object KnownPacketFactories { + object OutgoingFactories : List> by mutableListOf( + LoginPacket, + StatSvc.Register, + MessageSvc.PbGetMsg, + MessageSvc.PushForceOffline, + MessageSvc.PbSendMsg, + FriendList.GetFriendGroupList, + FriendList.GetTroopListSimplify + ) + + object IncomingFactories : List> by mutableListOf( + OnlinePush.PbPushGroupMsg, + MessageSvc.PushNotify, + ConfigPushSvc.PushReq + ) // SvcReqMSFLoginNotify 自己的其他设备上限 // MessageSvc.PushReaded 电脑阅读了别人的消息, 告知手机 // OnlinePush.PbC2CMsgSync 电脑发消息给别人, 同步给手机 - fun findPacketFactory(commandName: String): PacketFactory<*>? = this.firstOrNull { it.commandName == commandName } + @Suppress("MemberVisibilityCanBePrivate") // debugging use + fun findPacketFactory(commandName: String): PacketFactory<*>? { + return OutgoingFactories.firstOrNull { it.receivingCommandName == commandName } + ?: IncomingFactories.firstOrNull { it.receivingCommandName == commandName } + } // 00 00 08 70 00 00 00 0A 01 00 00 00 00 0E 31 39 39 34 37 30 31 30 32 31 F5 45 50 03 B7 F7 99 8F DC CE F6 A2 35 08 04 85 D6 1D 52 90 24 13 86 A2 9D 40 D9 CD BF 4B 08 56 E7 EF 37 E6 E7 BE 09 FD A8 E5 D8 DA 07 90 E5 CB 22 1A 5A 77 88 B5 1A 0B 36 2A 71 59 1C 79 7C B1 84 39 CF 74 31 C5 ED 4D BB 12 F3 BB 10 B2 2E CD 05 82 86 AC 78 68 74 C3 42 9F CF F9 14 0D D4 2B 89 E9 FC 4D 1D 29 F3 08 A0 3A 62 F3 B5 71 D3 A9 06 BD 45 BA 50 D6 2D 68 05 B7 B4 D3 07 D0 01 A4 F4 71 0A 76 34 1F CA 2D 3A 53 6A C5 44 CA 56 C9 FA 0F 81 5E 06 63 45 9B BD FA 81 D3 50 46 74 34 C2 A8 21 9B 1B 25 E6 23 38 E5 87 B4 D2 A7 E7 59 65 03 BB 6D 46 D5 21 66 F6 2F 2D BF A3 77 2A 33 9D E1 35 18 45 CE 22 DB C1 52 BB 87 B9 F0 CB B1 CD 39 81 43 BD C1 E5 2B 81 DE 29 EC 72 2A 56 14 23 67 7B 60 F7 FB C1 7F 9C 18 8E ED 67 35 3E 2F EA D1 EA 24 AD 12 6D 65 B3 27 0C 2B 0A 43 42 3E 0C 81 C5 02 7D E6 A5 2C 79 8D 53 2D 06 F1 EE A5 51 BC 24 A6 F5 F2 0C BC 1F 42 F2 21 8F FB DF 9C 98 6F 25 FB D0 09 E1 F3 85 76 A2 96 39 5E 73 06 24 F8 1E 6C F7 D3 03 15 44 BA 6B 42 9E CE 14 7B 1A F9 0B A1 9A 85 FD 52 2B 34 FB 0F D8 6F 34 38 6E F3 A2 7D EB DF 3F 55 6A 52 27 35 44 5C 26 05 F3 36 8E 8F 00 D2 31 85 BF 20 8A 1C 37 57 C4 74 36 BF 89 3F 44 3C 97 AA 6B 8F D1 B6 CD D6 45 88 F1 74 35 CD 8B 85 9F 60 F4 B7 00 3E 87 10 C4 3F 7C 3F 22 F0 20 58 40 CE E6 77 8B 3D EE AA EB 31 52 65 BE C4 12 2B 28 65 1A 26 16 55 E9 86 28 90 42 FD 48 D6 6F E6 63 E2 40 3F BE 68 C6 FE A7 B2 10 31 15 7E B4 C7 2C 8D D9 04 8D AD 8E 45 D2 CA EC 07 D6 D0 14 FD 93 02 4B 3D 71 6E 3E 1F D5 BC ED 98 0E 01 6B FE 1C 96 24 34 DF A3 E3 EE 67 40 F3 C7 AA 10 4E 44 62 49 D5 45 14 15 49 04 2F 9F FC 5D 40 F7 5A CC C1 78 7B 37 35 80 F9 10 80 EB 40 DB 33 06 5F 2A 70 88 F0 94 49 59 48 4B 00 66 28 E9 E9 E7 CE E4 CA 6D 21 79 09 62 7A 6E C5 47 A4 08 85 73 43 35 2D EE E4 0E 85 47 92 B4 F1 5C 76 C2 72 BC D1 70 41 6D 9B EE F4 47 67 1F 63 57 B9 65 C1 08 5C 42 D6 28 FB 6F F5 1A 4B E0 B7 5A 36 75 E6 BE ED C6 67 DA 64 19 09 11 CF 9A 74 4A F4 4E 4F 1E 02 2C 8C 21 21 DE 76 15 34 E5 F2 DF F9 34 31 99 4F 4B B2 5E E6 2B 8D 7C 64 E9 7D 78 98 4F 28 FF 2E 95 1B 5D 8E 2F 70 E6 01 0A 82 18 90 16 8F 98 5E 0F CA 30 4F 36 AF 9B 5E 2B 5B FE 59 5E 11 BC A5 68 64 55 BD 04 CE 43 60 4C C9 CB F7 88 D2 30 7A 89 75 3D 93 9D A9 D0 CE 7D 4B CE 4D 14 5E 95 0E 18 3E 75 AE 20 C6 8A 6E 15 F9 39 58 3B 17 74 99 98 07 5D 68 B1 51 57 AF 1D 85 F1 A5 8A FE 9F 07 BC CB B9 84 A5 49 AE 9F F4 50 06 27 24 7F EB 66 C0 F7 C4 4F E9 74 FA 69 8E D0 A6 A4 3E 8A A8 D9 10 A1 05 03 0F B1 E7 80 22 A9 21 22 FA 31 A1 61 0E 5A 42 75 5F 19 95 2E FE A9 38 51 BB E9 C1 6B 29 CD AE 8F 78 7C 1F A4 81 F2 20 D3 15 C1 EA 42 BD 5F 52 C1 BA 5F C7 42 97 A8 F1 FA C6 20 82 3C 00 36 96 75 69 27 FE 93 AA BD 43 BD 0E FD ED 30 97 A6 B2 A2 E8 D3 75 C2 BF 35 EC 78 8A 3E 23 9D 6D DD 3C D4 4A BC 5A A8 74 86 3C A7 31 F5 F3 8A 78 9C 3C 75 88 B1 35 4A 83 91 EB 5F 80 F3 E0 0C EC 82 5C 7B 08 61 45 E3 3B 7B F1 1F BC 6D 5E 99 3A 34 68 28 20 42 8C 42 C9 0A 3F 32 42 03 E5 9A 71 BB E1 02 C9 B4 98 6E 73 7E EC 81 79 28 01 A8 E5 AC 0F 24 0A 58 DA C1 D2 F0 2C 94 E7 4D E5 ED B3 43 58 23 73 1D 7F 33 B0 7B 1A A8 C1 AC 6E 7C F1 A6 51 0F CF E9 51 5F 06 EB 79 C4 0C E9 78 6C B8 B8 11 C0 2E 84 BC F4 4D 05 D5 B5 90 20 30 BE 73 28 83 91 3B 4D 90 2E 8F A5 A8 BF 85 63 29 05 04 33 14 7D 24 24 7D 02 9B 39 5D 30 D0 68 58 57 1A 0D 67 A6 EF 44 4C 4E 92 14 0A 2A E4 24 1E 60 78 A3 65 71 7E E3 B2 44 E1 55 3E F2 08 05 F5 59 5E EE D3 0A 12 34 C2 FC 74 4A 8C F9 BE 7F 4D EC 9E D3 14 97 7F DF 75 E2 52 21 95 65 99 F4 1D 01 AD F4 D2 4D 8C 9E 5A 16 DE 65 AA D0 AC 24 17 FE BE B9 D8 9B FB 36 33 E5 AE 1B F9 B1 AE A4 9B 15 94 91 6D 45 BE 61 33 4B 71 40 BC DB D0 BF 06 39 83 D5 5F 30 6D E0 20 D3 33 AA 78 13 DA 9A 80 A3 38 4F 3B F8 AE B9 7F 9B B7 F1 AD 10 88 96 DD 79 DD F8 86 A3 72 A2 3F C2 6E B2 6D CE 36 54 90 5F DE 23 90 CD BD BD DB 95 83 5A 94 8E B8 54 AF 0A AB 10 0C 15 B3 3D 2B 89 7D 83 64 B9 29 08 50 40 6E F6 EC 8D E7 79 6C 2B 70 A5 07 FA AD 6A A1 54 EC D7 C7 70 A6 9F 8F 8E 5B 00 5E 8D 27 0D 21 8B 38 31 02 88 13 6E F4 5C 8D 15 82 FC 3E AE 57 17 3D 6D 38 F9 8C 2B EF 87 FA 30 FB 59 D4 E2 49 CF 76 75 9C 9D 50 8D 4A CD AE F6 3C 59 E8 92 BB C1 E2 5C F6 96 8B DC 78 DF E1 27 6B F1 1C D9 68 1D 29 8A E3 09 DD 28 C7 0A ED BB 75 6B D9 87 9F 7F 71 5D D0 EE 03 5B 28 52 40 26 DD C9 C4 52 4D 58 02 3A 71 BE 6C F4 6A 30 14 52 72 CB 45 95 80 DE 28 02 8A 22 7A 05 B5 D7 22 61 06 E0 34 09 AC A9 A8 A8 D0 DF 37 BE 3F 86 33 CA B0 EA 27 A5 95 A5 F8 1C A9 C5 46 41 EB DF C8 5F AD 85 7A 0E A8 AD A9 2A BF F3 6F 39 0D AE 60 30 B2 23 3C D0 37 85 18 01 2E 4E 74 0B 5D 98 2E 1E 3B 3F 30 DC CB DA 1E 0A 4F 0B 70 74 54 28 4F 82 6C 11 7E 5C 7E 33 C7 BB 47 29 2B F6 92 01 3F 83 AE 50 CC 6E B5 87 3B D4 F6 3A 6D 8D 0D 98 37 AB A6 08 79 EE E9 AB 38 37 FA 22 4C 54 80 1F 88 E9 E9 45 37 7A AF DB 61 A9 37 61 30 05 38 46 E4 CD ED B4 71 B2 C7 2E 1F 4C 92 27 C5 AF 3C D9 26 60 1F 4E 65 5E EF F7 A7 9C CC 49 F5 20 58 60 47 ED 44 DF EF FF AD 91 24 28 28 A4 03 F3 10 1B E5 18 0D 49 FA 68 A3 F2 BA 77 32 E4 16 35 66 8F 2C 8E 04 19 5A 26 AE 8C EB D1 C4 6F 0E 38 85 B7 3C 79 F4 98 29 35 FF DF 13 03 FE 36 D7 0A 20 3D 28 14 DE A1 D4 12 5B 6B D0 BF 53 4C AB 36 4E 3A FB 91 73 9C 39 F0 AB 10 1A 25 D6 D6 AC 2F 68 E5 33 67 23 EF 7A 97 70 2C F7 0B 67 0F A6 11 CB AB EF A9 3F 67 5B 8D 1B 39 C9 99 56 79 92 44 6E 1B 6F EE FE E9 08 9C 8B D6 5D 5A 8E 7B BD 61 A4 97 B2 78 75 98 5D C3 19 79 28 26 8B 00 32 D3 E1 3A 02 7F 12 D1 02 2C 5D 27 B3 F0 A6 8B 9D B1 01 01 EC AB 0F 6D D5 E4 0B B0 BD 54 9C 73 CD C0 AB F8 7E D4 D4 D3 3C E9 05 B3 30 30 3D C6 A4 70 EA 0B D1 47 CB 71 41 27 09 DA FE 4A 0F D2 1C 28 EF A6 3E 7A F6 05 A0 52 72 A3 C0 05 BC 8E 38 69 C5 16 AD 98 9D 96 4F FB 95 1D BD B7 12 26 AB 7D E2 EA 57 2C BB 1C 12 C9 FF 90 FB 6B 4F 3D FE 26 7D 4B FF A6 8D 4C D7 FA 4E ED B1 5F 5B 92 92 68 B5 25 0C BC 56 C7 AE 01 C4 05 9A A6 7E 97 93 4E 15 67 83 40 F7 45 8C F8 FB D8 C4 5A D0 94 15 AF 33 24 4A 4E 43 A6 B7 D4 AC 0C EB 39 C9 83 D3 E1 CE 36 6B AC CE FD 3C 92 2D 5D C2 6A 1C C4 54 21 4E 06 8B BB CB 7D B4 C2 FF 53 00 3C A4 47 98 AC 7E 29 AF B2 AB EB 25 1A 7E 3C E0 C6 DF 65 13 64 C1 94 EA 86 3F CD 54 E1 5E C5 95 3D F8 C0 A5 6B 28 CA 4F B4 5A E6 93 CE 49 5E AD CD A1 6E B8 94 9D C4 C3 0E 37 C4 10 A8 C0 47 17 C4 EE 3D 61 B5 80 ED EF 5B CC B4 49 69 10 4D E9 CD 22 B3 1B 1C 52 29 9D 6D B2 84 76 C3 CE 3C 23 39 0D 68 02 6B 1F 3F 28 DA 59 78 AE EA D8 F4 E0 1B 90 21 81 77 23 52 05 53 A1 BD E7 50 1C 24 26 9F 1D 39 E4 F2 A0 F8 7E F7 29 58 41 98 12 62 1A 23 B3 D9 A4 5C D3 15 0D 04 31 48 03 1B CC 5F A0 D1 A9 75 5C D0 FD 8A 9C FA 24 89 B2 C3 A9 C2 13 5B CD 1C F9 B1 63 C7 01 D7 BD 0D 43 2F CB 6C 4B 4F 0D // 00 00 08 E0 00 00 00 0A 01 00 00 00 00 0E 31 39 39 34 37 30 31 30 32 31 B4 16 A6 D7 A3 E4 9E 53 99 CD 77 14 70 1F 51 3E 8B 79 F6 93 2B E0 92 E4 32 E2 87 6C 3A 9C 1B 29 87 CB 3C 60 45 9C 41 71 63 6A F6 99 FC 05 01 68 86 B3 6F 37 97 52 C5 D3 0E 66 B3 F6 40 CC EB 18 A3 AE 15 3E 31 B1 E9 7C 6F EC E4 4D 31 F1 1E 2C 0C 1C 45 66 CD F7 1B 90 11 9A D8 CE DD 6D 6C 63 9F EB CD 69 33 AF 6C 8E BA 8C CB C3 FF 27 A2 A6 C3 28 06 4A B5 79 79 12 AB 52 04 62 CA 7D 11 59 85 5C 0B D6 8D 2A E7 9C 04 97 62 7D 05 11 3E 2C 11 60 E3 E3 B3 DA 7A 7C 13 AF 22 01 53 80 69 D0 F9 C8 86 EC 25 8C F3 67 5C 82 45 08 FB 34 43 50 01 0E EA 43 77 D8 CF EC 55 E6 4E 66 5B 26 21 C9 E8 78 92 AE 5C 61 F0 5E 0B E7 34 1F 53 D6 EA 28 9C 02 1A E9 F0 55 61 4B 06 F8 56 3B AC 93 B2 2C CD 66 0D D1 18 CB BD 29 50 DE 0F 82 6D 28 63 AB 21 E1 6C BA B1 9F 69 A4 E3 C9 20 F8 11 82 39 04 2B 54 44 50 FA 2E 86 68 6D DC 5D 9E 18 F4 DD 19 09 BC CF E8 41 68 A3 8D 86 42 80 51 C4 C1 ED 54 DB 50 F5 1D A7 28 2A 0D E8 14 1A 4E F7 96 29 00 6C 9D 4A 2E 3E 7B 4C AC 20 78 F1 3C 70 6B 61 96 D7 EC 77 AD CB AD AF BB 47 C3 1F A0 6C 6C 9C 9F F3 6C EB 6C A4 D0 7F 2B E1 AA 68 26 99 B9 C8 A1 F5 C4 7E E7 E7 81 EE 66 00 96 33 49 C0 EE A2 F9 F6 52 C5 A6 5D EE 9D C5 E5 CE DA 31 FC FF 4B 02 97 68 3D 6A 99 4A CF 69 D9 F4 53 68 31 E7 32 2F 85 E7 7F 16 82 AE FA 73 D5 42 09 9C CB 53 26 79 41 63 80 B0 E2 6A 8B B9 C6 71 08 B4 2B E0 48 D3 C4 0F B0 00 D0 FA 8C 29 DE E9 71 6A D7 89 76 E7 5D 33 14 10 6F E2 44 6A A0 DC C1 CB F3 9A C3 13 CB D1 82 2C DF 34 68 79 E3 09 BD CC 2B 25 79 A8 E7 BE 29 6C 97 C3 D7 F4 0E CC 2B 74 71 02 BA 2B 5B 57 1B C2 C8 C2 BF 54 23 72 EA E4 38 54 20 7D 88 E4 39 7C C5 8A 1B C0 EC D2 1E 7D 1B 6B 7A BC EC 73 1E 53 4A 6F 4F EA F0 56 12 80 BD 0B 37 67 BD FD A8 29 23 2D 8E 66 7E 31 A9 F6 CE 7E BC 4F 38 D0 33 D4 C7 4A E9 43 9D 28 2E 8F 7C D5 81 F4 8C F9 6F 21 AC A1 08 FD F4 01 FB E8 CE 61 91 BE 68 5B E4 3A 5F F8 FB DA 5D 9B 2A AF E2 0C D3 A4 1F 42 90 96 E1 28 44 85 8D E1 CF 19 A9 47 04 8D 28 D9 B3 35 79 48 70 D9 ED 45 B6 24 B5 56 FA 1E DE 02 F3 EB 69 08 7D 24 9C 60 35 97 8D 13 4A 5A 57 BA B3 14 C1 EE 70 22 CA B2 65 F7 BB 3F A2 D9 14 AA 4C 52 E6 E4 10 D3 FD C6 2B DD BF C0 CF E5 35 57 9E 9F D0 77 C8 E6 EF 2B 8E 01 88 96 F8 68 95 A7 0D 58 81 30 60 88 44 CC 31 5B C1 D4 92 6E ED 17 CA 0A 01 69 90 4E 6A C0 D7 09 6C E5 33 64 CA 6E 5C 07 C3 AD 46 36 F9 DF DE B7 71 B2 87 CB 3D 76 C0 44 B8 6B 15 27 B2 03 99 C7 51 8A 00 35 C9 1C 76 55 32 AE 49 5A 34 6A 4E FD 20 7A 24 BF 34 E8 B4 18 BC 92 64 A1 F3 0A 2E 7B 00 EA B6 52 E7 AC 34 FD AE FF 1E 5D 6D D6 1F 6D 06 31 09 9D A9 9C 86 DB 5E 05 07 BA 4A 49 2B D2 7F EE 88 64 B2 6F 15 70 39 1B E9 57 6A 4E 29 4A A4 57 EA 80 3D 86 4C E9 F7 F5 2B C4 9F 35 62 76 09 0E 1C A4 99 50 99 82 2F 84 90 0E 9E 9F 75 C3 15 B0 61 34 D1 67 2D 30 16 FE D3 BF 59 6A B1 74 02 C4 EF 92 85 E0 16 4B 0C C5 9D 65 BB 5D 52 8F 52 5B 7C 7B 74 D9 EC 41 A9 5B FA 2D 95 D4 AE 5D F1 68 88 F6 82 ED 09 05 21 2E 5D 93 64 A0 96 15 64 A6 50 3C 03 2B FC 3E 80 89 90 62 CC D9 23 8E D7 BD 05 02 30 86 32 31 6A 5F F8 C4 BD 61 D0 CE B9 54 4E 93 E9 AE B9 4F 2B 98 DC 23 31 CC A8 06 89 A8 08 60 99 DC D4 81 98 13 C9 27 36 32 24 C1 B0 6B F0 3D EB CC 3B 32 5F 20 72 23 B3 DF 0B 48 3C 35 FD F1 FB DC 3E 2A BE B9 0F 42 56 F1 39 94 86 85 C6 1E A0 4C EC B8 69 45 5F 3D AB 3C 3B A2 70 61 91 9D 2C DD 6D C5 E9 EF 47 36 A6 A3 E0 96 C2 B8 EF 92 E9 E0 26 88 C6 B5 51 BA DE FD C5 BA 4C 6A 9A FE 6F DE B8 10 05 7F 9C 5D 40 11 39 75 CD 36 4F 6B A8 A1 94 57 5F 8F F2 D0 E2 36 A0 A4 24 05 FD 9E F5 51 93 C9 6E 5A 10 8D C3 33 2D E5 09 7A E0 DB 44 63 9C EA A5 ED BF 0B 98 32 F1 BA 04 96 F6 14 49 F1 F8 58 EA 6E 5E 5E 49 CA 2D E2 93 E6 AD 20 B2 CD 98 A7 3E BA 3E A8 @@ -139,15 +196,23 @@ internal object KnownPacketFactories : List> by mutableListOf( when (flag2) { 1 ->//it.data.parseUniResponse(bot, it.packetFactory, it.sequenceId, consumer) - { - consumer( - it.packetFactory as PacketFactory, - it.packetFactory.run { decode(bot, it.data) }, - it.packetFactory.commandName, - it.sequenceId - ) - } - 2 -> it.data.parseOicqResponse(bot, it.packetFactory as PacketFactory, it.sequenceId, consumer) + when (it.packetFactory) { + is OutgoingPacketFactory<*> -> consumer( + it.packetFactory as OutgoingPacketFactory, + it.packetFactory.run { decode(bot, it.data) }, + it.packetFactory.commandName, + it.sequenceId + ) + is IncomingPacketFactory<*> -> consumer( + it.packetFactory as IncomingPacketFactory, + it.packetFactory.run { decode(bot, it.data, it.sequenceId) }, + it.packetFactory.receivingCommandName, + it.sequenceId + ) + } + + // for oicq response, factory is always OutgoingPacketFactory + 2 -> it.data.parseOicqResponse(bot, it.packetFactory as OutgoingPacketFactory, it.sequenceId, consumer) else -> error("unknown flag2: $flag2. Body to be parsed for inner packet=${it.data.readBytes().toUHexString()}") } } ?: inline { @@ -160,22 +225,6 @@ internal object KnownPacketFactories : List> by mutableListOf( private inline fun inline(block: () -> R): R = block() - private fun parseUniFrame(bot: QQAndroidBot, rawInput: ByteReadPacket): IncomingPacket = - rawInput.debugIfFail("uni packet") { - readIoBuffer(readInt() - 4).withUse { - //00 01 4E 64 FF FF D8 E8 00 00 00 14 6E 65 65 64 20 41 32 20 61 6E 64 20 49 4D 45 49 00 00 00 04 00 00 00 08 60 7F B6 23 00 00 00 00 00 00 00 04 - val sequenceId = readInt() - - } - - // TODO: 2020/1/24 - - readIoBuffer(readInt() - 4).withUse { - debugPrintln("收到 UniPacket 的 body=${this.readBytes().toUHexString()}") - } - return IncomingPacket(null, 0, TODO()) - } - class IncomingPacket( val packetFactory: PacketFactory<*>?, val sequenceId: Int, @@ -227,7 +276,7 @@ internal object KnownPacketFactories : List> by mutableListOf( private suspend fun ByteReadPacket.parseOicqResponse( bot: QQAndroidBot, - packetFactory: PacketFactory, + packetFactory: OutgoingPacketFactory, ssoSequenceId: Int, consumer: PacketConsumer ) { @@ -276,16 +325,6 @@ internal object KnownPacketFactories : List> by mutableListOf( } } - private suspend fun ByteReadPacket.parseUniResponse( - bot: QQAndroidBot, - packetFactory: PacketFactory<*>, - ssoSequenceId: Int, - consumer: PacketConsumer - ) { - val uni = readBytes(readInt() - 4).loadAs(RequestPacket.serializer()) - PacketLogger.verbose(uni.toString()) - /// consumer(packetFactory.decode(bot, uni.sBuffer.toReadPacket()), uni.sServantName + "." + uni.sFuncName, ssoSequenceId) - } } @UseExperimental(ExperimentalContracts::class) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/image/ImageDownPacket.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/image/ImageDownPacket.kt index f6e7f6ded..118c27470 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/image/ImageDownPacket.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/image/ImageDownPacket.kt @@ -2,18 +2,18 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.writeFully -import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport import net.mamoe.mirai.data.Packet import net.mamoe.mirai.qqandroid.QQAndroidBot +import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport import net.mamoe.mirai.qqandroid.network.QQAndroidClient -import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket -import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory -import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x352Packet import net.mamoe.mirai.qqandroid.network.protocol.data.proto.GetImgUrlReq +import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket +import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory +import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket -internal object ImageDownPacket : PacketFactory("LongConn.OffPicDown") { +internal object ImageDownPacket : OutgoingPacketFactory("LongConn.OffPicDown") { operator fun invoke(client: QQAndroidClient, req: GetImgUrlReq): OutgoingPacket { // TODO: 2020/1/24 测试: bodyType, subAppId diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/image/ImageUpPacket.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/image/ImageUpPacket.kt index 8e7240b57..516bb72bc 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/image/ImageUpPacket.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/image/ImageUpPacket.kt @@ -2,18 +2,18 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.writeFully -import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport import net.mamoe.mirai.data.Packet import net.mamoe.mirai.qqandroid.QQAndroidBot +import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport import net.mamoe.mirai.qqandroid.network.QQAndroidClient -import net.mamoe.mirai.qqandroid.network.protocol.packet.* -import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket -import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory -import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x352Packet import net.mamoe.mirai.qqandroid.network.protocol.data.proto.UploadImgReq +import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket +import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory +import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket +import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket -internal object ImageUpPacket : PacketFactory("LongConn.OffPicUp") { +internal object ImageUpPacket : OutgoingPacketFactory("LongConn.OffPicUp") { operator fun invoke(client: QQAndroidClient, req: UploadImgReq): OutgoingPacket { // TODO: 2020/1/24 测试: bodyType, subAppId diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt index dfc7ebb3f..3b93a559e 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt @@ -19,9 +19,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgComm import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc import net.mamoe.mirai.qqandroid.network.protocol.data.proto.SyncCookie -import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket -import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory -import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket +import net.mamoe.mirai.qqandroid.network.protocol.packet.* import net.mamoe.mirai.qqandroid.utils.toMessageChain import net.mamoe.mirai.qqandroid.utils.toRichTextElems import net.mamoe.mirai.utils.MiraiInternalAPI @@ -36,19 +34,18 @@ internal class MessageSvc { /** * 告知要刷新好友消息 */ - internal object PushNotify : PacketFactory("MessageSvc.PushNotify") { - override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): RequestPushNotify { + internal object PushNotify : IncomingPacketFactory("MessageSvc.PushNotify") { + override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): RequestPushNotify { discardExact(8) return decodeUniPacket(RequestPushNotify.serializer()) } - override suspend fun QQAndroidBot.handle(packet: RequestPushNotify) { + override suspend fun QQAndroidBot.handle(packet: RequestPushNotify, sequenceId: Int): OutgoingPacket? { network.run { - PbGetMsg(client, MsgSvc.SyncFlag.START, packet.stMsgInfo?.uMsgTime ?: 0).sendAndExpect>() + return PbGetMsg(client, MsgSvc.SyncFlag.START, packet.stMsgInfo?.uMsgTime ?: 0) } } - } @@ -56,7 +53,7 @@ internal class MessageSvc { * 获取好友消息和消息记录 */ @UseExperimental(MiraiInternalAPI::class) - internal object PbGetMsg : PacketFactory("MessageSvc.PbGetMsg") { + internal object PbGetMsg : OutgoingPacketFactory("MessageSvc.PbGetMsg") { val EXTRA_DATA = "08 00 12 33 6D 6F 64 65 6C 3A 78 69 67 6F 6D 69 20 36 3B 6F 73 3A 32 32 3B 76 65 72 73 69 6F 6E 3A 76 32 6D 61 6E 3A 78 69 61 6F 6D 69 73 79 73 3A 4C 4D 59 34 38 5A 18 E4 E1 A4 FF FE 2D 20 E9 E1 A4 FF FE 2D 28 A8 E1 A4 FF FE 2D 30 99 E1 A4 FF FE 2D".hexToBytes() @@ -81,7 +78,7 @@ internal class MessageSvc { syncFlag = syncFlag, // serverBuf = from.serverBuf ?: EMPTY_BYTE_ARRAY, syncCookie = client.c2cMessageSync.syncCookie - ?: SyncCookie(time = Random.nextLong()).toByteArray(SyncCookie.serializer())//.also { client.c2cMessageSync.syncCookie = it }, + ?: SyncCookie(time = msgTime + client.timeDifference).toByteArray(SyncCookie.serializer())//.also { client.c2cMessageSync.syncCookie = it }, // syncFlag = client.c2cMessageSync.syncFlag, //msgCtrlBuf = client.c2cMessageSync.msgCtrlBuf, //pubaccountCookie = client.c2cMessageSync.pubAccountCookie @@ -160,7 +157,7 @@ internal class MessageSvc { /** * 被挤下线 */ - internal object PushForceOffline : PacketFactory("MessageSvc.PushForceOffline") { + internal object PushForceOffline : OutgoingPacketFactory("MessageSvc.PushForceOffline") { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): ForceOfflineEvent { discardExact(4) val struct = this.decodeUniPacket(RequestPushForceOffline.serializer()) @@ -168,7 +165,7 @@ internal class MessageSvc { } } - internal object PbSendMsg : PacketFactory("MessageSvc.PbSendMsg") { + internal object PbSendMsg : OutgoingPacketFactory("MessageSvc.PbSendMsg") { sealed class Response : Packet { object SUCCESS : Response() { override fun toString(): String = "MessageSvc.PbSendMsg.Response.SUCCESS" @@ -230,9 +227,9 @@ internal class MessageSvc { elems = message.toRichTextElems() ) ), - msgSeq = client.atomicNextMessageSequenceId() - // msgRand = 123 - //syncCookie = client.c2cMessageSync.syncCookie?.takeIf { it.isNotEmpty() } ?: + msgSeq = client.atomicNextMessageSequenceId(), + //msgRand = Random.nextInt() and 0x7FFF, + syncCookie = client.c2cMessageSync.syncCookie?.takeIf { it.isNotEmpty() } ?: EMPTY_BYTE_ARRAY //SyncCookie(currentTimeSeconds, Random.nextLong().absoluteValue, Random.nextLong().absoluteValue).toByteArray(SyncCookie.serializer()) // msgVia = 1 ) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.PbPushGroupMsg.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.PbPushGroupMsg.kt index 2d73a3ae1..fd2ef8492 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.PbPushGroupMsg.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.PbPushGroupMsg.kt @@ -11,7 +11,7 @@ import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgOnlinePush -import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory +import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory import net.mamoe.mirai.qqandroid.utils.toMessageChain @@ -19,9 +19,9 @@ internal class OnlinePush { /** * 接受群消息 */ - internal object PbPushGroupMsg : PacketFactory("OnlinePush.PbPushGroupMsg") { + internal object PbPushGroupMsg : IncomingPacketFactory("OnlinePush.PbPushGroupMsg") { @UseExperimental(ExperimentalStdlibApi::class) - override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GroupMessage { + override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): GroupMessage { // 00 00 02 E4 0A D5 05 0A 4F 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 18 52 20 00 28 BC 3D 30 8C 82 AB F1 05 38 D2 80 E0 8C 80 80 80 80 02 4A 21 08 E7 C1 AD B8 02 10 01 18 BA 05 22 09 48 69 6D 31 38 38 6D 6F 65 30 06 38 02 42 05 4D 69 72 61 69 50 01 58 01 60 00 88 01 08 12 06 08 01 10 00 18 00 1A F9 04 0A F6 04 0A 26 08 00 10 87 82 AB F1 05 18 B7 B4 BF 30 20 00 28 0C 30 00 38 86 01 40 22 4A 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 12 E6 03 42 E3 03 12 2A 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 22 00 2A 04 03 00 00 00 32 60 15 36 20 39 36 6B 45 31 41 38 35 32 32 39 64 63 36 39 38 34 37 39 37 37 62 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 31 32 31 32 41 38 C6 BB 8A A9 08 40 FB AE 9E C2 09 48 50 50 41 5A 00 60 01 6A 10 4E 18 58 22 0E 7B F8 0F C5 B1 34 48 83 74 D3 9C 72 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 31 39 38 3F 74 65 72 6D 3D 32 82 01 57 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 30 3F 74 65 72 6D 3D 32 B0 01 4D B8 01 2E C8 01 FF 05 D8 01 4D E0 01 2E FA 01 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 34 30 30 3F 74 65 72 6D 3D 32 80 02 4D 88 02 2E 12 45 AA 02 42 50 03 60 00 68 00 9A 01 39 08 09 20 BF 50 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00 8A 04 04 08 02 08 01 90 04 80 80 80 10 B8 04 00 C0 04 00 12 06 4A 04 08 00 40 01 12 14 82 01 11 0A 09 48 69 6D 31 38 38 6D 6F 65 18 06 20 08 28 03 10 8A CA 9D A1 07 1A 00 discardExact(4) val pbPushMsg = ProtoBufWithNullableSupport.load(MsgOnlinePush.PbPushMsg.serializer(), readBytes()) @@ -48,9 +48,5 @@ internal class OnlinePush { } ) } - - override suspend fun QQAndroidBot.handle(packet: GroupMessage) { - - } } } \ No newline at end of file diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendListPacket.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendListPacket.kt index 0d301896a..ca27136d0 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendListPacket.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendListPacket.kt @@ -14,7 +14,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.jce.* import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Vec0xd50 import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket -import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory +import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket import net.mamoe.mirai.utils.io.discardExact @@ -22,7 +22,7 @@ import net.mamoe.mirai.utils.io.discardExact internal class FriendList { internal object GetTroopMemberList : - PacketFactory("friendlist.GetTroopMemberListReq") { + OutgoingPacketFactory("friendlist.GetTroopMemberListReq") { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GetTroopMemberList.Response { TODO() } @@ -65,7 +65,7 @@ internal class FriendList { } internal object GetTroopListSimplify : - PacketFactory("friendlist.GetTroopListReqV2") { + OutgoingPacketFactory("friendlist.GetTroopListReqV2") { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GetTroopListSimplify.Response { val res = this.decodeUniPacket(GetTroopListRespV2.serializer()) return Response(res.vecTroopList.orEmpty()) @@ -109,7 +109,8 @@ internal class FriendList { } } } - internal object GetFriendGroupList : PacketFactory("friendlist.getFriendGroupList") { + + internal object GetFriendGroupList : OutgoingPacketFactory("friendlist.getFriendGroupList") { class Response( val totalFriendCount: Short, diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/ConfigPushSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/ConfigPushSvc.kt index 4572beb45..18f554c6f 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/ConfigPushSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/ConfigPushSvc.kt @@ -9,23 +9,25 @@ import net.mamoe.mirai.qqandroid.io.serialization.jceRequestSBuffer import net.mamoe.mirai.qqandroid.io.serialization.writeJceStruct import net.mamoe.mirai.qqandroid.network.protocol.data.jce.PushResp import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPacket -import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory -import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket +import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory +import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket +import net.mamoe.mirai.qqandroid.network.protocol.packet.buildResponseUniPacket import net.mamoe.mirai.qqandroid.network.protocol.data.jce.PushReq as PushReqJceStruct internal class ConfigPushSvc { - object PushReq : PacketFactory("ConfigPushSvc.PushReq") { - override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): PushReqJceStruct { + object PushReq : IncomingPacketFactory( + receivingCommandName = "ConfigPushSvc.PushReq", + responseCommandName = "ConfigPushSvc.PushResp" + ) { + override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): PushReqJceStruct { discardExact(4) - val pushReq = decodeUniPacket(PushReqJceStruct.serializer()) - //println(pushReq.contentToString()) - return pushReq + return decodeUniPacket(PushReqJceStruct.serializer()) } - override suspend fun QQAndroidBot.handle(packet: PushReqJceStruct) { - network.run { - buildOutgoingUniPacket( + override suspend fun QQAndroidBot.handle(packet: PushReqJceStruct, sequenceId: Int): OutgoingPacket? { + return network.run { + buildResponseUniPacket( client, sequenceId = client.configPushSvcPushReqSequenceId, commandName = "ConfigPushSvc.PushResp", @@ -51,7 +53,7 @@ internal class ConfigPushSvc { charset = JceCharset.UTF8 ) // writePacket(this.build().debugPrintThis()) - }.sendWithoutExpect() + } } } } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/LoginPacket.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/LoginPacket.kt index 4f8cd20a5..791d7cbe2 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/LoginPacket.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/LoginPacket.kt @@ -11,16 +11,19 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.* import net.mamoe.mirai.qqandroid.utils.GuidSource import net.mamoe.mirai.qqandroid.utils.MacOrAndroidIdChangeFlag import net.mamoe.mirai.qqandroid.utils.guidFlag -import net.mamoe.mirai.utils.* +import net.mamoe.mirai.utils.MiraiDebugAPI +import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.cryptor.decryptBy +import net.mamoe.mirai.utils.currentTimeSeconds import net.mamoe.mirai.utils.io.* import net.mamoe.mirai.utils.io.discardExact +import net.mamoe.mirai.utils.md5 /** * OicqRequest */ @UseExperimental(ExperimentalUnsignedTypes::class) -internal object LoginPacket : PacketFactory("wtlogin.login") { +internal object LoginPacket : OutgoingPacketFactory("wtlogin.login") { /** * 提交验证码 @@ -686,7 +689,7 @@ internal object LoginPacket : PacketFactory("wt */ private fun QQAndroidClient.analysisTlv130(t130: ByteArray) = t130.read { discardExact(2) - timeDifference = readUInt().toLong() - currentTimeMillis + timeDifference = readUInt().toLong() - currentTimeSeconds ipFromT149 = readBytes(4) } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/StatSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/StatSvc.kt index 96a9e7998..8113708a5 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/StatSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/StatSvc.kt @@ -10,7 +10,7 @@ import net.mamoe.mirai.qqandroid.network.QQAndroidClient import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPacket import net.mamoe.mirai.qqandroid.network.protocol.data.jce.SvcReqRegister import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket -import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory +import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.oidb.oidb0x769.Oidb0x769 import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket @@ -33,7 +33,7 @@ internal enum class RegPushReason { } internal class StatSvc { - internal object Register : PacketFactory("StatSvc.register") { + internal object Register : OutgoingPacketFactory("StatSvc.register") { internal object Response : Packet { override fun toString(): String = "Response(StatSvc.register)" diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/TransEmpPacket.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/TransEmpPacket.kt index 8798781cc..f66c51d44 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/TransEmpPacket.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/TransEmpPacket.kt @@ -7,7 +7,7 @@ import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.network.QQAndroidClient import net.mamoe.mirai.qqandroid.network.protocol.packet.* -internal object TransEmpPacket : PacketFactory("wtlogin.trans_emp") { +internal object TransEmpPacket : OutgoingPacketFactory("wtlogin.trans_emp") { private const val appId = 16L private const val subAppId = 537062845L diff --git a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/serverToClient.kt b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/serverToClient.kt index a6af9b33e..638a7156d 100644 --- a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/serverToClient.kt +++ b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/serverToClient.kt @@ -4,10 +4,7 @@ package androidPacketTests import kotlinx.io.core.* import kotlinx.io.pool.useInstance -import net.mamoe.mirai.qqandroid.network.protocol.packet.DECRYPTER_16_ZERO -import net.mamoe.mirai.qqandroid.network.protocol.packet.KnownPacketFactories -import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketLogger -import net.mamoe.mirai.qqandroid.network.protocol.packet.withUse +import net.mamoe.mirai.qqandroid.network.protocol.packet.* import net.mamoe.mirai.utils.cryptor.ECDH import net.mamoe.mirai.utils.cryptor.adjustToPublicKey import net.mamoe.mirai.utils.cryptor.decryptBy @@ -99,7 +96,7 @@ private fun processFullPacketWithoutLength(packet: ByteReadPacket) { try { bytes.toReadPacket().parseOicqResponse { debugIfFail { - if (it.packetFactory.commandName == "wtlogin.login") { + if ((it.packetFactory as? OutgoingPacketFactory<*>)?.commandName == "wtlogin.login") { DebugLogger.info("服务器发来了 wtlogin.login. 正在解析 key") try { val subCommand = readUShort().toInt() diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/MiraiLogger.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/MiraiLogger.kt index 1c8258e08..eb2d0891d 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/MiraiLogger.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/MiraiLogger.kt @@ -5,59 +5,73 @@ import kotlin.jvm.JvmOverloads /** - * 用于创建默认的日志记录器. 在一些需要使用日志的 Mirai 的组件, 如 [Bot], 都会通过这个函数构造日志记录器 + * 用于创建默认的日志记录器. 在一些需要使用日志的 Mirai 的组件, 如 [Bot], 都会通过这个函数构造日志记录器. * 可直接修改这个变量的值来重定向日志输出. + * + * **注意:** 请务必将所有的输出定向到日志记录系统, 否则在某些情况下 (如 web 控制台中) 将无法接收到输出 + * + * **注意:** 请为日志做好分类, 即不同的模块使用不同的 [MiraiLogger]. + * 如, [Bot] 中使用 identity 为 "Bot(qqId)" 的 [MiraiLogger] + * 而 [Bot] 的网络处理中使用 identity 为 "BotNetworkHandler" 的. */ var DefaultLogger: (identity: String?) -> MiraiLogger = { PlatformLogger(it) } -/** - * 当前平台的默认的日志记录器. - * 在 _JVM 控制台_ 端的实现为 [println] - * 在 _Android_ 端的实现为 [android.util.Log] - * - * 不应该直接构造这个类的实例. 请使用 [DefaultLogger], 或使用默认的顶层日志记录 [MiraiLogger.Companion] - */ -expect open class PlatformLogger @JvmOverloads internal constructor(identity: String? = "Mirai") : MiraiLoggerPlatformBase - /** * 给这个 logger 添加一个开关, 用于控制是否记录 log + * */ @JvmOverloads fun MiraiLogger.withSwitch(default: Boolean = true): MiraiLoggerWithSwitch = MiraiLoggerWithSwitch(this, default) /** * 日志记录器. 所有的输出均依赖于它. - * 不同的对象可能拥有只属于自己的 logger. 通过 [identity] 来区分. + * 不同的对象可拥有只属于自己的 logger. 通过 [identity] 来区分. * - * 注意: 请不要直接实现这个接口, 请继承 [MiraiLoggerPlatformBase] + * 注意: 如果你需要重新实现日志, 请不要直接实现这个接口, 请继承 [MiraiLoggerPlatformBase] * - * @see MiraiLoggerPlatformBase 平台通用基础实现 + * 在定义 logger 变量时, 请一直使用 [MiraiLogger] 或者 [MiraiLoggerWithSwitch]. + * + * @see SimpleLogger 简易 logger, 它将所有的日志记录操作都转移给 lambda `(String?, Throwable?) -> Unit` + * @see PlatformLogger 各个平台下的默认日志记录实现. + * @see SilentLogger 忽略任何日志记录操作的 logger 实例. + * + * @see MiraiLoggerPlatformBase 平台通用基础实现. 若 */ interface MiraiLogger { /** * 顶层日志记录器. + * + * 顶层日志会导致混乱并难以定位问题. 请自行构造 logger 实例并使用. + * 请参考使用 [DefaultLogger] */ + @Deprecated(message = "顶层日志会导致混乱并难以定位问题. 请自行构造 logger 实例并使用.", level = DeprecationLevel.WARNING) companion object : MiraiLogger by DefaultLogger("Mirai") + /** + * 日志的标记. 在 Mirai 中, identity 可为 + * - "Bot" + * - "BotNetworkHandler" + * 等. + * + * 它只用于帮助调试或统计. 十分建议清晰定义 identity + */ val identity: String? /** * 随从. 在 this 中调用所有方法后都应继续往 [follower] 传递调用. * [follower] 的存在可以让一次日志被多个日志记录器记录. * - * 例: - * ```kotlin - * val bot = Bot( ... ) - * bot.follower = MyOwnLogger() + * 一般不建议直接修改这个属性. 请通过 [plus] 来连接两个日志记录器. + * 如: `val logger = bot.logger + MyOwnLogger()` + * 这样, 当调用 `logger.info()` 时, bot.logger 会首先记录, MyOwnLogger 会随后记录. * - * bot.info("Hi") - * ``` - * 在这个例子中的 `MyOwnLogger` 将可以记录到 "Hi". + * 当然, 多个 logger 也可以加在一起: `val logger = bot.logger + MyOwnLogger() + MyOwnLogger2()` */ var follower: MiraiLogger? /** * 记录一个 `verbose` 级别的日志. + * 无关紧要的, 经常大量输出的日志应使用它. */ fun verbose(any: Any?) @@ -65,7 +79,7 @@ interface MiraiLogger { fun verbose(message: String?, e: Throwable?) /** - * 记录一个 `debug` 级别的日志. + * 记录一个 _调试_ 级别的日志. */ fun debug(any: Any?) @@ -74,7 +88,7 @@ interface MiraiLogger { /** - * 记录一个 `info` 级别的日志. + * 记录一个 _信息_ 级别的日志. */ fun info(any: Any?) @@ -83,7 +97,7 @@ interface MiraiLogger { /** - * 记录一个 `warning` 级别的日志. + * 记录一个 _警告_ 级别的日志. */ fun warning(any: Any?) @@ -92,7 +106,7 @@ interface MiraiLogger { /** - * 记录一个 `error` 级别的日志. + * 记录一个 _错误_ 级别的日志. */ fun error(e: Any?) @@ -109,10 +123,9 @@ interface MiraiLogger { * | base | <-- | follower | <-- | follower | <-- | follower | * +------+ +----------+ +----------+ +----------+ * - * @see follower * @return [follower] */ - operator fun plus(follower: MiraiLogger): MiraiLogger + operator fun plus(follower: T): T /** * 添加一个 [follower] @@ -123,6 +136,15 @@ interface MiraiLogger { operator fun plusAssign(follower: MiraiLogger) } +/** + * 当前平台的默认的日志记录器. + * 在 _JVM 控制台_ 端的实现为 [println] + * 在 _Android_ 端的实现为 [android.util.Log] + * + * 不应该直接构造这个类的实例. 请使用 [DefaultLogger], 或使用默认的顶层日志记录 [MiraiLogger.Companion] + */ +expect open class PlatformLogger @JvmOverloads internal constructor(identity: String? = "Mirai") : MiraiLoggerPlatformBase + /** * 不做任何事情的 logger, keep silent. */ @@ -167,7 +189,11 @@ class SimpleLogger(override val identity: String?, private val logger: (String?, class MiraiLoggerWithSwitch internal constructor(private val delegate: MiraiLogger, default: Boolean) : MiraiLoggerPlatformBase() { override val identity: String? get() = delegate.identity - private var switch: Boolean = default + /** + * true 为开启. + */ + @PublishedApi + internal var switch: Boolean = default fun enable() { switch = true @@ -188,15 +214,53 @@ class MiraiLoggerWithSwitch internal constructor(private val delegate: MiraiLogg override fun error0(any: Any?) = if (switch) delegate.error(any) else Unit override fun error0(message: String?, e: Throwable?) = if (switch) delegate.error(message, e) else Unit + inline fun verbose(lazyMessage: () -> String) { + if (switch) verbose(lazyMessage()) + } + + inline fun verbose(lazyMessage: () -> String, e: Throwable?) { + if (switch) verbose(lazyMessage(), e) + } + + inline fun debug(lazyMessage: () -> Any?) { + if (switch) debug(lazyMessage()) + } + + inline fun debug(lazyMessage: () -> String?, e: Throwable?) { + if (switch) debug(lazyMessage(), e) + } + + inline fun info(lazyMessage: () -> Any?) { + if (switch) info(lazyMessage()) + } + + inline fun info(lazyMessage: () -> String?, e: Throwable?) { + if (switch) info(lazyMessage(), e) + } + + inline fun warning(lazyMessage: () -> Any?) { + if (switch) warning(lazyMessage()) + } + + inline fun warning(lazyMessage: () -> String?, e: Throwable?) { + if (switch) warning(lazyMessage(), e) + } + + inline fun error(lazyMessage: () -> Any?) { + if (switch) error(lazyMessage()) + } + + inline fun error(lazyMessage: () -> String?, e: Throwable?) { + if (switch) error(lazyMessage(), e) + } } /** - * 平台日志基类. - * 实现了 [follower] 的调用传递. + * 日志基类. 实现了 [follower] 的调用传递. + * 若 Mirai 自带的日志系统无法满足需求, 请继承这个类并实现其抽象函数. * - * 若要自行实现日志记录, 请优先考虑继承 [PlatformLogger]. - * - * 它不应该被用作变量的类型定义. 只应被继承 + * 这个类不应该被用作变量的类型定义. 只应被作为继承对象. + * 在定义 logger 变量时, 请一直使用 [MiraiLogger] 或者 [MiraiLoggerWithSwitch]. */ abstract class MiraiLoggerPlatformBase : MiraiLogger { final override var follower: MiraiLogger? = null @@ -262,7 +326,7 @@ abstract class MiraiLoggerPlatformBase : MiraiLogger { protected abstract fun error0(any: Any?) protected abstract fun error0(message: String?, e: Throwable?) - override fun plus(follower: MiraiLogger): MiraiLogger { + override operator fun plus(follower: T): T { this.follower = follower return follower }