From 44cdbf8a9476662fa6747dd8e24e815d7cbc7b92 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 8 Feb 2020 01:17:14 +0800 Subject: [PATCH 01/11] Simplify structure, improve performance --- .../qqandroid/network/QQAndroidClient.kt | 30 +++++++++++------- .../protocol/packet/OutgoingPacketAndroid.kt | 6 ++-- .../network/protocol/packet/PacketFactory.kt | 31 +++++++++---------- .../protocol/packet/login/ConfigPushSvc.kt | 4 +-- 4 files changed, 36 insertions(+), 35 deletions(-) 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 28bbc4527..890e7f239 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 @@ -64,14 +64,14 @@ internal open class QQAndroidClient( internal inline fun tryDecryptOrNull(data: ByteArray, size: Int = data.size, mapper: (ByteArray) -> R): R? { keys.forEach { (key, value) -> kotlin.runCatching { - return mapper(data.decryptBy(value, size).also { PacketLogger.verbose("成功使用 $key 解密") }) + return mapper(data.decryptBy(value, size).also { PacketLogger.verbose { "成功使用 $key 解密" } }) } } return null } - override fun toString(): String { // net.mamoe.mirai.utils.cryptor.ProtoKt.contentToString - return "QQAndroidClient(account=$account, ecdh=$ecdh, device=$device, tgtgtKey=${tgtgtKey.contentToString()}, randomKey=${randomKey.contentToString()}, miscBitMap=$miscBitMap, mainSigMap=$mainSigMap, subSigMap=$subSigMap, openAppId=$openAppId, apkVersionName=${apkVersionName.contentToString()}, loginState=$loginState, appClientVersion=$appClientVersion, networkType=$networkType, apkSignatureMd5=${apkSignatureMd5.contentToString()}, protocolVersion=$protocolVersion, apkId=${apkId.contentToString()}, t150=${t150?.contentToString()}, rollbackSig=${rollbackSig?.contentToString()}, ipFromT149=${ipFromT149?.contentToString()}, timeDifference=$timeDifference, uin=$uin, t530=${t530?.contentToString()}, t528=${t528?.contentToString()}, ksid='$ksid', pwdFlag=$pwdFlag, loginExtraData=$loginExtraData, wFastLoginInfo=$wFastLoginInfo, reserveUinInfo=$reserveUinInfo, wLoginSigInfo=$wLoginSigInfo, tlv113=${tlv113?.contentToString()}, qrPushSig=${qrPushSig.contentToString()}, mainDisplayName='$mainDisplayName')" + override fun toString(): String { // extremely slow + return "QQAndroidClient(account=$account, ecdh=$ecdh, device=$device, tgtgtKey=${tgtgtKey.toUHexString()}, randomKey=${randomKey.toUHexString()}, miscBitMap=$miscBitMap, mainSigMap=$mainSigMap, subSigMap=$subSigMap, openAppId=$openAppId, apkVersionName=${apkVersionName.toUHexString()}, loginState=$loginState, appClientVersion=$appClientVersion, networkType=$networkType, apkSignatureMd5=${apkSignatureMd5.toUHexString()}, protocolVersion=$protocolVersion, apkId=${apkId.toUHexString()}, t150=${t150?.value?.toUHexString()}, rollbackSig=${rollbackSig?.toUHexString()}, ipFromT149=${ipFromT149?.toUHexString()}, timeDifference=$timeDifference, uin=$uin, t530=${t530?.toUHexString()}, t528=${t528?.toUHexString()}, ksid='$ksid', pwdFlag=$pwdFlag, loginExtraData=$loginExtraData, wFastLoginInfo=$wFastLoginInfo, reserveUinInfo=$reserveUinInfo, wLoginSigInfo=$wLoginSigInfo, tlv113=${tlv113?.toUHexString()}, qrPushSig=${qrPushSig.toUHexString()}, mainDisplayName='$mainDisplayName')" } var onlineStatus: OnlineStatus = OnlineStatus.ONLINE @@ -86,8 +86,6 @@ internal open class QQAndroidClient( var mainSigMap: Int = 16724722 var subSigMap: Int = 0x10400 //=66,560 - var configPushSvcPushReqSequenceId: Int = 0 - private val _ssoSequenceId: AtomicInt = atomic(85600) @MiraiInternalAPI("Do not use directly. Get from the lambda param of buildSsoPacket") @@ -136,7 +134,7 @@ internal open class QQAndroidClient( @PublishedApi internal val apkId: ByteArray = "com.tencent.mobileqq".toByteArray() - var outgoingPacketUnknownValue: ByteArray = 0x02B05B8B.toByteArray() + var outgoingPacketSessionId: ByteArray = 0x02B05B8B.toByteArray() var loginState = 0 var t150: Tlv? = null @@ -194,7 +192,7 @@ internal class ReserveUinInfo( val imgUrl: ByteArray ) { override fun toString(): String { - return "ReserveUinInfo(imgType=${imgType.contentToString()}, imgFormat=${imgFormat.contentToString()}, imgUrl=${imgUrl.contentToString()})" + return "ReserveUinInfo(imgType=${imgType.toUHexString()}, imgFormat=${imgFormat.toUHexString()}, imgUrl=${imgUrl.toUHexString()})" } } @@ -222,7 +220,7 @@ internal class WLoginSimpleInfo( val mainDisplayName: ByteArray ) { override fun toString(): String { - return "WLoginSimpleInfo(uin=$uin, face=$face, age=$age, gender=$gender, nick='$nick', imgType=${imgType.contentToString()}, imgFormat=${imgFormat.contentToString()}, imgUrl=${imgUrl.contentToString()}, mainDisplayName=${mainDisplayName.contentToString()})" + return "WLoginSimpleInfo(uin=$uin, face=$face, age=$age, gender=$gender, nick='$nick', imgType=${imgType.toUHexString()}, imgFormat=${imgFormat.toUHexString()}, imgUrl=${imgUrl.toUHexString()}, mainDisplayName=${mainDisplayName.toUHexString()})" } } @@ -233,7 +231,7 @@ internal class LoginExtraData( val version: Int ) { override fun toString(): String { - return "LoginExtraData(uin=$uin, ip=${ip.contentToString()}, time=$time, version=$version)" + return "LoginExtraData(uin=$uin, ip=${ip.toUHexString()}, time=$time, version=$version)" } } @@ -285,7 +283,7 @@ internal class WLoginSigInfo( val deviceToken: ByteArray ) { override fun toString(): String { - return "WLoginSigInfo(uin=$uin, encryptA1=${encryptA1.contentToString()}, noPicSig=${noPicSig.contentToString()}, G=${G.contentToString()}, dpwd=${dpwd.contentToString()}, randSeed=${randSeed.contentToString()}, simpleInfo=$simpleInfo, appPri=$appPri, a2ExpiryTime=$a2ExpiryTime, loginBitmap=$loginBitmap, tgt=${tgt.contentToString()}, a2CreationTime=$a2CreationTime, tgtKey=${tgtKey.contentToString()}, userStSig=$userStSig, userStKey=${userStKey.contentToString()}, userStWebSig=$userStWebSig, userA5=$userA5, userA8=$userA8, lsKey=$lsKey, sKey=$sKey, userSig64=$userSig64, openId=${openId.contentToString()}, openKey=$openKey, vKey=$vKey, accessToken=$accessToken, d2=$d2, d2Key=${d2Key.contentToString()}, sid=$sid, aqSig=$aqSig, psKey=${psKeyMap.contentToString()}, superKey=${superKey.contentToString()}, payToken=${payToken.contentToString()}, pf=${pf.contentToString()}, pfKey=${pfKey.contentToString()}, da2=${da2.contentToString()}, wtSessionTicket=$wtSessionTicket, wtSessionTicketKey=${wtSessionTicketKey.contentToString()}, deviceToken=${deviceToken.contentToString()})" + return "WLoginSigInfo(uin=$uin, encryptA1=${encryptA1?.toUHexString()}, noPicSig=${noPicSig?.toUHexString()}, G=${G.toUHexString()}, dpwd=${dpwd.toUHexString()}, randSeed=${randSeed.toUHexString()}, simpleInfo=$simpleInfo, appPri=$appPri, a2ExpiryTime=$a2ExpiryTime, loginBitmap=$loginBitmap, tgt=${tgt.toUHexString()}, a2CreationTime=$a2CreationTime, tgtKey=${tgtKey.toUHexString()}, userStSig=$userStSig, userStKey=${userStKey.toUHexString()}, userStWebSig=$userStWebSig, userA5=$userA5, userA8=$userA8, lsKey=$lsKey, sKey=$sKey, userSig64=$userSig64, openId=${openId.toUHexString()}, openKey=$openKey, vKey=$vKey, accessToken=$accessToken, d2=$d2, d2Key=${d2Key.toUHexString()}, sid=$sid, aqSig=$aqSig, psKey=${psKeyMap.toString()}, superKey=${superKey.toUHexString()}, payToken=${payToken.toUHexString()}, pf=${pf.toUHexString()}, pfKey=${pfKey.toUHexString()}, da2=${da2.toUHexString()}, wtSessionTicket=$wtSessionTicket, wtSessionTicketKey=${wtSessionTicketKey.toUHexString()}, deviceToken=${deviceToken.toUHexString()})" } } @@ -330,9 +328,17 @@ internal open class KeyWithExpiry( data: ByteArray, creationTime: Long, val expireTime: Long -) : KeyWithCreationTime(data, creationTime) +) : KeyWithCreationTime(data, creationTime) { + override fun toString(): String { + return "KeyWithExpiry(data=${data.toUHexString()}, creationTime=$creationTime)" + } +} internal open class KeyWithCreationTime( val data: ByteArray, val creationTime: Long -) \ No newline at end of file +) { + override fun toString(): String { + return "KeyWithCreationTime(data=${data.toUHexString()}, creationTime=$creationTime)" + } +} \ 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 6d93797b2..f0f290ecc 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 @@ -80,7 +80,7 @@ internal inline fun OutgoingPacketFactory<*>.buildOutgoingUniPacket( writeStringUtf8(it) } encryptAndWrite(key) { - writeUniPacket(commandName, client.outgoingPacketUnknownValue, extraData) { + writeUniPacket(commandName, client.outgoingPacketSessionId, extraData) { body(sequenceId) } } @@ -111,7 +111,7 @@ internal inline fun IncomingPacketFactory<*>.buildResponseUniPacket( writeStringUtf8(it) } encryptAndWrite(key) { - writeUniPacket(commandName, client.outgoingPacketUnknownValue, extraData) { + writeUniPacket(commandName, client.outgoingPacketSessionId, extraData) { body(sequenceId) } } @@ -215,7 +215,7 @@ internal inline fun BytePacketBuilder.writeSsoPacket( } writeInt(4 + 4) - writeFully(client.outgoingPacketUnknownValue) // 02 B0 5B 8B + writeFully(client.outgoingPacketSessionId) // 02 B0 5B 8B client.device.imei.let { writeInt(it.length + 4) 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 a9cfe3046..90b883583 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 @@ -161,15 +161,15 @@ internal object KnownPacketFactories { // login val flag1 = readInt() - PacketLogger.verbose("开始处理一个包") - PacketLogger.verbose("flag1(0A/0B) = ${flag1.toUByte().toUHexString()}") + PacketLogger.verbose { "开始处理一个包" } + PacketLogger.verbose { "flag1(0A/0B) = ${flag1.toUByte().toUHexString()}" } // 00 00 05 30 // 00 00 00 0A // flag 1 // 01 // packet type. 02: sso, 01: uni // // 00 00 00 00 0E 31 39 39 34 37 30 31 30 32 31 40 3C 63 DC A2 8F FC E7 09 66 62 11 A3 5A B6 AB DC 6E A1 CA CF E2 0A 6F A8 6D 36 64 4E 22 4B A9 8A ED 07 7A 0A 9E F3 C7 7B 72 EF C1 C7 6E 9A 28 27 10 F8 2A 7F 37 49 B6 48 35 52 E9 CF 2A B5 F3 26 90 33 68 9B 5A 04 2A 8B F5 78 13 82 FE 3C 13 C4 F9 38 39 0E 02 4C 3D 91 0A 2A 94 3F 9F A6 52 B9 14 89 C5 D9 57 0F 96 F8 0E 7D 32 81 8E 10 DB C0 CA BE C7 3F EC D0 B1 F0 9D A2 4B 9F B3 8D E0 EB 1F 42 52 EA 5E 9E 76 E2 F4 13 9D 0E 7E 6D 0A E3 56 C3 EE 8A 80 24 DE FB 08 82 FB B7 AF CE 2A 69 16 E3 C3 79 5C C7 CD 44 BA AA 08 A2 51 0B 43 31 69 A1 12 D1 AE 48 15 AE 76 E9 AB BB D2 E0 16 03 EB 2D 47 A4 61 24 65 5E CC C5 03 B3 96 3E 7A 39 90 3D DB 63 56 2B 23 85 CE 5F 9E 04 20 45 31 79 7B BF 78 33 77 34 C1 8E 83 B3 50 88 2A 01 C0 C4 E4 BF 2D 0D B9 37 32 AB E0 BB 82 36 B1 4E 51 4B F7 07 6A 12 3E 79 EA 93 3D BD 06 4E AE 1C 49 82 17 14 00 09 59 40 A6 A9 01 56 1A 23 86 A8 33 B3 9A 70 7B 3A C1 F9 31 03 FD DB 4B 5C 7B F9 BB 43 94 65 A0 1C DA 2B 85 AA AD 7B 79 42 F2 EB 25 5E F0 DA B7 E7 AD 4B 25 02 36 BB 78 5F 83 7F F7 78 F0 99 D2 B5 A3 0C 4A 7F 0E B0 A6 C4 99 F7 9E 0B C6 4D FC F5 8D 6B 5F 35 27 36 D3 DB D0 46 C7 10 76 7D 96 91 48 EA 1C B2 B7 D7 2F D2 88 A8 4C 87 D6 A9 40 33 4C 76 C5 48 3E 32 4D C1 C3 7F 5C D9 B3 22 00 88 BE 04 82 64 A9 73 AA E1 65 1A EF 49 B4 54 74 53 FF 75 B6 E9 57 1B 89 2D 6F 2A 6A CE 23 BF 41 CB 55 B3 A0 53 87 AD A0 22 EE 6B 3F 4A 97 23 36 BF 7E 08 2D 0A 9E 2E 4B F2 2E 00 59 EC F1 21 34 45 75 DB 6B F2 EC 65 24 30 69 50 CC 45 78 00 AF C8 F6 3D 8E 03 60 CF CA A1 88 14 18 82 6F 56 58 D0 BC E0 48 FD AA 86 63 CA C1 01 63 07 16 4A 79 79 17 9D 1F E2 40 4B B6 77 6E 44 84 DE BE 02 4C 33 7A F5 2F 93 21 3E 17 62 38 81 95 E6 84 8B 7C C8 7B E2 23 FB 12 4F E8 42 5F 1D 48 92 84 B1 45 FF 69 97 3C 30 C9 09 E8 84 E8 07 0E 17 D4 A1 CC 35 D6 FE 7B D2 9A 44 8B 17 BF E7 D6 98 1D 98 D7 30 BE 55 19 A9 F4 D6 0D E8 18 80 35 85 B6 AB B9 20 32 C7 ED C6 AD A7 AE 19 48 B7 17 02 B3 45 C3 A2 B9 C9 B7 58 B5 8B 4C AF 52 AD A1 E1 62 45 AB 58 26 67 20 C7 64 AA DA 7E F3 70 8B C2 92 69 E3 3E 3E 6F 39 6F 2B 35 35 0F 00 FC 52 B5 5C 5B 73 FE F6 F5 10 55 36 7C 9A 84 FC A6 23 29 4A 75 49 7C 13 1C CA 54 A2 A2 FA 2A 63 A5 4C 9A B4 27 E8 5F 9F 23 96 B2 E7 AA E6 8B E0 E2 6A 75 8A B2 F4 E4 7E 09 E8 22 70 2A 42 8B E3 DC AD E8 A8 A2 92 71 6B A2 12 78 E1 DA CC 70 57 67 F5 B4 52 F3 B4 4C 17 AB 05 33 DA 6E 47 52 C5 B2 B7 9A D2 A8 BC 44 64 D3 26 1A 6B C6 C5 36 1C 2B 8F BD B7 27 91 3E C0 C2 FC 03 41 FE 02 D3 4B B1 E5 5F 5B 50 05 29 BD 3A 64 85 E3 8C FB 11 F2 1D 94 DB D7 78 AF AD 77 A3 9C D4 39 5D 8B EA DF 9D 08 CA 92 7C 5F D5 17 49 0E FA A1 21 1C 9F C3 88 1A DC E7 D8 82 80 85 86 32 99 15 E4 89 BA 91 2B 4B FB 87 EC 44 B4 D9 83 CC 79 77 A4 A0 D0 50 E3 4F 00 E7 DA DA 79 38 1E D8 04 86 16 CD 25 BE BA 76 E4 8C F9 86 91 69 6E C7 A0 EF 6B 44 2B C9 C3 DC 8D 2D 65 60 7A F4 37 02 D4 8F 38 D0 D5 20 30 DE A5 F5 A8 75 C7 EE 0B 0F 1B 88 C2 8A CC 6F 70 1D E4 D8 4E DD 04 A5 5B B8 04 B1 29 42 08 92 19 78 E2 26 EB 6B 07 49 DE 8A AF A3 41 72 1D E2 3C 62 0F 7E 7B DE A3 0F 71 8C 5D EC E9 96 96 45 A9 39 33 8A 87 C9 93 CE 3B 6D 75 50 21 1F 4C 03 E9 A7 AD 03 0F 5E A9 EE 60 CC EA 05 4F DF E1 B1 13 A6 7D C7 B9 37 58 53 3B 06 1A AD 98 E5 06 D9 74 2A B1 96 75 DE A6 B7 89 25 53 2A A3 07 B6 70 C6 86 1F 59 EB 53 08 57 6E 86 D7 A1 5C DB 26 D7 86 3E 97 BB FD 6A 0A 4C E1 81 B9 4C C1 A0 49 89 57 29 E0 CD 79 6F 0A 46 C1 C6 62 75 49 C6 9A B9 22 75 EE 10 C7 56 E6 D5 DE 4D EC 89 5A 6F AC 60 0F B3 CC 37 9E F2 BE 49 A7 77 3C 05 AE 92 66 C8 BE 16 E5 35 17 24 18 A5 CE B8 BB AE CD 88 DE 01 53 40 84 E0 06 C6 77 96 09 DF D7 76 3B CA C9 B5 B2 91 95 07 54 6F 51 EB 12 58 16 8A AF C3 E3 B9 4A EC 25 A5 D1 19 59 72 F5 E3 4F 7C 40 B2 D0 4E 9F 50 13 FB 86 C3 6A 88 32 5B 67 EC 4F 0E 0B 31 F8 0C 02 6C CE 8D 50 55 A2 B3 57 73 7C 78 D3 43 1F 48 33 51 E7 0A D0 6D 46 71 4A AD 66 50 F9 96 11 4F A5 5B 3C A0 3E 46 D2 CB 3B A1 03 84 9C 8E 4E 2D 83 69 2E 17 9B F8 36 63 F1 93 CA F9 32 57 2B AB 4E 14 A3 5A F1 39 B0 3F 0F 99 CC 9B FB 7E BC 0A AA C9 65 3C C8 B4 B0 1F val flag2 = readByte().toInt() - PacketLogger.verbose("包类型(flag2) = $flag2. (可能是 ${if (flag2 == 2) "OicqRequest" else "Uni"})") + PacketLogger.verbose { "包类型(flag2) = $flag2. (可能是 ${if (flag2 == 2) "OicqRequest" else "Uni"})" } val flag3 = readByte().toInt() check(flag3 == 0) { "Illegal flag3. Expected 0, whereas got $flag3. flag1=$flag1, flag2=$flag2. Remaining=${this.readBytes().toUHexString()}" } @@ -184,15 +184,15 @@ internal object KnownPacketFactories { kotlin.runCatching { // 快速解密 if (flag2 == 2) { - PacketLogger.verbose("SSO, 尝试使用 16 zero 解密.") - data.decryptBy(DECRYPTER_16_ZERO, size).also { PacketLogger.verbose("成功使用 16 zero 解密") } + PacketLogger.verbose { "SSO, 尝试使用 16 zero 解密." } + data.decryptBy(DECRYPTER_16_ZERO, size).also { PacketLogger.verbose { "成功使用 16 zero 解密" } } } else { - PacketLogger.verbose("Uni, 尝试使用 d2Key 解密.") - data.decryptBy(bot.client.wLoginSigInfo.d2Key, size).also { PacketLogger.verbose("成功使用 d2Key 解密") } + PacketLogger.verbose { "Uni, 尝试使用 d2Key 解密." } + data.decryptBy(bot.client.wLoginSigInfo.d2Key, size).also { PacketLogger.verbose { "成功使用 d2Key 解密" } } } }.getOrElse { // 慢速解密 - PacketLogger.verbose("失败, 尝试其他各种key") + PacketLogger.verbose { "失败, 尝试其他各种key" } bot.client.tryDecryptOrNull(data, size) { it } }?.toReadPacket()?.let { decryptedData -> // 解析外层包装 @@ -204,8 +204,8 @@ internal object KnownPacketFactories { }?.let { // 处理内层真实的包 if (it.packetFactory == null) { - PacketLogger.warning("找不到 PacketFactory") - PacketLogger.verbose("传递给 PacketFactory 的数据 = ${it.data.useBytes { data, length -> data.toUHexString(length = length) }}") + PacketLogger.warning { "找不到 PacketFactory" } + PacketLogger.verbose { "传递给 PacketFactory 的数据 = ${it.data.useBytes { data, length -> data.toUHexString(length = length) }}" } return } @@ -234,7 +234,7 @@ internal object KnownPacketFactories { } } ?: inline { // 无法解析 - PacketLogger.error("任何key都无法解密: ${data.take(size).toUHexString()}") + PacketLogger.error{"任何key都无法解密: ${data.take(size).toUHexString()}"} return } } @@ -259,20 +259,17 @@ internal object KnownPacketFactories { // head input.readPacket(input.readInt() - 4).withUse { ssoSequenceId = readInt() - PacketLogger.verbose("sequenceId = $ssoSequenceId") + PacketLogger.verbose { "sequenceId = $ssoSequenceId" } val returnCode = readInt() if (returnCode != 0) { error("returnCode = $returnCode") } val extraData = readBytes(readInt() - 4) - PacketLogger.verbose("(sso/inner)extraData = ${extraData.toUHexString()}") + PacketLogger.verbose { "(sso/inner)extraData = ${extraData.toUHexString()}" } commandName = readString(readInt() - 4) - bot.client.outgoingPacketUnknownValue = readBytes(readInt() - 4) + bot.client.outgoingPacketSessionId = readBytes(readInt() - 4) - if (commandName == "ConfigPushSvc.PushReq") { - bot.client.configPushSvcPushReqSequenceId = ssoSequenceId - } dataCompressed = readInt() } 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 f210016b7..47fc1b9a9 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 @@ -27,9 +27,7 @@ internal class ConfigPushSvc { return network.run { buildResponseUniPacket( client, - sequenceId = client.configPushSvcPushReqSequenceId, - commandName = "ConfigPushSvc.PushResp", - name = "ConfigPushSvc.PushResp" + sequenceId = sequenceId ) { writeJceStruct( RequestPacket.serializer(), From ce3ba66d34fb7558484df8a2031f6012b135fe4e Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 8 Feb 2020 01:17:44 +0800 Subject: [PATCH 02/11] Faster init: saved 200ms for each load --- .../network/QQAndroidBotNetworkHandler.kt | 227 +++++++++--------- 1 file changed, 119 insertions(+), 108 deletions(-) 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 58ff8a668..fb59f24d6 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 @@ -33,6 +33,8 @@ import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.io.* import kotlin.coroutines.CoroutineContext import kotlin.jvm.Volatile +import kotlin.time.ExperimentalTime +import kotlin.time.measureTime @Suppress("MemberVisibilityCanBePrivate") @UseExperimental(MiraiInternalAPI::class) @@ -106,8 +108,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler StatSvc.Register(bot.client).sendAndExpect(6000) // it's slow } - @UseExperimental(MiraiExperimentalAPI::class) - override suspend fun init() { + @UseExperimental(MiraiExperimentalAPI::class, ExperimentalTime::class) + override suspend fun init(): Unit = coroutineScope { this@QQAndroidBotNetworkHandler.subscribeAlways { if (this@QQAndroidBotNetworkHandler.bot == this.bot) { this.bot.logger.error("被挤下线") @@ -117,102 +119,106 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect() - //val msg = MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect() - //println(msg.contentToString()) bot.qqs.delegate.clear() bot.groups.delegate.clear() - val startTime = currentTimeMillis - try { - bot.logger.info("开始加载好友信息") - var currentFriendCount = 0 - var totalFriendCount: Short - while (true) { - val data = FriendList.GetFriendGroupList( - bot.client, - currentFriendCount, - 150, - 0, - 0 - ).sendAndExpect(timeoutMillis = 5000, retry = 2) + val friendListLoadTime = async { + measureTime { + try { + bot.logger.info("开始加载好友信息") + var currentFriendCount = 0 + var totalFriendCount: Short + while (true) { + val data = FriendList.GetFriendGroupList( + bot.client, + currentFriendCount, + 150, + 0, + 0 + ).sendAndExpect(timeoutMillis = 5000, retry = 2) - totalFriendCount = data.totalFriendCount - data.friendList.forEach { - // atomic add - bot.qqs.delegate.addLast(QQImpl(bot, bot.coroutineContext, it.friendUin)).also { - currentFriendCount++ + totalFriendCount = data.totalFriendCount + data.friendList.forEach { + // atomic add + bot.qqs.delegate.addLast(QQImpl(bot, bot.coroutineContext, it.friendUin)).also { + currentFriendCount++ + } + } + bot.logger.verbose("正在加载好友列表 ${currentFriendCount}/${totalFriendCount}") + if (currentFriendCount >= totalFriendCount) { + break + } + // delay(200) } + bot.logger.info("好友列表加载完成, 共 ${currentFriendCount}个") + } catch (e: Exception) { + bot.logger.error("加载好友列表失败|一般这是由于加载过于频繁导致/将以热加载方式加载好友列表") } - bot.logger.verbose("正在加载好友列表 ${currentFriendCount}/${totalFriendCount}") - if (currentFriendCount >= totalFriendCount) { - break - } - // delay(200) } - bot.logger.info("好友列表加载完成, 共 ${currentFriendCount}个") - } catch (e: Exception) { - bot.logger.error("加载好友列表失败|一般这是由于加载过于频繁导致/将以热加载方式加载好友列表") } - val friendLoadFinish = currentTimeMillis val groupInfo = mutableMapOf() - coroutineScope { - try { - bot.logger.info("开始加载群组列表与群成员列表") - val troopListData = FriendList.GetTroopListSimplify(bot.client) - .sendAndExpect(timeoutMillis = 5000, retry = 2) - // println("获取到群数量" + troopData.groups.size) - val toGet: MutableMap> = mutableMapOf() - troopListData.groups.forEach { troopNum -> - val contactList = ContactList(LockFreeLinkedList()) - val groupInfoResponse = try { - TroopManagement.GetGroupOperationInfo( - client = bot.client, - groupCode = troopNum.groupCode - ).sendAndExpect() - } catch (e: Exception) { - bot.logger.info("获取" + troopNum.groupCode + "的群设置失败") - TroopManagement.GetGroupOperationInfo.Response( - allowAnonymousChat = false, - allowMemberInvite = false, - autoApprove = false, - confessTalk = false - ) - } - val group = - GroupImpl( - bot = bot, - coroutineContext = bot.coroutineContext, - id = troopNum.groupCode, - uin = troopNum.groupUin, - _name = troopNum.groupName, - _announcement = troopNum.groupMemo, - _allowMemberInvite = groupInfoResponse.allowMemberInvite, - _confessTalk = groupInfoResponse.confessTalk, - _muteAll = troopNum.dwShutUpTimestamp != 0L, - _autoApprove = groupInfoResponse.autoApprove, - _anonymousChat = groupInfoResponse.allowAnonymousChat, - members = contactList - ) - toGet[group] = contactList - bot.groups.delegate.addLast(group) - launch { - try { - getTroopMemberList(group, contactList, troopNum.dwGroupOwnerUin) - groupInfo[troopNum.groupCode] = contactList.size + + val groupTime = async { + measureTime { + try { + bot.logger.info("开始加载群组列表与群成员列表") + val troopListData = FriendList.GetTroopListSimplify(bot.client) + .sendAndExpect(timeoutMillis = 5000, retry = 2) + // println("获取到群数量" + troopData.groups.size) + val toGet: MutableMap> = mutableMapOf() + troopListData.groups.forEach { troopNum -> + val contactList = ContactList(LockFreeLinkedList()) + val groupInfoResponse = try { + TroopManagement.GetGroupOperationInfo( + client = bot.client, + groupCode = troopNum.groupCode + ).sendAndExpect() } catch (e: Exception) { - groupInfo[troopNum.groupCode] = -1 - bot.logger.info("群${troopNum.groupCode}的列表拉取失败, 将采用动态加入") - bot.logger.error(e) + bot.logger.info("获取" + troopNum.groupCode + "的群设置失败") + TroopManagement.GetGroupOperationInfo.Response( + allowAnonymousChat = false, + allowMemberInvite = false, + autoApprove = false, + confessTalk = false + ) + } + val group = + GroupImpl( + bot = bot, + coroutineContext = bot.coroutineContext, + id = troopNum.groupCode, + uin = troopNum.groupUin, + _name = troopNum.groupName, + _announcement = troopNum.groupMemo, + _allowMemberInvite = groupInfoResponse.allowMemberInvite, + _confessTalk = groupInfoResponse.confessTalk, + _muteAll = troopNum.dwShutUpTimestamp != 0L, + _autoApprove = groupInfoResponse.autoApprove, + _anonymousChat = groupInfoResponse.allowAnonymousChat, + members = contactList + ) + toGet[group] = contactList + bot.groups.delegate.addLast(group) + launch { + try { + fillTroopMemberList(group, contactList, troopNum.dwGroupOwnerUin) + groupInfo[troopNum.groupCode] = contactList.size + } catch (e: Exception) { + groupInfo[troopNum.groupCode] = -1 + bot.logger.warning("群${troopNum.groupCode}的列表拉取失败, 将采用动态加入") + bot.logger.error(e) + } } } + bot.logger.info("群组列表与群成员加载完成, 共 ${troopListData.groups.size}个") + } catch (e: Exception) { + bot.logger.error("加载组信息失败|一般这是由于加载过于频繁导致/将以热加载方式加载群列表") + bot.logger.error(e) } - bot.logger.info("群组列表与群成员加载完成, 共 ${troopListData.groups.size}个") - } catch (e: Exception) { - bot.logger.error("加载组信息失败|一般这是由于加载过于频繁导致/将以热加载方式加载群列表") - bot.logger.error(e) } } + //===log===// fun fillUntil(long: Number, size: Int): String { val x = long.toString() @@ -225,9 +231,11 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ) } + joinAll(friendListLoadTime, groupTime) + bot.logger.info("====================Mirai Bot List初始化完毕====================") - bot.logger.info("好友数量: ${fillUntil(bot.qqs.size, 9)}\t\t\t 加载时间: ${friendLoadFinish - startTime}ms") - bot.logger.info("加入群组: ${fillUntil(bot.groups.size, 9)}\t\t\t 加载时间: ${currentTimeMillis - friendLoadFinish}ms") + bot.logger.info("好友数量: ${fillUntil(bot.qqs.size, 9)}\t\t\t 加载时间: ${friendListLoadTime.await().inMilliseconds}ms") + bot.logger.info("加入群组: ${fillUntil(bot.groups.size, 9)}\t\t\t 加载时间: ${groupTime.await().inMilliseconds}ms") groupInfo.forEach { if (it.value == -1) { bot.logger.error("群组号码: ${fillUntil(it.key, 9)}\t 成员数量加载失败") @@ -242,34 +250,40 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } bot.logger.info("====================Mirai Bot List初始化完毕====================") - bot.firstLoginSucceed = true - - launch { + this@QQAndroidBotNetworkHandler.launch(CoroutineName("Heartbeat")) { while (this.isActive) { delay(bot.configuration.heartbeatPeriodMillis) - var lastException: Exception? - try { - check( - StatSvc.GetOnlineStatus(bot.client) - .sendAndExpect( - timeoutMillis = bot.configuration.heartbeatTimeoutMillis, - retry = 1 - ) is StatSvc.GetOnlineStatus.Response.Success - ) - continue - } catch (e: Exception) { - lastException = e + val failException = doHeartBeat() + if (failException != null) { + delay(bot.configuration.firstReconnectDelayMillis) + close() + bot.tryReinitializeNetworkHandler(failException) } - delay(bot.configuration.firstReconnectDelayMillis) - close() - bot.tryReinitializeNetworkHandler(lastException) } } + + bot.firstLoginSucceed = true } + suspend fun doHeartBeat(): Exception? { + var lastException: Exception? + try { + check( + StatSvc.GetOnlineStatus(bot.client) + .sendAndExpect( + timeoutMillis = bot.configuration.heartbeatTimeoutMillis, + retry = 1 + ) is StatSvc.GetOnlineStatus.Response.Success + ) + return null + } catch (e: Exception) { + lastException = e + } + return lastException + } - suspend fun getTroopMemberList(group: GroupImpl, list: ContactList, owner: Long): ContactList { - bot.logger.info("开始获取群[${group.uin}]成员列表") + suspend fun fillTroopMemberList(group: GroupImpl, list: ContactList, owner: Long) { + bot.logger.verbose("开始获取群[${group.uin}]成员列表") var size = 0 var nextUin = 0L while (true) { @@ -306,10 +320,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler if (nextUin == 0L) { break } - //println("已获取群[${group.uin}]成员列表前" + size + "个成员") } - //println("群[${group.uin}]成员全部获取完成, 共${list.size}个成员") - return list } /** @@ -473,7 +484,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler cachedPacketTimeoutJob = launch { delay(1000) if (cachedPacketTimeoutJob == this.coroutineContext[Job] && cachedPacket.getAndSet(null) != null) { - PacketLogger.verbose("等待另一部分包时超时. 将舍弃已接收的半个包") + PacketLogger.verbose { "等待另一部分包时超时. 将舍弃已接收的半个包" } } } } From 5c5670c66fd78df791c24d0370d20fed06297863 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 8 Feb 2020 16:03:20 +0800 Subject: [PATCH 03/11] Add QuoteReply --- .../net.mamoe.mirai/message/data/MessageSource.kt | 8 ++++++++ .../kotlin/net.mamoe.mirai/message/data/QuoteReply.kt | 11 +++++++++++ 2 files changed, 19 insertions(+) create mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt create mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt new file mode 100644 index 000000000..571174f55 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt @@ -0,0 +1,8 @@ +package net.mamoe.mirai.message.data + +/** + * 消息源, 用于被引用. 它将由协议模块实现为 `MessageSourceImpl` + */ +interface MessageSource : Message { + companion object : Message.Key +} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt new file mode 100644 index 000000000..3b32a8fbe --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt @@ -0,0 +1,11 @@ +package net.mamoe.mirai.message.data + + +/** + * 群内的引用回复. 它将由协议模块实现为 `QuoteReplyImpl` + */ +interface QuoteReply : Message { + val source: MessageSource + + companion object Key : Message.Key +} \ No newline at end of file From ad2e1e243eee3367c6b52edb1fc70c6335fee1f3 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 8 Feb 2020 16:03:43 +0800 Subject: [PATCH 04/11] Less log --- .../kotlin/androidPacketTests/clientToServer.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt index ef2a81cf0..96b02acd0 100644 --- a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt +++ b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt @@ -126,14 +126,14 @@ fun Map.printTLVMap(name: String = "", keyLength: Int = 2) = fun ByteReadPacket.analysisOneFullPacket(): ByteReadPacket = debugIfFail("Failed", { buildPacket { writeInt(it.size + 4); writeFully(it) } }) { val flag1 = readInt() - println("flag1=" + flag1.contentToString()) + print("flag1=" + flag1.contentToString() + ", ") val flag2 = readByte().toInt() - println("flag2=$flag2") + print("flag2=$flag2" + ", ") if (flag1 == 0x0B) { if (flag2 == 1) { - println("sequenceId = " + readInt().toUHexString()) + print("sequenceId = " + readInt().toUHexString() + ", ") } else { - println("extra data=" + readBytes(readInt() - 4).toUHexString()) + print("extra data=" + readBytes(readInt() - 4).toUHexString() + ", ") } } else { //if (flag2 == 1) { @@ -145,15 +145,15 @@ fun ByteReadPacket.analysisOneFullPacket(): ByteReadPacket = debugIfFail("Failed // } } - println("flag3=" + readByte().toUHexString()) - println("uin=" + readString(readInt() - 4)) + print("flag3=" + readByte().toUHexString() + ", ") + readString(readInt() - 4) - println("// 解密 body") + print("// 解密 body") val encrypted = readBytes() val decrypted = encrypted.tryDecryptOrNull() if (decrypted == null) { - println("cannot decrypt: ${encrypted.toUHexString()}") + println(", cannot decrypt: ${encrypted.toUHexString()}") error("cannot decrypt: ${encrypted.toUHexString()}") } else { decrypted.toReadPacket().debugPrintThis("outer body decrypted").apply { From ee3f08f722981b18b53fa915cb221dc1fed9c9fb Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 8 Feb 2020 16:04:06 +0800 Subject: [PATCH 05/11] Move MessageQQA.kt to message --- .../mamoe/mirai/qqandroid/{utils => message}/MessageQQA.kt | 2 +- .../network/protocol/packet/chat/receive/MessageSvc.kt | 4 ++-- .../network/protocol/packet/chat/receive/OnlinePush.kt | 2 +- mirai-core-qqandroid/src/jvmTest/kotlin/test/QLogReader.kt | 4 ++++ 4 files changed, 8 insertions(+), 4 deletions(-) rename mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/{utils => message}/MessageQQA.kt (99%) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/MessageQQA.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt similarity index 99% rename from mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/MessageQQA.kt rename to mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt index 6fb3d7961..01573d540 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/MessageQQA.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt @@ -1,4 +1,4 @@ -package net.mamoe.mirai.qqandroid.utils +package net.mamoe.mirai.qqandroid.message import kotlinx.io.core.readUInt import net.mamoe.mirai.message.data.* 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 a47583e6b..9d2ce1c64 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 @@ -21,8 +21,8 @@ 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.* -import net.mamoe.mirai.qqandroid.utils.toMessageChain -import net.mamoe.mirai.qqandroid.utils.toRichTextElems +import net.mamoe.mirai.qqandroid.message.toMessageChain +import net.mamoe.mirai.qqandroid.message.toRichTextElems import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.currentTimeSeconds import kotlin.math.absoluteValue diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt index bcd8e3b7c..99875ab37 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt @@ -19,7 +19,7 @@ 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.IncomingPacketFactory import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket -import net.mamoe.mirai.qqandroid.utils.toMessageChain +import net.mamoe.mirai.qqandroid.message.toMessageChain import net.mamoe.mirai.utils.cryptor.contentToString import net.mamoe.mirai.utils.io.discardExact import net.mamoe.mirai.utils.io.read diff --git a/mirai-core-qqandroid/src/jvmTest/kotlin/test/QLogReader.kt b/mirai-core-qqandroid/src/jvmTest/kotlin/test/QLogReader.kt index 1fafcb180..4a9741302 100644 --- a/mirai-core-qqandroid/src/jvmTest/kotlin/test/QLogReader.kt +++ b/mirai-core-qqandroid/src/jvmTest/kotlin/test/QLogReader.kt @@ -16,6 +16,10 @@ object QLogReader { return (decompress(file.readBytes())) } + fun readQLog(file: ByteArray): String { + return (decompress(file)) + } + fun decompress(array: ByteArray): String { return buildString { From 24d7d49a24a7c34bccadcd9d2b46fdf3bb805a56 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 8 Feb 2020 16:57:48 +0800 Subject: [PATCH 06/11] Fix endsWith --- .../kotlin/net.mamoe.mirai/event/MessageSubscribers.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt index 8d8222d0f..32604623d 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt @@ -305,12 +305,12 @@ class MessageSubscribersBuilder>( ): Listener { return if (trim) { val toCheck = suffix.trim() - content({ it.trimStart().startsWith(toCheck) }, { - if (removeSuffix) this.onEvent(this.message.toString().substringBeforeLast(toCheck).trim()) + content({ it.trimEnd().endsWith(toCheck) }, { + if (removeSuffix) this.onEvent(this.message.toString().removeSuffix(toCheck).trim()) else onEvent(this, this.message.toString().trim()) }) } else { - content({ it.startsWith(suffix) }, { + content({ it.endsWith(suffix) }, { if (removeSuffix) this.onEvent(this.message.toString().removeSuffix(suffix)) else onEvent(this, this.message.toString()) }) From 96554f2c9575d2097e0db38a31b4a76ca2bfd560 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 8 Feb 2020 16:59:24 +0800 Subject: [PATCH 07/11] Remove bad heartbeat --- .../mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fb59f24d6..f4bdeb67c 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 @@ -253,7 +253,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler this@QQAndroidBotNetworkHandler.launch(CoroutineName("Heartbeat")) { while (this.isActive) { delay(bot.configuration.heartbeatPeriodMillis) - val failException = doHeartBeat() + val failException = null//doHeartBeat() if (failException != null) { delay(bot.configuration.firstReconnectDelayMillis) close() From e2f50210bcc865ac2b75119e347302dd7787b3a6 Mon Sep 17 00:00:00 2001 From: ryoii Date: Sat, 8 Feb 2020 17:27:00 +0800 Subject: [PATCH 08/11] http-api refactor dto --- .../mamoe/mirai/api/http/data/Exception.kt | 38 ++++++++ .../mamoe/mirai/api/http/data/StateCode.kt | 21 ++++ .../http/{dto => data/common}/ContactDTO.kt | 5 +- .../mamoe/mirai/api/http/data/common/DTO.kt | 18 ++++ .../http/{dto => data/common}/MessageDTO.kt | 2 +- .../net/mamoe/mirai/api/http/dto/AuthDTO.kt | 6 -- .../net/mamoe/mirai/api/http/dto/VerifyDTO.kt | 97 ------------------- .../mirai/api/http/route/AuthRouteModule.kt | 7 +- .../mamoe/mirai/api/http/route/BaseRoute.kt | 47 +-------- ...ageModule.kt => GroupManageRouteModule.kt} | 66 +++++++++++-- .../mirai/api/http/route/InfoRouteModule.kt | 8 +- ...uteModule.kt => SendMessageRouteModule.kt} | 21 ++-- .../api/http/{dto/DTO.kt => util/Json.kt} | 7 +- 13 files changed, 170 insertions(+), 173 deletions(-) create mode 100644 mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/Exception.kt create mode 100644 mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/StateCode.kt rename mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/{dto => data/common}/ContactDTO.kt (88%) create mode 100644 mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/DTO.kt rename mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/{dto => data/common}/MessageDTO.kt (98%) delete mode 100644 mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/AuthDTO.kt delete mode 100644 mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/VerifyDTO.kt rename mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/{GroupManageModule.kt => GroupManageRouteModule.kt} (57%) rename mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/{MessageRouteModule.kt => SendMessageRouteModule.kt} (73%) rename mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/{dto/DTO.kt => util/Json.kt} (93%) diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/Exception.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/Exception.kt new file mode 100644 index 000000000..2f6113472 --- /dev/null +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/Exception.kt @@ -0,0 +1,38 @@ +package net.mamoe.mirai.api.http.data + +/** + * 错误请求. 抛出这个异常后将会返回错误给一个请求 + */ +@Suppress("unused") +open class IllegalAccessException : Exception { + override val message: String get() = super.message!! + + constructor(message: String) : super(message, null) + constructor(cause: Throwable) : super(cause.toString(), cause) + constructor(message: String, cause: Throwable?) : super(message, cause) +} + +/** + * Session失效或不存在 + */ +object IllegalSessionException : IllegalAccessException("Session失效或不存在") + +/** + * Session未激活 + */ +object NotVerifiedSessionException : IllegalAccessException("Session未激活") + +/** + * 指定Bot不存在 + */ +object NoSuchBotException: IllegalAccessException("指定Bot不存在") + +/** + * 指定Bot不存在 + */ +object PermissionDeniedException: IllegalAccessException("无操作限权") + +/** + * 错误参数 + */ +class IllegalParamException(message: String) : IllegalAccessException(message) \ No newline at end of file diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/StateCode.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/StateCode.kt new file mode 100644 index 000000000..51766c1cb --- /dev/null +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/StateCode.kt @@ -0,0 +1,21 @@ +package net.mamoe.mirai.api.http.data + +import kotlinx.serialization.Serializable + +@Serializable +open class StateCode(val code: Int, var msg: String) { + object Success : StateCode(0, "success") // 成功 + object NoBot : StateCode(2, "指定Bot不存在") + object IllegalSession : StateCode(3, "Session失效或不存在") + object NotVerifySession : StateCode(4, "Session未认证") + object NoElement : StateCode(5, "指定对象不存在") + object PermissionDenied : StateCode(10, "无操作权限") + + // KS bug: 主构造器中不能有非字段参数 https://github.com/Kotlin/kotlinx.serialization/issues/575 + @Serializable + class IllegalAccess() : StateCode(400, "") { // 非法访问 + constructor(msg: String) : this() { + this.msg = msg + } + } +} \ No newline at end of file diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/ContactDTO.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/ContactDTO.kt similarity index 88% rename from mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/ContactDTO.kt rename to mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/ContactDTO.kt index 2410a8ef9..3540e0cc6 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/ContactDTO.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/ContactDTO.kt @@ -1,4 +1,4 @@ -package net.mamoe.mirai.api.http.dto +package net.mamoe.mirai.api.http.data.common import kotlinx.serialization.Serializable import net.mamoe.mirai.contact.Group @@ -30,7 +30,8 @@ data class MemberDTO( val group: GroupDTO ) : ContactDTO() { constructor(member: Member) : this ( - member.id, member.groupCard, member.permission, GroupDTO(member.group) + member.id, member.groupCard, member.permission, + GroupDTO(member.group) ) } diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/DTO.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/DTO.kt new file mode 100644 index 000000000..157f739bc --- /dev/null +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/DTO.kt @@ -0,0 +1,18 @@ +package net.mamoe.mirai.api.http.data.common + +import kotlinx.serialization.* +import kotlinx.serialization.json.Json +import kotlinx.serialization.modules.SerializersModule +import net.mamoe.mirai.api.http.AuthedSession + +interface DTO + +@Serializable +data class AuthDTO(val authKey: String) : DTO + +@Serializable +abstract class VerifyDTO : DTO { + abstract val sessionKey: String + @Transient + lateinit var session: AuthedSession // 反序列化验证成功后传入 +} diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/MessageDTO.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt similarity index 98% rename from mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/MessageDTO.kt rename to mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt index e670b3f33..dea0705e5 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/MessageDTO.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt @@ -1,4 +1,4 @@ -package net.mamoe.mirai.api.http.dto +package net.mamoe.mirai.api.http.data.common import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/AuthDTO.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/AuthDTO.kt deleted file mode 100644 index ac8ccb5a0..000000000 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/AuthDTO.kt +++ /dev/null @@ -1,6 +0,0 @@ -package net.mamoe.mirai.api.http.dto - -import kotlinx.serialization.Serializable - -@Serializable -data class AuthDTO(val authKey: String) : DTO diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/VerifyDTO.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/VerifyDTO.kt deleted file mode 100644 index e652c5167..000000000 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/VerifyDTO.kt +++ /dev/null @@ -1,97 +0,0 @@ -package net.mamoe.mirai.api.http.dto - -import kotlinx.serialization.Serializable -import kotlinx.serialization.Transient -import net.mamoe.mirai.api.http.AuthedSession -import net.mamoe.mirai.contact.Group -import net.mamoe.mirai.contact.Member - -@Serializable -abstract class VerifyDTO : DTO { - abstract val sessionKey: String - @Transient - lateinit var session: AuthedSession // 反序列化验证后传入 -} - -@Serializable -data class BindDTO(override val sessionKey: String, val qq: Long) : VerifyDTO() - -@Serializable -data class SendDTO( - override val sessionKey: String, - val target: Long, - val messageChain: MessageChainDTO -) : VerifyDTO() - -typealias GroupTargetDTO = FriendTargetDTO - -@Serializable -data class FriendTargetDTO( - override val sessionKey: String, - val target: Long -) : VerifyDTO() - -@Serializable -data class MuteDTO( - override val sessionKey: String, - val target: Long, - val member: Long = 0, - val time: Int = 0 -) : VerifyDTO() - -@Serializable -data class GroupConfigDTO( - override val sessionKey: String, - val target: Long, - val config: GroupInfoDTO -) : VerifyDTO() - -@Serializable -data class GroupInfoDTO( - val name: String? = null, - val announcement: String? = null, - val confessTalk: Boolean? = null, - val allowMemberInvite: Boolean? = null, - val autoApprove: Boolean? = null, - val anonymousChat: Boolean? = null -) : DTO { - constructor(group: Group) : this( - group.name, group.announcement, group.confessTalk, group.allowMemberInvite, - group.autoApprove, group.anonymousChat - ) -} - -@Serializable -data class MemberConfigDTO( - override val sessionKey: String, - val target: Long, - val memberId: Long, - val config: MemberInfoDTO -) : VerifyDTO() - -@Serializable -data class MemberInfoDTO( - val name: String? = null, - val specialTitle: String? = null -) : DTO { - constructor(member: Member) : this(member.groupCard, member.specialTitle) -} - -@Serializable -open class StateCode(val code: Int, var msg: String) { - object Success : StateCode(0, "success") // 成功 - object NoBot : StateCode(2, "指定Bot不存在") - object IllegalSession : StateCode(3, "Session失效或不存在") - object NotVerifySession : StateCode(4, "Session未认证") - object NoElement : StateCode(5, "指定对象不存在") - object PermissionDenied : StateCode(10, "无操作权限") - - // KS bug: 主构造器中不能有非字段参数 https://github.com/Kotlin/kotlinx.serialization/issues/575 - @Serializable - class IllegalAccess() : StateCode(400, "") { // 非法访问 - constructor(msg: String) : this() { - this.msg = msg - } - } -} - diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/AuthRouteModule.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/AuthRouteModule.kt index 718d8b7a3..8191447fd 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/AuthRouteModule.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/AuthRouteModule.kt @@ -3,10 +3,12 @@ package net.mamoe.mirai.api.http.route import io.ktor.application.Application import io.ktor.application.call import io.ktor.routing.routing +import kotlinx.serialization.Serializable import net.mamoe.mirai.Bot import net.mamoe.mirai.api.http.AuthedSession import net.mamoe.mirai.api.http.SessionManager -import net.mamoe.mirai.api.http.dto.* +import net.mamoe.mirai.api.http.data.* +import net.mamoe.mirai.api.http.data.common.VerifyDTO import kotlin.coroutines.EmptyCoroutineContext @@ -43,6 +45,9 @@ fun Application.authModule() { } } +@Serializable +private data class BindDTO(override val sessionKey: String, val qq: Long) : VerifyDTO() + private fun getBotOrThrow(qq: Long) = try { Bot.instanceWhose(qq) } catch (e: NoSuchElementException) { diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/BaseRoute.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/BaseRoute.kt index fab85148b..d6d1148ec 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/BaseRoute.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/BaseRoute.kt @@ -19,7 +19,10 @@ import io.ktor.util.pipeline.PipelineContext import net.mamoe.mirai.api.http.AuthedSession import net.mamoe.mirai.api.http.SessionManager import net.mamoe.mirai.api.http.TempSession -import net.mamoe.mirai.api.http.dto.* +import net.mamoe.mirai.api.http.data.* +import net.mamoe.mirai.api.http.data.common.* +import net.mamoe.mirai.api.http.util.jsonParseOrNull +import net.mamoe.mirai.api.http.util.toJson fun Application.mirai() { install(DefaultHeaders) @@ -136,14 +139,13 @@ internal suspend fun ApplicationCall.respondJson(json: String, status: HttpStatu internal suspend inline fun ApplicationCall.receiveDTO(): T? = receive().jsonParseOrNull() - - fun PipelineContext.illegalParam( expectingType: String?, paramName: String, actualValue: String? = call.parameters[paramName] ): Nothing = throw IllegalParamException("Illegal param. A $expectingType is required for `$paramName` while `$actualValue` is given") + @Suppress("IMPLICIT_CAST_TO_ANY") @UseExperimental(ExperimentalUnsignedTypes::class) internal inline fun PipelineContext.paramOrNull(name: String): R = @@ -171,42 +173,3 @@ internal inline fun PipelineContext.paramOrNu else -> error(name::class.simpleName + " is not supported") } as R ?: illegalParam(R::class.simpleName, name) - - -/** - * 错误请求. 抛出这个异常后将会返回错误给一个请求 - */ -@Suppress("unused") -open class IllegalAccessException : Exception { - override val message: String get() = super.message!! - - constructor(message: String) : super(message, null) - constructor(cause: Throwable) : super(cause.toString(), cause) - constructor(message: String, cause: Throwable?) : super(message, cause) -} - -/** - * Session失效或不存在 - */ -object IllegalSessionException : IllegalAccessException("Session失效或不存在") - -/** - * Session未激活 - */ -object NotVerifiedSessionException : IllegalAccessException("Session未激活") - -/** - * 指定Bot不存在 - */ -object NoSuchBotException: IllegalAccessException("指定Bot不存在") - -/** - * 指定Bot不存在 - */ -object PermissionDeniedException: IllegalAccessException("无操作限权") - -/** - * 错误参数 - */ -class IllegalParamException(message: String) : IllegalAccessException(message) - diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageModule.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt similarity index 57% rename from mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageModule.kt rename to mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt index 69299ae06..b316be667 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageModule.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt @@ -3,7 +3,12 @@ package net.mamoe.mirai.api.http.route import io.ktor.application.Application import io.ktor.application.call import io.ktor.routing.routing -import net.mamoe.mirai.api.http.dto.* +import kotlinx.serialization.Serializable +import net.mamoe.mirai.api.http.data.* +import net.mamoe.mirai.api.http.data.common.DTO +import net.mamoe.mirai.api.http.data.common.VerifyDTO +import net.mamoe.mirai.contact.Group +import net.mamoe.mirai.contact.Member fun Application.groupManageModule() { @@ -23,14 +28,14 @@ fun Application.groupManageModule() { } miraiVerify("/mute") { - when(it.session.bot.getGroup(it.target)[it.member].mute(it.time)) { + when(it.session.bot.getGroup(it.target)[it.memberId].mute(it.time)) { true -> call.respondStateCode(StateCode.Success) else -> throw PermissionDeniedException } } miraiVerify("/unmute") { - when(it.session.bot.getGroup(it.target).members[it.member].unmute()) { + when(it.session.bot.getGroup(it.target).members[it.memberId].unmute()) { true -> call.respondStateCode(StateCode.Success) else -> throw PermissionDeniedException } @@ -41,7 +46,7 @@ fun Application.groupManageModule() { */ miraiGet("/groupConfig") { val group = it.bot.getGroup(paramOrNull("target")) - call.respondDTO(GroupInfoDTO(group)) + call.respondDTO(GroupDetailDTO(group)) } miraiVerify("/groupConfig") { dto -> @@ -63,12 +68,12 @@ fun Application.groupManageModule() { */ miraiGet("/memberInfo") { val member = it.bot.getGroup(paramOrNull("target"))[paramOrNull("memberID")] - call.respondDTO(MemberInfoDTO(member)) + call.respondDTO(MemberDetailDTO(member)) } - miraiVerify("/memberInfo") { dto -> + miraiVerify("/memberInfo") { dto -> val member = dto.session.bot.getGroup(dto.target)[dto.memberId] - with(dto.config) { + with(dto.info) { name?.let { member.groupCard = it } specialTitle?.let { member.specialTitle = it } } @@ -76,4 +81,51 @@ fun Application.groupManageModule() { } } +} + + +@Serializable +private data class MuteDTO( + override val sessionKey: String, + val target: Long, + val memberId: Long = 0, + val time: Int = 0 +) : VerifyDTO() + +@Serializable +private data class GroupConfigDTO( + override val sessionKey: String, + val target: Long, + val config: GroupDetailDTO +) : VerifyDTO() + +@Serializable +private data class GroupDetailDTO( + val name: String? = null, + val announcement: String? = null, + val confessTalk: Boolean? = null, + val allowMemberInvite: Boolean? = null, + val autoApprove: Boolean? = null, + val anonymousChat: Boolean? = null +) : DTO { + constructor(group: Group) : this( + group.name, group.announcement, group.confessTalk, group.allowMemberInvite, + group.autoApprove, group.anonymousChat + ) +} + +@Serializable +private data class MemberInfoDTO( + override val sessionKey: String, + val target: Long, + val memberId: Long, + val info: MemberDetailDTO +) : VerifyDTO() + +@Serializable +private data class MemberDetailDTO( + val name: String? = null, + val specialTitle: String? = null +) : DTO { + constructor(member: Member) : this(member.groupCard, member.specialTitle) } \ No newline at end of file diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/InfoRouteModule.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/InfoRouteModule.kt index 847f88d79..8fc741a5b 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/InfoRouteModule.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/InfoRouteModule.kt @@ -3,10 +3,10 @@ package net.mamoe.mirai.api.http.route import io.ktor.application.Application import io.ktor.application.call import io.ktor.routing.routing -import net.mamoe.mirai.api.http.dto.GroupDTO -import net.mamoe.mirai.api.http.dto.MemberDTO -import net.mamoe.mirai.api.http.dto.QQDTO -import net.mamoe.mirai.api.http.dto.toJson +import net.mamoe.mirai.api.http.data.common.GroupDTO +import net.mamoe.mirai.api.http.data.common.MemberDTO +import net.mamoe.mirai.api.http.data.common.QQDTO +import net.mamoe.mirai.api.http.util.toJson import net.mamoe.mirai.contact.toMutableList fun Application.infoModule() { diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/MessageRouteModule.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/SendMessageRouteModule.kt similarity index 73% rename from mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/MessageRouteModule.kt rename to mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/SendMessageRouteModule.kt index 6d3be41b0..b287c4a41 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/MessageRouteModule.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/SendMessageRouteModule.kt @@ -3,7 +3,10 @@ package net.mamoe.mirai.api.http.route import io.ktor.application.Application import io.ktor.application.call import io.ktor.routing.routing -import net.mamoe.mirai.api.http.dto.* +import kotlinx.serialization.Serializable +import net.mamoe.mirai.api.http.data.* +import net.mamoe.mirai.api.http.data.common.* +import net.mamoe.mirai.api.http.util.toJson fun Application.messageModule() { routing { @@ -26,12 +29,12 @@ fun Application.messageModule() { call.respondStateCode(StateCode.Success) } - miraiVerify("/event/message") { - - } - - miraiVerify("/addFriend") { - - } } -} \ No newline at end of file +} + +@Serializable +private data class SendDTO( + override val sessionKey: String, + val target: Long, + val messageChain: MessageChainDTO +) : VerifyDTO() \ No newline at end of file diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/DTO.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/util/Json.kt similarity index 93% rename from mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/DTO.kt rename to mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/util/Json.kt index d7acf6c22..a0fd5b45f 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/DTO.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/util/Json.kt @@ -1,10 +1,9 @@ -package net.mamoe.mirai.api.http.dto +package net.mamoe.mirai.api.http.util import kotlinx.serialization.* import kotlinx.serialization.json.Json import kotlinx.serialization.modules.SerializersModule - -interface DTO +import net.mamoe.mirai.api.http.data.common.* // 解析失败时直接返回null,由路由判断响应400状态 @UseExperimental(ImplicitReflectionSerializer::class) @@ -20,7 +19,7 @@ inline fun String.jsonParseOrNull( inline fun T.toJson( serializer: SerializationStrategy? = null ): String = if (serializer == null) MiraiJson.json.stringify(this) - else MiraiJson.json.stringify(serializer, this) +else MiraiJson.json.stringify(serializer, this) // 序列化列表时,stringify需要使用的泛型是T,而非List From aad50921a44712404f4809f5919565ce54e8979a Mon Sep 17 00:00:00 2001 From: ryoii Date: Sat, 8 Feb 2020 17:39:45 +0800 Subject: [PATCH 09/11] fix --- .../net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt index b316be667..96bd31f68 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt @@ -67,7 +67,7 @@ fun Application.groupManageModule() { * 群员信息管理(需要相关权限) */ miraiGet("/memberInfo") { - val member = it.bot.getGroup(paramOrNull("target"))[paramOrNull("memberID")] + val member = it.bot.getGroup(paramOrNull("target"))[paramOrNull("memberId")] call.respondDTO(MemberDetailDTO(member)) } From cf82401eed077b88760043c663995eb173ba0886 Mon Sep 17 00:00:00 2001 From: ryoii Date: Sat, 8 Feb 2020 18:40:09 +0800 Subject: [PATCH 10/11] http-api support kick --- .../api/http/route/GroupManageRouteModule.kt | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt index 96bd31f68..5e5f10720 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt @@ -28,14 +28,24 @@ fun Application.groupManageModule() { } miraiVerify("/mute") { - when(it.session.bot.getGroup(it.target)[it.memberId].mute(it.time)) { + when (it.session.bot.getGroup(it.target)[it.memberId].mute(it.time)) { true -> call.respondStateCode(StateCode.Success) else -> throw PermissionDeniedException } } miraiVerify("/unmute") { - when(it.session.bot.getGroup(it.target).members[it.memberId].unmute()) { + when (it.session.bot.getGroup(it.target).members[it.memberId].unmute()) { + true -> call.respondStateCode(StateCode.Success) + else -> throw PermissionDeniedException + } + } + + /** + * 移出群聊(需要相关权限) + */ + miraiVerify("/kick") { + when (it.session.bot.getGroup(it.target)[it.memberId].kick(it.msg)) { true -> call.respondStateCode(StateCode.Success) else -> throw PermissionDeniedException } @@ -55,7 +65,7 @@ fun Application.groupManageModule() { name?.let { group.name = it } announcement?.let { group.announcement = it } confessTalk?.let { group.confessTalk = it } - allowMemberInvite?.let{ group.allowMemberInvite = it } + allowMemberInvite?.let { group.allowMemberInvite = it } // TODO: 待core接口实现设置可改 // autoApprove?.let { group.autoApprove = it } // anonymousChat?.let { group.anonymousChat = it } @@ -92,6 +102,14 @@ private data class MuteDTO( val time: Int = 0 ) : VerifyDTO() +@Serializable +private data class KickDTO( + override val sessionKey: String, + val target: Long, + val memberId: Long, + val msg: String = "" +) : VerifyDTO() + @Serializable private data class GroupConfigDTO( override val sessionKey: String, @@ -128,4 +146,4 @@ private data class MemberDetailDTO( val specialTitle: String? = null ) : DTO { constructor(member: Member) : this(member.groupCard, member.specialTitle) -} \ No newline at end of file +} From 4995921996b04fc358d3639a1acb3f3a2a20ce5d Mon Sep 17 00:00:00 2001 From: ryoii Date: Sat, 8 Feb 2020 20:15:34 +0800 Subject: [PATCH 11/11] http-api update readme_cn.md --- mirai-api-http/README_CH.md | 126 +++++++++++++++++++++++++++++++++--- 1 file changed, 116 insertions(+), 10 deletions(-) diff --git a/mirai-api-http/README_CH.md b/mirai-api-http/README_CH.md index 31d1b69cc..fb539bbc2 100644 --- a/mirai-api-http/README_CH.md +++ b/mirai-api-http/README_CH.md @@ -300,13 +300,13 @@ fun main() { ```json5 { "type": "Face", - "faceID": 123 + "faceId": 123 } ``` | 名字 | 类型 | 说明 | | ------ | ---- | ---------- | -| faceID | Int | QQ表情编号 | +| faceId | Int | QQ表情编号 | #### Plain @@ -453,7 +453,7 @@ fun main() { ### 群全体禁言 -使用此方法令指定群进行全体禁言 +使用此方法令指定群进行全体禁言(需要有相关限权) ``` [POST] /muteAll @@ -487,7 +487,7 @@ fun main() { ### 群解除全体禁言 -使用此方法令指定群解除全体禁言 +使用此方法令指定群解除全体禁言(需要有相关限权) ``` [POST] /unmuteAll @@ -505,7 +505,7 @@ fun main() { ### 群禁言群成员 -使用此方法指定群禁言指定群员 +使用此方法指定群禁言指定群员(需要有相关限权) ``` [POST] /mute @@ -517,7 +517,7 @@ fun main() { { "sessionKey": "YourSessionKey", "target": 123456789, - "member": 987654321, + "memberId": 987654321, "time": 1800 } ``` @@ -526,7 +526,7 @@ fun main() { | ---------- | ----- | ------ | ---------------- | ------------------------------------- | | sessionKey | false | String | "YourSessionKey" | 你的session key | | target | false | Long | 123456789 | 指定群的群号 | -| member | false | Long | 987654321 | 指定群员QQ号 | +| memberId | false | Long | 987654321 | 指定群员QQ号 | | time | true | Int | 1800 | 禁言时长,单位为秒,最多30天,默认为0 | #### 响应: 返回统一状态码 @@ -542,7 +542,7 @@ fun main() { ### 群解除群成员禁言 -使用此方法令指定群解除全体禁言 +使用此方法令指定群解除全体禁言(需要有相关限权) ``` [POST] /unmute @@ -554,7 +554,7 @@ fun main() { { "sessionKey": "YourSessionKey", "target": 123456789, - "member": 987654321 + "memberId": 987654321 } ``` @@ -564,9 +564,48 @@ fun main() { +### 移除群成员 + +使用此方法移除指定群成员(需要有相关限权) + +``` +[POST] /kick +``` + +#### 请求: + +```json5 +{ + "sessionKey": "YourSessionKey", + "target": 123456789, + "memberId": 987654321, + "msg": "您已被移出群聊" +} +``` + +| 名字 | 可选 | 类型 | 举例 | 说明 | +| ---------- | ----- | ------ | ---------------- | --------------- | +| sessionKey | false | String | "YourSessionKey" | 你的session key | +| target | false | Long | 123456789 | 指定群的群号 | +| memberId | false | Long | 987654321 | 指定群员QQ号 | +| msg | true | String | "" | 信息 | + +#### 响应 + +#### 响应: 返回统一状态码 + +```json5 +{ + "code": 0, + "msg": "success" +} +``` + + + ### 群设置 -使用此方法修改群设置(需要又相关限权) +使用此方法修改群设置(需要有相关限权) ``` [POST] /groupConfig @@ -638,3 +677,70 @@ fun main() { "anonymousChat": true } ``` + + +### 修改群员资料 + +使用此方法修改群员资料(需要有相关限权) + +``` +[POST] /memberInfo +``` + +#### 请求: + +```json5 +{ + "sessionKey": "YourSessionKey", + "target": 123456789, + "memberId": 987654321, + "info": { + "name": "群名片", + "specialTitle": "群头衔" + } +} +``` + +| 名字 | 可选 | 类型 | 举例 | 说明 | +| ----------------- | ----- | ------- | ---------------- | -------------------- | +| sessionKey | false | String | "YourSessionKey" | 你的session key | +| target | false | Long | 123456789 | 指定群的群号 | +| memberId | false | Long | 987654321 | 群员QQ号 | +| info | false | Object | {} | 群员资料 | +| name | true | String | "Name" | 群名片,即群昵称 | +| specialTitle | true | String | "Title" | 群头衔 | + +#### 响应: 返回统一状态码 + +```json5 +{ + "code": 0, + "msg": "success" +} +``` + +### 获取群员资料 + +使用此方法获取群员资料 + +``` +[Get] /groupConfig?sessionKey=YourSessionKey&target=123456789 +``` + +#### 请求: + +| 名字 | 可选 | 类型 | 举例 | 说明 | +| ----------------- | ----- | ------- | ---------------- | -------------------- | +| sessionKey | false | String | YourSessionKey | 你的session key | +| target | false | Long | 123456789 | 指定群的群号 | +| memberId | false | Long | 987654321 | 群员QQ号 | + + +#### 响应 + +```json5 +{ + "name": "群名片", + "announcement": "群头衔" +} +``` \ No newline at end of file