Commit 181ab6e3 authored by Him188's avatar Him188

Improve performance

parent 2aaff44c
...@@ -32,9 +32,9 @@ internal actual class ECDHKeyPairImpl( ...@@ -32,9 +32,9 @@ internal actual class ECDHKeyPairImpl(
} }
@Suppress("FunctionName") @Suppress("FunctionName")
actual fun ECDH() = ECDH(ECDH.generateKeyPair()) internal actual fun ECDH() = ECDH(ECDH.generateKeyPair())
actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) { internal actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) {
actual companion object { actual companion object {
@Suppress("ObjectPropertyName") @Suppress("ObjectPropertyName")
private var _isECDHAvailable: Boolean = false // because `runCatching` has no contract. private var _isECDHAvailable: Boolean = false // because `runCatching` has no contract.
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE * https://github.com/mamoe/mirai/blob/master/LICENSE
*/ */
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.qqandroid package net.mamoe.mirai.qqandroid
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
...@@ -34,7 +36,6 @@ import net.mamoe.mirai.qqandroid.contact.MemberInfoImpl ...@@ -34,7 +36,6 @@ import net.mamoe.mirai.qqandroid.contact.MemberInfoImpl
import net.mamoe.mirai.qqandroid.contact.QQImpl import net.mamoe.mirai.qqandroid.contact.QQImpl
import net.mamoe.mirai.qqandroid.contact.checkIsGroupImpl import net.mamoe.mirai.qqandroid.contact.checkIsGroupImpl
import net.mamoe.mirai.qqandroid.io.serialization.toByteArray import net.mamoe.mirai.qqandroid.io.serialization.toByteArray
import net.mamoe.mirai.qqandroid.message.MessageSourceFromSendFriend
import net.mamoe.mirai.qqandroid.message.OnlineFriendImageImpl import net.mamoe.mirai.qqandroid.message.OnlineFriendImageImpl
import net.mamoe.mirai.qqandroid.message.OnlineGroupImageImpl import net.mamoe.mirai.qqandroid.message.OnlineGroupImageImpl
import net.mamoe.mirai.qqandroid.network.QQAndroidBotNetworkHandler import net.mamoe.mirai.qqandroid.network.QQAndroidBotNetworkHandler
...@@ -373,29 +374,17 @@ internal abstract class QQAndroidBotBase constructor( ...@@ -373,29 +374,17 @@ internal abstract class QQAndroidBotBase constructor(
check(chain.toString().length <= 4500 && chain.count { it is Image } <= 50) { "message is too large. Allow up to 4500 chars or 50 images" } check(chain.toString().length <= 4500 && chain.count { it is Image } <= 50) { "message is too large. Allow up to 4500 chars or 50 images" }
val group = getGroup(groupCode) val group = getGroup(groupCode)
val source = MessageSourceFromSendFriend(
messageRandom = Random.nextInt().absoluteValue,
senderId = client.uin,
toUin = Group.calculateGroupUinByGroupCode(groupCode),
time = currentTimeSeconds,
groupId = groupCode,
originalMessage = chain,
sequenceId = client.atomicNextMessageSequenceId()
// sourceMessage = message
)
// TODO: 2020/3/26 util 方法来添加单例元素 // TODO: 2020/3/26 util 方法来添加单例元素
val toSend = buildMessageChain(chain.size) {
source.originalMessage.forEach { val time = currentTimeSeconds
if (it !is MessageSource) {
add(it)
}
}
add(source)
}
network.run { network.run {
val data = toSend.calculateValidationDataForGroup(group) val data = chain.calculateValidationDataForGroup(
sequenceId = client.atomicNextMessageSequenceId(),
time = time.toInt(),
random = Random.nextInt().absoluteValue.toULong().toLong(),
group
)
val response = val response =
MultiMsg.ApplyUp.createForGroupLongMessage( MultiMsg.ApplyUp.createForGroupLongMessage(
...@@ -443,7 +432,7 @@ internal abstract class QQAndroidBotBase constructor( ...@@ -443,7 +432,7 @@ internal abstract class QQAndroidBotBase constructor(
group.sendMessage( group.sendMessage(
RichMessage.longMessage( RichMessage.longMessage(
brief = toSend.joinToString(limit = 30) { brief = chain.joinToString(limit = 30) {
when (it) { when (it) {
is PlainText -> it.stringValue is PlainText -> it.stringValue
is At -> it.toString() is At -> it.toString()
...@@ -451,7 +440,7 @@ internal abstract class QQAndroidBotBase constructor( ...@@ -451,7 +440,7 @@ internal abstract class QQAndroidBotBase constructor(
} }
}, },
resId = resId, resId = resId,
timeSeconds = source.time timeSeconds = time
) )
) )
} }
......
...@@ -27,14 +27,17 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.login.Heartbeat ...@@ -27,14 +27,17 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.login.Heartbeat
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.StatSvc import net.mamoe.mirai.qqandroid.network.protocol.packet.login.StatSvc
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.WtLogin import net.mamoe.mirai.qqandroid.network.protocol.packet.login.WtLogin
import net.mamoe.mirai.qqandroid.network.readUShortLVByteArray import net.mamoe.mirai.qqandroid.network.readUShortLVByteArray
import net.mamoe.mirai.qqandroid.utils.cryptor.TEA
import net.mamoe.mirai.qqandroid.utils.cryptor.adjustToPublicKey
import net.mamoe.mirai.qqandroid.utils.io.readPacketExact import net.mamoe.mirai.qqandroid.utils.io.readPacketExact
import net.mamoe.mirai.qqandroid.utils.io.readString import net.mamoe.mirai.qqandroid.utils.io.readString
import net.mamoe.mirai.qqandroid.utils.io.useBytes import net.mamoe.mirai.qqandroid.utils.io.useBytes
import net.mamoe.mirai.qqandroid.utils.io.withUse import net.mamoe.mirai.qqandroid.utils.io.withUse
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
import net.mamoe.mirai.qqandroid.utils.cryptor.TEA import net.mamoe.mirai.utils.io.ByteArrayPool
import net.mamoe.mirai.qqandroid.utils.cryptor.adjustToPublicKey import net.mamoe.mirai.utils.io.toInt
import net.mamoe.mirai.utils.io.* import net.mamoe.mirai.utils.io.toReadPacket
import net.mamoe.mirai.utils.io.toUHexString
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
...@@ -171,9 +174,6 @@ internal object KnownPacketFactories { ...@@ -171,9 +174,6 @@ internal object KnownPacketFactories {
?: IncomingFactories.firstOrNull { it.receivingCommandName == commandName } ?: IncomingFactories.firstOrNull { it.receivingCommandName == commandName }
} }
/**
* full packet without length
*/
// do not inline. Exceptions thrown will not be reported correctly // do not inline. Exceptions thrown will not be reported correctly
@OptIn(MiraiInternalAPI::class) @OptIn(MiraiInternalAPI::class)
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
...@@ -183,22 +183,12 @@ internal object KnownPacketFactories { ...@@ -183,22 +183,12 @@ internal object KnownPacketFactories {
val flag1 = readInt() val flag1 = readInt()
PacketLogger.verbose { "开始处理一个包" } PacketLogger.verbose { "开始处理一个包" }
PacketLogger.verbose { "flag1(0A/0B) = ${flag1.toUByte().toUHexString()}" }
val flag2 = readByte().toInt() val flag2 = readByte().toInt()
PacketLogger.verbose {
"包类型(flag2) = $flag2. (可能是 ${when (flag2) {
2 -> "OicqRequest"
1 -> "Uni/ProtoBuf"
0 -> "Heartbeat"
else -> "未知"
}})"
}
val flag3 = readByte().toInt() val flag3 = readByte().toInt()
check(flag3 == 0) { check(flag3 == 0) {
"Illegal flag3. Expected 0, whereas got $flag3. flag1=$flag1, flag2=$flag2. Remaining=${this.readBytes() "Illegal flag3. Expected 0, whereas got $flag3. flag1=$flag1, flag2=$flag2. " +
.toUHexString()}" "Remaining=${this.readBytes().toUHexString()}"
} }
readString(readInt() - 4)// uinAccount readString(readInt() - 4)// uinAccount
...@@ -209,14 +199,11 @@ internal object KnownPacketFactories { ...@@ -209,14 +199,11 @@ internal object KnownPacketFactories {
kotlin.runCatching { kotlin.runCatching {
when (flag2) { when (flag2) {
2 -> TEA.decrypt(data, DECRYPTER_16_ZERO, size) 2 -> TEA.decrypt(data, DECRYPTER_16_ZERO, size)
.also { PacketLogger.verbose { "成功使用 16 zero 解密" } }
1 -> TEA.decrypt(data, bot.client.wLoginSigInfo.d2Key, size) 1 -> TEA.decrypt(data, bot.client.wLoginSigInfo.d2Key, size)
.also { PacketLogger.verbose { "成功使用 d2Key 解密" } }
0 -> data 0 -> data
else -> error("") else -> error("")
} }
}.getOrElse { }.getOrElse {
PacketLogger.verbose { "失败, 尝试其他各种key" }
bot.client.tryDecryptOrNull(data, size) { it } bot.client.tryDecryptOrNull(data, size) { it }
}?.toReadPacket()?.let { decryptedData -> }?.toReadPacket()?.let { decryptedData ->
when (flag1) { when (flag1) {
...@@ -236,7 +223,7 @@ internal object KnownPacketFactories { ...@@ -236,7 +223,7 @@ internal object KnownPacketFactories {
} else { } else {
handleIncomingPacket(it, bot, flag2, consumer) handleIncomingPacket(it, bot, flag2, consumer)
} }
} ?: inline { } ?: kotlin.run {
PacketLogger.error { "任何key都无法解密: ${data.take(size).toUHexString()}" } PacketLogger.error { "任何key都无法解密: ${data.take(size).toUHexString()}" }
return return
} }
...@@ -295,8 +282,6 @@ internal object KnownPacketFactories { ...@@ -295,8 +282,6 @@ internal object KnownPacketFactories {
} }
} }
private inline fun <R> inline(block: () -> R): R = block()
class IncomingPacket<T : Packet?>( class IncomingPacket<T : Packet?>(
val packetFactory: PacketFactory<T>?, val packetFactory: PacketFactory<T>?,
val sequenceId: Int, val sequenceId: Int,
...@@ -358,9 +343,7 @@ internal object KnownPacketFactories { ...@@ -358,9 +343,7 @@ internal object KnownPacketFactories {
} }
} }
} }
8 -> { 8 -> input
input
}
else -> error("unknown dataCompressed flag: $dataCompressed") else -> error("unknown dataCompressed flag: $dataCompressed")
} }
......
...@@ -21,7 +21,7 @@ expect interface ECDHPublicKey { ...@@ -21,7 +21,7 @@ expect interface ECDHPublicKey {
internal expect class ECDHKeyPairImpl : ECDHKeyPair internal expect class ECDHKeyPairImpl : ECDHKeyPair
interface ECDHKeyPair { internal interface ECDHKeyPair {
val privateKey: ECDHPrivateKey val privateKey: ECDHPrivateKey
val publicKey: ECDHPublicKey val publicKey: ECDHPublicKey
...@@ -43,7 +43,7 @@ interface ECDHKeyPair { ...@@ -43,7 +43,7 @@ interface ECDHKeyPair {
/** /**
* 椭圆曲线密码, ECDH 加密 * 椭圆曲线密码, ECDH 加密
*/ */
expect class ECDH(keyPair: ECDHKeyPair) { internal expect class ECDH(keyPair: ECDHKeyPair) {
val keyPair: ECDHKeyPair val keyPair: ECDHKeyPair
/** /**
...@@ -74,9 +74,9 @@ expect class ECDH(keyPair: ECDHKeyPair) { ...@@ -74,9 +74,9 @@ expect class ECDH(keyPair: ECDHKeyPair) {
} }
@Suppress("FunctionName") @Suppress("FunctionName")
expect fun ECDH(): ECDH internal expect fun ECDH(): ECDH
val initialPublicKey internal val initialPublicKey
get() = ECDH.constructPublicKey("3046301006072A8648CE3D020106052B8104001F03320004928D8850673088B343264E0C6BACB8496D697799F37211DEB25BB73906CB089FEA9639B4E0260498B51A992D50813DA8".chunkedHexToBytes()) get() = ECDH.constructPublicKey("3046301006072A8648CE3D020106052B8104001F03320004928D8850673088B343264E0C6BACB8496D697799F37211DEB25BB73906CB089FEA9639B4E0260498B51A992D50813DA8".chunkedHexToBytes())
private val commonHeadFor02 = "302E301006072A8648CE3D020106052B8104001F031A00".chunkedHexToBytes() private val commonHeadFor02 = "302E301006072A8648CE3D020106052B8104001F031A00".chunkedHexToBytes()
private val commonHeadForNot02 = "3046301006072A8648CE3D020106052B8104001F033200".chunkedHexToBytes() private val commonHeadForNot02 = "3046301006072A8648CE3D020106052B8104001F033200".chunkedHexToBytes()
...@@ -86,7 +86,7 @@ private val byteArray_04 = byteArrayOf(0x04) ...@@ -86,7 +86,7 @@ private val byteArray_04 = byteArrayOf(0x04)
private val head1 = "302E301006072A8648CE3D020106052B8104001F031A00".chunkedHexToBytes() private val head1 = "302E301006072A8648CE3D020106052B8104001F031A00".chunkedHexToBytes()
private val head2 = "3046301006072A8648CE3D020106052B8104001F03320004".chunkedHexToBytes() private val head2 = "3046301006072A8648CE3D020106052B8104001F03320004".chunkedHexToBytes()
fun ByteArray.adjustToPublicKey(): ECDHPublicKey { internal fun ByteArray.adjustToPublicKey(): ECDHPublicKey {
val head = if (this.size < 30) head1 else head2 val head = if (this.size < 30) head1 else head2
return ECDH.constructPublicKey(head + this) return ECDH.constructPublicKey(head + this)
......
...@@ -23,7 +23,7 @@ import kotlin.random.Random ...@@ -23,7 +23,7 @@ import kotlin.random.Random
/** /**
* 解密错误 * 解密错误
*/ */
class DecryptionFailedException : Exception { internal class DecryptionFailedException : Exception {
constructor() : super() constructor() : super()
constructor(message: String?) : super(message) constructor(message: String?) : super(message)
} }
...@@ -34,7 +34,7 @@ class DecryptionFailedException : Exception { ...@@ -34,7 +34,7 @@ class DecryptionFailedException : Exception {
* **注意**: 此为 Mirai 内部 API. 它可能会在任何时刻被改变. * **注意**: 此为 Mirai 内部 API. 它可能会在任何时刻被改变.
*/ */
@MiraiInternalAPI @MiraiInternalAPI
object TEA { internal object TEA {
// TODO: 2020/2/28 使用 stream 式输入以避免缓存 // TODO: 2020/2/28 使用 stream 式输入以避免缓存
/** /**
......
...@@ -20,7 +20,7 @@ import net.mamoe.mirai.utils.MiraiInternalAPI ...@@ -20,7 +20,7 @@ import net.mamoe.mirai.utils.MiraiInternalAPI
import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
fun BytePacketBuilder.writeShortLVByteArrayLimitedLength(array: ByteArray, maxLength: Int) { internal fun BytePacketBuilder.writeShortLVByteArrayLimitedLength(array: ByteArray, maxLength: Int) {
if (array.size <= maxLength) { if (array.size <= maxLength) {
writeShort(array.size.toShort()) writeShort(array.size.toShort())
writeFully(array) writeFully(array)
...@@ -32,13 +32,13 @@ fun BytePacketBuilder.writeShortLVByteArrayLimitedLength(array: ByteArray, maxLe ...@@ -32,13 +32,13 @@ fun BytePacketBuilder.writeShortLVByteArrayLimitedLength(array: ByteArray, maxLe
} }
} }
inline fun BytePacketBuilder.writeShortLVByteArray(byteArray: ByteArray): Int { internal inline fun BytePacketBuilder.writeShortLVByteArray(byteArray: ByteArray): Int {
this.writeShort(byteArray.size.toShort()) this.writeShort(byteArray.size.toShort())
this.writeFully(byteArray) this.writeFully(byteArray)
return byteArray.size return byteArray.size
} }
inline fun BytePacketBuilder.writeIntLVPacket(tag: UByte? = null, lengthOffset: ((Long) -> Long) = {it}, builder: BytePacketBuilder.() -> Unit): Int = internal inline fun BytePacketBuilder.writeIntLVPacket(tag: UByte? = null, lengthOffset: ((Long) -> Long) = {it}, builder: BytePacketBuilder.() -> Unit): Int =
BytePacketBuilder().apply(builder).build().use { BytePacketBuilder().apply(builder).build().use {
if (tag != null) writeUByte(tag) if (tag != null) writeUByte(tag)
val length = lengthOffset.invoke(it.remaining).coerceAtMostOrFail(0xFFFFFFFFL) val length = lengthOffset.invoke(it.remaining).coerceAtMostOrFail(0xFFFFFFFFL)
...@@ -47,7 +47,7 @@ inline fun BytePacketBuilder.writeIntLVPacket(tag: UByte? = null, lengthOffset: ...@@ -47,7 +47,7 @@ inline fun BytePacketBuilder.writeIntLVPacket(tag: UByte? = null, lengthOffset:
return length.toInt() return length.toInt()
} }
inline fun BytePacketBuilder.writeShortLVPacket(tag: UByte? = null, lengthOffset: ((Long) -> Long) = {it}, builder: BytePacketBuilder.() -> Unit): Int = internal inline fun BytePacketBuilder.writeShortLVPacket(tag: UByte? = null, lengthOffset: ((Long) -> Long) = {it}, builder: BytePacketBuilder.() -> Unit): Int =
BytePacketBuilder().apply(builder).build().use { BytePacketBuilder().apply(builder).build().use {
if (tag != null) writeUByte(tag) if (tag != null) writeUByte(tag)
val length = lengthOffset.invoke(it.remaining).coerceAtMostOrFail(0xFFFFFFFFL) val length = lengthOffset.invoke(it.remaining).coerceAtMostOrFail(0xFFFFFFFFL)
...@@ -56,18 +56,16 @@ inline fun BytePacketBuilder.writeShortLVPacket(tag: UByte? = null, lengthOffset ...@@ -56,18 +56,16 @@ inline fun BytePacketBuilder.writeShortLVPacket(tag: UByte? = null, lengthOffset
return length.toInt() return length.toInt()
} }
inline fun BytePacketBuilder.writeShortLVString(str: String) = writeShortLVByteArray(str.toByteArray()) internal inline fun BytePacketBuilder.writeShortLVString(str: String) = writeShortLVByteArray(str.toByteArray())
fun BytePacketBuilder.writeHex(uHex: String) { internal fun BytePacketBuilder.writeHex(uHex: String) {
uHex.split(" ").forEach { uHex.split(" ").forEach {
if (it.isNotBlank()) { if (it.isNotBlank()) {
writeUByte(it.toUByte(16)) writeUByte(it.toUByte(16))
} }
} }
} }
/**
* 会使用 [ByteArrayPool] 缓存
*/
@OptIn(MiraiInternalAPI::class) @OptIn(MiraiInternalAPI::class)
inline fun BytePacketBuilder.encryptAndWrite(key: ByteArray, encoder: BytePacketBuilder.() -> Unit) = internal inline fun BytePacketBuilder.encryptAndWrite(key: ByteArray, encoder: BytePacketBuilder.() -> Unit) =
TEA.encrypt(BytePacketBuilder().apply(encoder).build(), key) { decrypted -> writeFully(decrypted) } TEA.encrypt(BytePacketBuilder().apply(encoder).build(), key) { decrypted -> writeFully(decrypted) }
\ No newline at end of file
...@@ -32,10 +32,10 @@ internal actual class ECDHKeyPairImpl( ...@@ -32,10 +32,10 @@ internal actual class ECDHKeyPairImpl(
} }
@Suppress("FunctionName") @Suppress("FunctionName")
actual fun ECDH() = internal actual fun ECDH() =
ECDH(ECDH.generateKeyPair()) ECDH(ECDH.generateKeyPair())
actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) { internal actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) {
actual companion object { actual companion object {
actual val isECDHAvailable: Boolean actual val isECDHAvailable: Boolean
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment