diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/SerializationUtils.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/SerializationUtils.kt index cfd57a14a..9b5f13501 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/SerializationUtils.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/SerializationUtils.kt @@ -21,7 +21,7 @@ fun BytePacketBuilder.writeJceStruct(serializer: SerializationSt this.writePacket(Jce.byCharSet(charset).dumpAsPacket(serializer, struct)) } -fun ByteReadPacket.readRemainingAsJceStruct( +fun ByteReadPacket.readJceStruct( serializer: DeserializationStrategy, charset: JceCharset = JceCharset.UTF8, length: Int = this.remaining.toInt() @@ -36,7 +36,7 @@ fun ByteReadPacket.decodeUniPacket(deserializer: Deserialization return decodeUniRequestPacketAndDeserialize(name) { it.read { discardExact(1) - this.readRemainingAsJceStruct(deserializer, length = (this.remaining - 1).toInt()) + this.readJceStruct(deserializer, length = (this.remaining - 1).toInt()) } } } @@ -48,13 +48,13 @@ fun ByteReadPacket.decodeUniPacket(deserializer: DeserializationS return decodeUniRequestPacketAndDeserialize(name) { it.read { discardExact(1) - this.readRemainingAsProtoBuf(deserializer, (this.remaining - 1).toInt()) + this.readProtoBuf(deserializer, (this.remaining - 1).toInt()) } } } fun ByteReadPacket.decodeUniRequestPacketAndDeserialize(name: String? = null, block: (ByteArray) -> R): R { - val request = this.readRemainingAsJceStruct(RequestPacket.serializer()) + val request = this.readJceStruct(RequestPacket.serializer()) return block(if (name == null) when (request.iVersion.toInt()) { 2 -> request.sBuffer.loadAs(RequestDataVersion2.serializer()).map.firstValue().firstValue() @@ -90,7 +90,7 @@ fun ByteArray.loadAs(deserializer: DeserializationStrategy): T /** * load */ -fun ByteReadPacket.readRemainingAsProtoBuf(serializer: DeserializationStrategy, length: Int = this.remaining.toInt()): T { +fun ByteReadPacket.readProtoBuf(serializer: DeserializationStrategy, length: Int = this.remaining.toInt()): T { return ProtoBufWithNullableSupport.load(serializer, this.readBytes(length)) } 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 a59edc796..fb51a07b2 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 @@ -3,8 +3,10 @@ package net.mamoe.mirai.qqandroid.network import kotlinx.atomicfu.AtomicRef import kotlinx.atomicfu.atomic import kotlinx.coroutines.* -import kotlinx.io.core.* -import kotlinx.io.pool.ObjectPool +import kotlinx.io.core.ByteReadPacket +import kotlinx.io.core.Input +import kotlinx.io.core.buildPacket +import kotlinx.io.core.use import net.mamoe.mirai.data.MultiPacket import net.mamoe.mirai.data.Packet import net.mamoe.mirai.event.BroadcastControllable @@ -143,28 +145,10 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler /** * 在 [PacketProcessDispatcher] 调度器中解析包内容. - * [input] 将会被 [ObjectPool.recycle]. - * - * @param input 一个完整的包的内容, 去掉开头的 int 包长度 - */ - fun parsePacketAsync(input: IoBuffer, pool: ObjectPool = IoBuffer.Pool): Job = - this.launch(PacketProcessDispatcher) { - try { - parsePacket(input) - } finally { - input.discard() - input.release(pool) - } - } - - /** - * 在 [PacketProcessDispatcher] 调度器中解析包内容. - * [input] 将会被 [Input.close], 因此 [input] 不能为 [IoBuffer] * * @param input 一个完整的包的内容, 去掉开头的 int 包长度 */ fun parsePacketAsync(input: Input): Job { - require(input !is IoBuffer) { "input cannot be IoBuffer" } return this.launch(PacketProcessDispatcher) { input.use { parsePacket(it) } } @@ -180,6 +164,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler generifiedParsePacket(input) } + // with generic type, less mistakes private suspend inline fun

generifiedParsePacket(input: Input) { KnownPacketFactories.parseIncomingPacket(bot, input) { packetFactory: PacketFactory

, packet: P, commandName: String, sequenceId: Int -> handlePacket(packetFactory, packet, commandName, sequenceId) @@ -230,7 +215,6 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler * 处理从服务器接收过来的包. 这些包可能是粘在一起的, 也可能是不完整的. 将会自动处理. * 处理后的包会调用 [parsePacketAsync] */ - @UseExperimental(ExperimentalCoroutinesApi::class) internal fun processPacket(rawInput: ByteReadPacket) { if (rawInput.remaining == 0L) { return @@ -248,7 +232,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } // 循环所有完整的包 while (rawInput.remaining > length) { - parsePacketAsync(rawInput.readIoBuffer(length)) + parsePacketAsync(rawInput.readPacket(length)) length = rawInput.readInt() - 4 } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt index fc847868b..e34531671 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt @@ -11,15 +11,15 @@ import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketLogger import net.mamoe.mirai.qqandroid.network.protocol.packet.Tlv -import net.mamoe.mirai.qqandroid.utils.* -import net.mamoe.mirai.utils.MiraiExperimentalAPI -import net.mamoe.mirai.utils.MiraiInternalAPI +import net.mamoe.mirai.qqandroid.utils.Context +import net.mamoe.mirai.qqandroid.utils.DeviceInfo +import net.mamoe.mirai.qqandroid.utils.NetworkType +import net.mamoe.mirai.qqandroid.utils.SystemDeviceInfo +import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.cryptor.ECDH import net.mamoe.mirai.utils.cryptor.contentToString import net.mamoe.mirai.utils.cryptor.decryptBy -import net.mamoe.mirai.utils.getValue import net.mamoe.mirai.utils.io.* -import net.mamoe.mirai.utils.unsafeWeakRef /* APP ID: @@ -174,7 +174,11 @@ internal open class QQAndroidClient( lateinit var t104: ByteArray } -class ReserveUinInfo( +internal fun generateTgtgtKey(guid: ByteArray): ByteArray = + md5(getRandomByteArray(16) + guid) + + +internal class ReserveUinInfo( val imgType: ByteArray, val imgFormat: ByteArray, val imgUrl: ByteArray @@ -184,7 +188,7 @@ class ReserveUinInfo( } } -class WFastLoginInfo( +internal class WFastLoginInfo( val outA1: ByteReadPacket, var adUrl: String = "", var iconUrl: String = "", @@ -196,7 +200,7 @@ class WFastLoginInfo( } } -class WLoginSimpleInfo( +internal class WLoginSimpleInfo( val uin: Long, // uin val face: Int, // ubyte actually val age: Int, // ubyte @@ -212,7 +216,7 @@ class WLoginSimpleInfo( } } -class LoginExtraData( +internal class LoginExtraData( val uin: Long, val ip: ByteArray, val time: Int, @@ -223,7 +227,7 @@ class LoginExtraData( } } -class WLoginSigInfo( +internal class WLoginSigInfo( val uin: Long, val encryptA1: ByteArray?, // sigInfo[0] val noPicSig: ByteArray?, // sigInfo[1] @@ -275,24 +279,24 @@ class WLoginSigInfo( } } -class UserStSig(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) -class LSKey(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) -class UserStWebSig(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) -class UserA8(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) -class UserA5(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) -class SKey(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) -class UserSig64(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) -class OpenKey(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) -class VKey(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) -class AccessToken(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) -class D2(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) -class Sid(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) -class AqSig(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) +internal class UserStSig(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) +internal class LSKey(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) +internal class UserStWebSig(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) +internal class UserA8(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) +internal class UserA5(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) +internal class SKey(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) +internal class UserSig64(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) +internal class OpenKey(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) +internal class VKey(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) +internal class AccessToken(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) +internal class D2(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) +internal class Sid(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) +internal class AqSig(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) -class Pt4Token(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) +internal class Pt4Token(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) -typealias PSKeyMap = MutableMap -typealias Pt4TokenMap = MutableMap +internal typealias PSKeyMap = MutableMap +internal typealias Pt4TokenMap = MutableMap internal fun parsePSKeyMapAndPt4TokenMap(data: ByteArray, creationTime: Long, expireTime: Long, outPSKeyMap: PSKeyMap, outPt4TokenMap: Pt4TokenMap) = data.read { @@ -308,17 +312,17 @@ internal fun parsePSKeyMapAndPt4TokenMap(data: ByteArray, creationTime: Long, ex } } -class PSKey(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) +internal class PSKey(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) -class WtSessionTicket(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) +internal class WtSessionTicket(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) -open class KeyWithExpiry( +internal open class KeyWithExpiry( data: ByteArray, creationTime: Long, val expireTime: Long ) : KeyWithCreationTime(data, creationTime) -open class KeyWithCreationTime( +internal open class KeyWithCreationTime( val data: ByteArray, val creationTime: Long ) \ No newline at end of file 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 8c7825e67..f1b05fd0a 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 @@ -192,7 +192,7 @@ internal inline fun PacketFactory<*>.buildLoginOutgoingPacket( }) } -private val BRP_STUB = ByteReadPacket(EMPTY_BYTE_ARRAY) +private inline val BRP_STUB get() = ByteReadPacket.Empty /** * The second outermost packet for login @@ -233,7 +233,8 @@ internal inline fun BytePacketBuilder.writeSsoPacket( writeInt(subAppId.toInt()) writeInt(subAppId.toInt()) writeHex(unknownHex) - if (extraData === BRP_STUB) { + if (extraData === BRP_STUB || extraData.remaining == 0L) { + // fast-path writeInt(0x04) } else { writeInt((extraData.remaining + 4).toInt()) 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 8fd2ee497..875858b11 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 @@ -9,7 +9,7 @@ import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.event.ForceOfflineEvent import net.mamoe.mirai.qqandroid.io.serialization.decodeUniPacket -import net.mamoe.mirai.qqandroid.io.serialization.readRemainingAsProtoBuf +import net.mamoe.mirai.qqandroid.io.serialization.readProtoBuf import net.mamoe.mirai.qqandroid.io.serialization.toByteArray import net.mamoe.mirai.qqandroid.io.serialization.writeProtoBuf import net.mamoe.mirai.qqandroid.network.QQAndroidClient @@ -87,7 +87,7 @@ internal class MessageSvc { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): MultiPacket { // 00 00 01 0F 08 00 12 00 1A 34 08 FF C1 C4 F1 05 10 FF C1 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 8A CA 91 D1 0C 48 9B A5 BD 9B 0A 58 DE 9D 99 F8 08 60 1D 68 FF C1 C4 F1 05 70 00 20 02 2A 9D 01 08 F3 C1 C4 F1 05 10 A2 FF 8C F0 03 18 01 22 8A 01 0A 2A 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 18 A6 01 20 0B 28 AE F9 01 30 F4 C1 C4 F1 05 38 A7 E3 D8 D4 84 80 80 80 01 B8 01 CD B5 01 12 08 08 01 10 00 18 00 20 00 1A 52 0A 50 0A 27 08 00 10 F4 C1 C4 F1 05 18 A7 E3 D8 D4 04 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 08 0A 06 0A 04 4E 4D 53 4C 12 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 12 04 4A 02 08 00 30 01 2A 15 08 97 A2 C1 F1 05 10 95 A6 F5 E5 0C 18 01 30 01 40 01 48 81 01 2A 10 08 D3 F7 B5 F1 05 10 DD F1 92 B7 07 18 01 30 01 38 00 42 00 48 00 discardExact(4) - val resp = readRemainingAsProtoBuf(MsgSvc.PbGetMsgResp.serializer()) + val resp = readProtoBuf(MsgSvc.PbGetMsgResp.serializer()) if (resp.result != 0) { return MultiPacket(emptyList()) @@ -201,7 +201,7 @@ internal class MessageSvc { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response { discardExact(4) - val response = readRemainingAsProtoBuf(MsgSvc.PbSendMsgResp.serializer()) + val response = readProtoBuf(MsgSvc.PbSendMsgResp.serializer()) return if (response.result == 0) { Response.SUCCESS } else { 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 766f26ba7..91beaf8f1 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 @@ -20,7 +20,7 @@ import net.mamoe.mirai.utils.io.toReadPacket import net.mamoe.mirai.utils.localIpAddress @Suppress("EnumEntryName") -enum class RegPushReason { +internal enum class RegPushReason { appRegister, createDefaultRegInfo, fillRegProxy, @@ -32,7 +32,7 @@ enum class RegPushReason { unknown } -class StatSvc { +internal class StatSvc { internal object Register : PacketFactory("StatSvc.register") { internal object Response : Packet { diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/TgtgtKey.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/TgtgtKey.kt deleted file mode 100644 index c72c93eeb..000000000 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/TgtgtKey.kt +++ /dev/null @@ -1,8 +0,0 @@ -package net.mamoe.mirai.qqandroid.utils - -import net.mamoe.mirai.utils.io.getRandomByteArray -import net.mamoe.mirai.utils.md5 - -fun generateTgtgtKey(guid: ByteArray): ByteArray = - md5(getRandomByteArray(16) + guid) -