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 1aafc0620..8306bba9f 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 @@ -1,8 +1,8 @@ package net.mamoe.mirai.qqandroid.network import kotlinx.coroutines.* -import kotlinx.io.core.ByteReadPacket -import kotlinx.io.core.use +import kotlinx.io.core.* +import kotlinx.io.pool.ObjectPool import net.mamoe.mirai.data.Packet import net.mamoe.mirai.event.broadcast import net.mamoe.mirai.network.BotNetworkHandler @@ -14,11 +14,8 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.login.PacketId import net.mamoe.mirai.qqandroid.network.protocol.packet.login.RegPushReason import net.mamoe.mirai.qqandroid.network.protocol.packet.login.SvcReqRegisterPacket -import net.mamoe.mirai.utils.LockFreeLinkedList -import net.mamoe.mirai.utils.MiraiInternalAPI -import net.mamoe.mirai.utils.getValue +import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.io.* -import net.mamoe.mirai.utils.unsafeWeakRef import kotlin.coroutines.CoroutineContext @UseExperimental(MiraiInternalAPI::class) @@ -46,25 +43,137 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler SvcReqRegisterPacket(bot.client, RegPushReason.setOnlineStatus).sendAndExpect<SvcReqRegisterPacket.Response>() } - internal fun launchPacketProcessor(rawInput: ByteReadPacket): Job = launch(CoroutineName("Incoming Packet handler")) { - rawInput.debugPrint("Received").use { input -> - if (input.remaining == 0L) { - bot.logger.error("Empty packet received. Consider if bad packet was sent.") - return@launch + /** + * 单线程处理包的接收, 分割和连接. + */ + @Suppress("PrivatePropertyName") + private val PacketReceiveDispatcher = newCoroutineDispatcher(1) + + /** + * 单线程处理包的解析 (协程挂起效率够) + */ + @Suppress("PrivatePropertyName") + private val PacketProcessDispatcher = newCoroutineDispatcher(1) + + /** + * 缓存的包 + */ + private var cachedPacket: ByteReadPacket? = null + /** + * 缓存的包还差多少长度 + */ + private var expectingRemainingLength: Long = 0 + + /** + * 在 [PacketProcessDispatcher] 调度器中解析包内容. + * [input] 将会被 [ObjectPool.recycle]. + * + * @param input 一个完整的包的内容, 去掉开头的 int 包长度 + */ + fun parsePacketAsync(input: IoBuffer, pool: ObjectPool<IoBuffer> = IoBuffer.Pool): Job = + this.launch(PacketProcessDispatcher) { + try { + parsePacket(input) + } finally { + input.discard() + input.release(pool) } - KnownPacketFactories.parseIncomingPacket(bot, input) { packet: Packet, packetId: PacketId, sequenceId: Int -> - if (PacketReceivedEvent(packet).broadcast().cancelled) { - return@parseIncomingPacket - } - packetListeners.forEach { listener -> - if (listener.filter(packetId, sequenceId) && packetListeners.remove(listener)) { - listener.complete(packet) - } + } + + /** + * 在 [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) } + } + } + + /** + * 解析包内容 + * **注意**: 需要函数调用者 close 这个 [input] + * + * @param input 一个完整的包的内容, 去掉开头的 int 包长度 + */ + suspend fun parsePacket(input: Input) { + KnownPacketFactories.parseIncomingPacket(bot, input) { packet: Packet, packetId: PacketId, sequenceId: Int -> + if (PacketReceivedEvent(packet).broadcast().cancelled) { + return@parseIncomingPacket + } + packetListeners.forEach { listener -> + if (listener.filter(packetId, sequenceId) && packetListeners.remove(listener)) { + listener.complete(packet) } } } } + /** + * 处理从服务器接收过来的包. 这些包可能是粘在一起的, 也可能是不完整的. 将会自动处理 + */ + @UseExperimental(ExperimentalCoroutinesApi::class) + internal suspend fun processPacket(rawInput: ByteReadPacket): Unit = rawInput.debugPrint("Received").let { input: ByteReadPacket -> + if (input.remaining == 0L) { + return + } + + if (cachedPacket == null) { + // 没有缓存 + var length: Int = input.readInt() - 4 + if (input.remaining == length.toLong()) { + // 捷径: 当包长度正好, 直接传递剩余数据. + parsePacketAsync(input) + return + } + // 循环所有完整的包 + while (input.remaining > length) { + parsePacketAsync(input.readIoBuffer(length)) + + length = input.readInt() - 4 + } + + if (input.remaining != 0L) { + // 剩余的包长度不够, 缓存后接收下一个包 + expectingRemainingLength = length - input.remaining + cachedPacket = input + } else { + cachedPacket = null // 表示包长度正好 + } + } else { + // 有缓存 + + if (input.remaining >= expectingRemainingLength) { + // 剩余长度够, 连接上去, 处理这个包. + parsePacketAsync(buildPacket { + writePacket(cachedPacket!!) + writePacket(input, expectingRemainingLength) + }) + cachedPacket = null // 缺少的长度已经给上了. + + if (input.remaining != 0L) { + processPacket(input) // 继续处理剩下内容 + } + } else { + // 剩余不够, 连接上去 + expectingRemainingLength -= input.remaining + cachedPacket = buildPacket { + writePacket(cachedPacket!!) + writePacket(input) + } + } + } + if (input.remaining == 0L) { + bot.logger.error("Empty packet received. Consider if bad packet was sent.") + return + } + } + + + @UseExperimental(ExperimentalCoroutinesApi::class) private suspend fun processReceive() { while (channel.isOpen) { val rawInput = try { @@ -81,7 +190,9 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler bot.logger.error("Caught unexpected exceptions", e) continue } - launchPacketProcessor(rawInput) + launch(context = PacketReceiveDispatcher + CoroutineName("Incoming Packet handler"), start = CoroutineStart.ATOMIC) { + processPacket(rawInput) + } } } 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 6a091e427..f367c2e0d 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 @@ -62,16 +62,13 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf( // 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 + /** + * full packet without length + */ // do not inline. Exceptions thrown will not be reported correctly - suspend fun parseIncomingPacket(bot: QQAndroidBot, rawInput: ByteReadPacket, consumer: PacketConsumer) = + suspend fun parseIncomingPacket(bot: QQAndroidBot, rawInput: Input, consumer: PacketConsumer) = rawInput.debugIfFail("Incoming packet") { require(remaining < Int.MAX_VALUE) { "rawInput is too long" } - val expectedLength = readUInt().toInt() - 4 - if (expectedLength > 16e7) { - bot.logger.warning("Detect incomplete packet, ignoring.") - return@debugIfFail - } - check(remaining.toInt() == expectedLength) { "Invalid packet length. Expected $expectedLength, got ${this.remaining} Probably packets merged? " } // login val flag1 = readInt() @@ -88,12 +85,12 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf( //debugPrint("remaining") when (flag1) { - 0x0A -> parseLoginSsoPacket(bot, decryptBy(DECRYPTER_16_ZERO), consumer) + 0x0A -> parseLoginSsoPacket(bot, if (flag2 == 2) decryptBy(DECRYPTER_16_ZERO) else decryptBy(bot.client.wLoginSigInfo.d2Key), consumer) 0x0B -> parseUniPacket(bot, decryptBy(DECRYPTER_16_ZERO), consumer) } } - private suspend fun parseUniPacket(bot: QQAndroidBot, rawInput: ByteReadPacket, consumer: PacketConsumer) = + private fun parseUniPacket(bot: QQAndroidBot, rawInput: ByteReadPacket, consumer: PacketConsumer) = rawInput.debugIfFail("Login sso 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 diff --git a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt index 1e27f8ff2..78becc0cf 100644 --- a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt +++ b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt @@ -68,8 +68,12 @@ private val shareKeyCalculatedByConstPubKey = ECDH.calculateShareKey( ) fun main() { + + val data = """ -20da22db750806141ef448110800450001b45126400080060000c0a8030a71600dd0fe501f908b8c585508ceeec6501801fc448900000000018c0000000a0100000044e0e22a59327abb9ce80cf63be86694210344fab2f2b065d7785a32cacfa4075cd509f49cb37a075ad0685cbd472344bfdef1ede611c0ad81129be9e2d7e476d2000000000e31393934373031303231f00754574170e9a5d13ca9426984103d1813e22d9c2147f8da5a0af64f64e4ebffde9ce8bfda6c1f798364a1de449adc701595fdce57fa4643e5e14eb4444ad0aea85261a6d5ee90c42a29b5af461a971a7fe85ecf1ed0d582d1cce60d1c34f6a3dc74a75d2f525d590da954098a1a7a4973773195dd209e662cb5c1e0db69843aa75425993bdc8876f21fd9c875d25fa47b689ebc302f3087de8e4a9862cff283703237602e50fa6bb281e974315b70f04f436d8ae9c5d67e22af3495e64aada419940e63c8d0ddbb066fa3d2b8cb27209a687d782d4ec32e6505593625bf0de257d59332f779ed6edb849502591e2c37b983974dbc3ec4740dfd0a9244baf958219067ca7d435ec8bde8e57b36f04d31622a86cb9c8d59d81074c9af38d57f42bb331a0a15f9ac5e216ae54abe8f8a +20da22db750806141ef448110800450000d4512f400080060000c0a8030a71600dd0fe501f908b8c5c9908cf2416501801ff43a90000000000ac0000000b0100014f0d000000000e3139393437303130323193c94c8ce2871f6d5f6664df9e9231dedce5c7cb914cf5d616cf64af478aea9f210098e7f5efae9a952742b8fff704681885e5cc14a44e40d88910258f4a4a5cfcadd642cc159fdc475478475b18ba225cfad1c8bc2c5c828a9cc3ebaed1aa040d04b94f577fcfdb0861fd19754622733a242c5bcb37ca8597a2935d9910162111e44839b6787bb9be80058ad9c921c2 + + """.trimIndent() .trim().split("\n").map { val bytes = it.trim().autoHexToBytes() diff --git a/mirai-core-qqandroid/src/jvmTest/kotlin/test/dumpProtobufId.kts b/mirai-core-qqandroid/src/jvmTest/kotlin/test/dumpProtobufId.kts index 6284e937d..4c9728774 100644 --- a/mirai-core-qqandroid/src/jvmTest/kotlin/test/dumpProtobufId.kts +++ b/mirai-core-qqandroid/src/jvmTest/kotlin/test/dumpProtobufId.kts @@ -3,7 +3,8 @@ package test import net.mamoe.mirai.utils.cryptor.protoFieldNumber +import net.mamoe.mirai.utils.cryptor.protoType -intArrayOf(10, 18, 26, 34, 42, 50, 58, 66, 74).forEach { - println(protoFieldNumber(it.toUInt())) +intArrayOf(8, 18, 26, 34, 80).forEach { + println(protoFieldNumber(it.toUInt()).toString() + " -> " + protoType(it.toUInt())) } \ No newline at end of file diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsAndroid.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsAndroid.kt index c4d80af76..d2bb58323 100644 --- a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsAndroid.kt +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsAndroid.kt @@ -3,12 +3,15 @@ package net.mamoe.mirai.utils import io.ktor.client.HttpClient import io.ktor.client.engine.cio.CIO import io.ktor.util.KtorExperimentalAPI +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.asCoroutineDispatcher import java.io.ByteArrayOutputStream import java.io.DataInput import java.io.EOFException import java.io.InputStream import java.net.InetAddress import java.security.MessageDigest +import java.util.concurrent.Executors import java.util.zip.CRC32 import java.util.zip.Inflater @@ -91,4 +94,8 @@ actual fun ByteArray.unzip(): ByteArray { } inflater.end() return output.toByteArray() +} + +actual fun newCoroutineDispatcher(threadCount: Int): CoroutineDispatcher { + return Executors.newFixedThreadPool(threadCount).asCoroutineDispatcher() } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformUtils.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformUtils.kt index fbdcd67a7..974ed9d44 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformUtils.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformUtils.kt @@ -4,6 +4,7 @@ package net.mamoe.mirai.utils import io.ktor.client.HttpClient import io.ktor.util.date.GMTDate +import kotlinx.coroutines.CoroutineDispatcher /** * 时间戳 @@ -46,3 +47,5 @@ expect fun localIpAddress(): String * Ktor HttpClient. 不同平台使用不同引擎. */ expect val Http: HttpClient + +expect fun newCoroutineDispatcher(threadCount: Int): CoroutineDispatcher \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/DebugUtil.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/DebugUtil.kt index c7dc58de5..fc0bf4bd0 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/DebugUtil.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/DebugUtil.kt @@ -2,7 +2,10 @@ package net.mamoe.mirai.utils.io import kotlinx.io.core.* import kotlinx.io.pool.useInstance -import net.mamoe.mirai.utils.* +import net.mamoe.mirai.utils.DefaultLogger +import net.mamoe.mirai.utils.MiraiDebugAPI +import net.mamoe.mirai.utils.MiraiLogger +import net.mamoe.mirai.utils.withSwitch import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -74,7 +77,7 @@ inline fun <R> Input.debugIfFail(name: String = "", onFail: (ByteArray) -> ByteR ByteArrayPool.useInstance { val count = this.readAvailable(it) try { - return block(it.toReadPacket(0, count)) + return it.toReadPacket(0, count).use(block) } catch (e: Throwable) { onFail(it.take(count).toByteArray()).readAvailable(it) DebugLogger.debug("Error in ByteReadPacket $name=" + it.toUHexString(offset = 0, length = count)) diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt index bbb4120f9..262fdb04c 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt @@ -4,15 +4,15 @@ package net.mamoe.mirai.utils import io.ktor.client.HttpClient import io.ktor.client.engine.cio.CIO -import kotlinx.io.core.IoBuffer -import kotlinx.io.core.Output +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.io.core.copyTo -import kotlinx.io.core.readBytes import kotlinx.io.streams.asInput import kotlinx.io.streams.asOutput import java.io.* import java.net.InetAddress import java.security.MessageDigest +import java.util.concurrent.Executors import java.util.zip.CRC32 import java.util.zip.Inflater @@ -68,4 +68,8 @@ actual fun ByteArray.unzip(): ByteArray { } inflater.end() return output.toByteArray() +} + +actual fun newCoroutineDispatcher(threadCount: Int): CoroutineDispatcher { + return Executors.newFixedThreadPool(threadCount).asCoroutineDispatcher() } \ No newline at end of file diff --git a/mirai-debug/src/main/kotlin/test/ProtoTest.kt b/mirai-debug/src/main/kotlin/test/ProtoTest.kt index 29b43598c..47f8b367e 100644 --- a/mirai-debug/src/main/kotlin/test/ProtoTest.kt +++ b/mirai-debug/src/main/kotlin/test/ProtoTest.kt @@ -2,15 +2,17 @@ package test -import kotlinx.serialization.* +import kotlinx.serialization.ImplicitReflectionSerializer +import kotlinx.serialization.SerialId +import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoBuf import kotlinx.serialization.protobuf.ProtoNumberType import kotlinx.serialization.protobuf.ProtoType +import kotlinx.serialization.serializer import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.cryptor.readProtoMap import net.mamoe.mirai.utils.io.hexToBytes import net.mamoe.mirai.utils.io.read -import net.mamoe.mirai.utils.io.toUHexString import kotlin.reflect.KClass @Serializable @@ -25,15 +27,14 @@ data class ProtoTest( @UseExperimental(MiraiInternalAPI::class) suspend fun main() { - println("PNG".toUtf8Bytes().toUHexString()) deserializeTest() } suspend fun deserializeTest() { val bytes = """ - - """.trimIndent() + 08 02 1A 55 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 1A 25 2F 34 35 35 38 66 39 30 38 2D 37 62 39 61 2D 34 65 32 66 2D 38 63 36 39 2D 34 61 35 32 61 66 62 33 36 35 61 37 20 01 30 04 38 05 40 09 48 01 58 00 60 01 6A 0A 38 2E 32 2E 30 2E 31 32 39 36 70 E0 8C B2 F0 05 78 01 50 03 + """.trimIndent() .replace("\n", " ") .replace("UVarInt", "", ignoreCase = true) .replace("uint", "", ignoreCase = true)