mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 02:20:14 +08:00
Fix friendlist
This commit is contained in:
parent
bfcd265016
commit
0c6526afb8
@ -29,6 +29,7 @@ import net.mamoe.mirai.utils.io.*
|
|||||||
import net.mamoe.mirai.utils.unsafeWeakRef
|
import net.mamoe.mirai.utils.unsafeWeakRef
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.EmptyCoroutineContext
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
|
import kotlin.jvm.Volatile
|
||||||
|
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
@UseExperimental(MiraiInternalAPI::class)
|
@UseExperimental(MiraiInternalAPI::class)
|
||||||
@ -123,7 +124,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
|||||||
val data = FriendList.GetFriendGroupList(
|
val data = FriendList.GetFriendGroupList(
|
||||||
bot.client,
|
bot.client,
|
||||||
currentFriendCount,
|
currentFriendCount,
|
||||||
20,
|
150,
|
||||||
0,
|
0,
|
||||||
0
|
0
|
||||||
).sendAndExpect<FriendList.GetFriendGroupList.Response>(timeoutMillis = 1000)
|
).sendAndExpect<FriendList.GetFriendGroupList.Response>(timeoutMillis = 1000)
|
||||||
@ -161,6 +162,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
|||||||
/**
|
/**
|
||||||
* 缓存超时处理的 [Job]. 超时后将清空缓存, 以免阻碍后续包的处理
|
* 缓存超时处理的 [Job]. 超时后将清空缓存, 以免阻碍后续包的处理
|
||||||
*/
|
*/
|
||||||
|
@Volatile
|
||||||
private var cachedPacketTimeoutJob: Job? = null
|
private var cachedPacketTimeoutJob: Job? = null
|
||||||
/**
|
/**
|
||||||
* 缓存的包
|
* 缓存的包
|
||||||
@ -169,6 +171,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
|||||||
/**
|
/**
|
||||||
* 缓存的包还差多少长度
|
* 缓存的包还差多少长度
|
||||||
*/
|
*/
|
||||||
|
@Volatile
|
||||||
private var expectingRemainingLength: Long = 0
|
private var expectingRemainingLength: Long = 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -256,8 +259,11 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
|||||||
if (cache == null) {
|
if (cache == null) {
|
||||||
// 没有缓存
|
// 没有缓存
|
||||||
var length: Int = rawInput.readInt() - 4
|
var length: Int = rawInput.readInt() - 4
|
||||||
if (length < 0) {
|
if (length and 0xFFFF != length) {
|
||||||
|
cachedPacket.value = rawInput
|
||||||
|
expectingRemainingLength = length.toLong() and 0xFFFF
|
||||||
// 丢包了. 后半部分包提前到达
|
// 丢包了. 后半部分包提前到达
|
||||||
|
PacketLogger.error { "丢包了." }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (rawInput.remaining == length.toLong()) {
|
if (rawInput.remaining == length.toLong()) {
|
||||||
@ -267,7 +273,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 循环所有完整的包
|
// 循环所有完整的包
|
||||||
while (rawInput.remaining > length) {
|
while (rawInput.remaining >= length) {
|
||||||
parsePacketAsync(rawInput.readPacket(length))
|
parsePacketAsync(rawInput.readPacket(length))
|
||||||
|
|
||||||
length = rawInput.readInt() - 4
|
length = rawInput.readInt() - 4
|
||||||
@ -284,20 +290,27 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 有缓存
|
// 有缓存
|
||||||
|
val expectingLength = expectingRemainingLength
|
||||||
if (rawInput.remaining >= expectingRemainingLength) {
|
if (expectingLength and 0xFFFF != expectingLength) {
|
||||||
|
processPacket(buildPacket {
|
||||||
|
writePacket(rawInput)
|
||||||
|
writeInt(expectingLength.toInt())
|
||||||
|
writePacket(cache)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (rawInput.remaining >= expectingLength) {
|
||||||
// 剩余长度够, 连接上去, 处理这个包.
|
// 剩余长度够, 连接上去, 处理这个包.
|
||||||
parsePacketAsync(buildPacket {
|
parsePacketAsync(buildPacket {
|
||||||
writePacket(cache)
|
writePacket(cache)
|
||||||
writePacket(rawInput, expectingRemainingLength)
|
writePacket(rawInput, expectingLength)
|
||||||
})
|
})
|
||||||
cachedPacket.value = null // 缺少的长度已经给上了.
|
cachedPacket.value = null // 缺少的长度已经给上了.
|
||||||
|
cachedPacketTimeoutJob?.cancel()
|
||||||
|
|
||||||
if (rawInput.remaining != 0L) {
|
if (rawInput.remaining != 0L) {
|
||||||
return processPacket(rawInput) // 继续处理剩下内容
|
return processPacket(rawInput) // 继续处理剩下内容
|
||||||
} else {
|
} else {
|
||||||
// 处理好了.
|
// 处理好了.
|
||||||
cachedPacketTimeoutJob?.cancel()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -11,13 +11,15 @@ class SyncCookie(
|
|||||||
@SerialId(2) val time: Long, // 1580277992
|
@SerialId(2) val time: Long, // 1580277992
|
||||||
@SerialId(3) val unknown1: Long = Random.nextLong(),// 678328038
|
@SerialId(3) val unknown1: Long = Random.nextLong(),// 678328038
|
||||||
@SerialId(4) val unknown2: Long = Random.nextLong(), // 1687142153
|
@SerialId(4) val unknown2: Long = Random.nextLong(), // 1687142153
|
||||||
@SerialId(5) val const1: Long = Random.nextLong(), // 1458467940
|
@SerialId(5) val const1: Long = const1_, // 1458467940
|
||||||
@SerialId(11) val const2: Long = Random.nextLong(), // 2683038258
|
@SerialId(11) val const2: Long = const2_, // 2683038258
|
||||||
@SerialId(12) val unknown3: Long = 0x1d,
|
@SerialId(12) val unknown3: Long = 0x1d,
|
||||||
@SerialId(13) val lastSyncTime: Long? = null,
|
@SerialId(13) val lastSyncTime: Long? = null,
|
||||||
@SerialId(14) val unknown4: Long = 0
|
@SerialId(14) val unknown4: Long = 0
|
||||||
) : ProtoBuf
|
) : ProtoBuf
|
||||||
|
|
||||||
|
private val const1_: Long = Random.nextLong()
|
||||||
|
private val const2_: Long = Random.nextLong()
|
||||||
/*
|
/*
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@ -147,6 +147,7 @@ internal object KnownPacketFactories {
|
|||||||
// login
|
// login
|
||||||
val flag1 = readInt()
|
val flag1 = readInt()
|
||||||
|
|
||||||
|
PacketLogger.verbose("开始处理一个包")
|
||||||
PacketLogger.verbose("flag1(0A/0B) = ${flag1.toUByte().toUHexString()}")
|
PacketLogger.verbose("flag1(0A/0B) = ${flag1.toUByte().toUHexString()}")
|
||||||
// 00 00 05 30
|
// 00 00 05 30
|
||||||
// 00 00 00 0A // flag 1
|
// 00 00 00 0A // flag 1
|
||||||
@ -240,10 +241,13 @@ internal object KnownPacketFactories {
|
|||||||
val ssoSequenceId: Int
|
val ssoSequenceId: Int
|
||||||
val dataCompressed: Int
|
val dataCompressed: Int
|
||||||
// head
|
// head
|
||||||
input.readIoBuffer(input.readInt() - 4).withUse {
|
input.readPacket(input.readInt() - 4).withUse {
|
||||||
ssoSequenceId = readInt()
|
ssoSequenceId = readInt()
|
||||||
PacketLogger.verbose("sequenceId = $ssoSequenceId")
|
PacketLogger.verbose("sequenceId = $ssoSequenceId")
|
||||||
check(readInt() == 0)
|
val returnCode = readInt()
|
||||||
|
if (returnCode != 0) {
|
||||||
|
error("returnCode = $returnCode")
|
||||||
|
}
|
||||||
val extraData = readBytes(readInt() - 4)
|
val extraData = readBytes(readInt() - 4)
|
||||||
PacketLogger.verbose("(sso/inner)extraData = ${extraData.toUHexString()}")
|
PacketLogger.verbose("(sso/inner)extraData = ${extraData.toUHexString()}")
|
||||||
|
|
||||||
@ -280,7 +284,7 @@ internal object KnownPacketFactories {
|
|||||||
ssoSequenceId: Int,
|
ssoSequenceId: Int,
|
||||||
consumer: PacketConsumer<T>
|
consumer: PacketConsumer<T>
|
||||||
) {
|
) {
|
||||||
readIoBuffer(readInt() - 4).withUse {
|
readPacket(readInt() - 4).withUse {
|
||||||
check(readByte().toInt() == 2)
|
check(readByte().toInt() == 2)
|
||||||
this.discardExact(2) // 27 + 2 + body.size
|
this.discardExact(2) // 27 + 2 + body.size
|
||||||
this.discardExact(2) // const, =8001
|
this.discardExact(2) // const, =8001
|
||||||
@ -292,30 +296,30 @@ internal object KnownPacketFactories {
|
|||||||
this.discardExact(1) // const = 0
|
this.discardExact(1) // const = 0
|
||||||
val packet = when (encryptionMethod) {
|
val packet = when (encryptionMethod) {
|
||||||
4 -> { // peer public key, ECDH
|
4 -> { // peer public key, ECDH
|
||||||
var data = this.decryptBy(bot.client.ecdh.keyPair.initialShareKey, this.readRemaining - 1)
|
var data = this.decryptBy(bot.client.ecdh.keyPair.initialShareKey, (this.remaining - 1).toInt())
|
||||||
|
|
||||||
val peerShareKey = bot.client.ecdh.calculateShareKeyByPeerPublicKey(readUShortLVByteArray().adjustToPublicKey())
|
val peerShareKey = bot.client.ecdh.calculateShareKeyByPeerPublicKey(readUShortLVByteArray().adjustToPublicKey())
|
||||||
data = data.decryptBy(peerShareKey)
|
data = data.decryptBy(peerShareKey)
|
||||||
|
|
||||||
packetFactory.decode(bot, data.toReadPacket())
|
packetFactory.decode(bot, data)
|
||||||
}
|
}
|
||||||
0 -> {
|
0 -> {
|
||||||
val data = if (bot.client.loginState == 0) {
|
val data = if (bot.client.loginState == 0) {
|
||||||
ByteArrayPool.useInstance { byteArrayBuffer ->
|
ByteArrayPool.useInstance { byteArrayBuffer ->
|
||||||
val size = this.readRemaining - 1
|
val size = (this.remaining - 1).toInt()
|
||||||
this.readFully(byteArrayBuffer, 0, size)
|
this.readFully(byteArrayBuffer, 0, size)
|
||||||
|
|
||||||
runCatching {
|
runCatching {
|
||||||
byteArrayBuffer.decryptBy(bot.client.ecdh.keyPair.initialShareKey, size)
|
byteArrayBuffer.decryptBy(bot.client.ecdh.keyPair.initialShareKey, size)
|
||||||
}.getOrElse {
|
}.getOrElse {
|
||||||
byteArrayBuffer.decryptBy(bot.client.randomKey, size)
|
byteArrayBuffer.decryptBy(bot.client.randomKey, size)
|
||||||
} // 这里实际上应该用 privateKey(另一个random出来的key)
|
}.toReadPacket() // 这里实际上应该用 privateKey(另一个random出来的key)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.decryptBy(bot.client.randomKey, 0, this.readRemaining - 1)
|
this.decryptBy(bot.client.randomKey, 0, (this.remaining - 1).toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
packetFactory.decode(bot, data.toReadPacket())
|
packetFactory.decode(bot, data)
|
||||||
|
|
||||||
}
|
}
|
||||||
else -> error("Illegal encryption method. expected 0 or 4, got $encryptionMethod")
|
else -> error("Illegal encryption method. expected 0 or 4, got $encryptionMethod")
|
||||||
@ -338,3 +342,15 @@ internal inline fun <I : IoBuffer, R> I.withUse(block: I.() -> R): R {
|
|||||||
this.release(IoBuffer.Pool)
|
this.release(IoBuffer.Pool)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UseExperimental(ExperimentalContracts::class)
|
||||||
|
internal inline fun <I : ByteReadPacket, R> I.withUse(block: I.() -> R): R {
|
||||||
|
contract {
|
||||||
|
callsInPlace(block, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
|
||||||
|
}
|
||||||
|
return try {
|
||||||
|
block(this)
|
||||||
|
} finally {
|
||||||
|
this.close()
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,10 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
|
|||||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgComm
|
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgComm
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc
|
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.data.proto.SyncCookie
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.*
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory
|
||||||
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
|
||||||
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
|
||||||
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
|
||||||
import net.mamoe.mirai.qqandroid.utils.toMessageChain
|
import net.mamoe.mirai.qqandroid.utils.toMessageChain
|
||||||
import net.mamoe.mirai.qqandroid.utils.toRichTextElems
|
import net.mamoe.mirai.qqandroid.utils.toRichTextElems
|
||||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||||
@ -229,7 +232,7 @@ internal class MessageSvc {
|
|||||||
),
|
),
|
||||||
msgSeq = client.atomicNextMessageSequenceId(),
|
msgSeq = client.atomicNextMessageSequenceId(),
|
||||||
//msgRand = Random.nextInt() and 0x7FFF,
|
//msgRand = Random.nextInt() and 0x7FFF,
|
||||||
syncCookie = client.c2cMessageSync.syncCookie?.takeIf { it.isNotEmpty() } ?: EMPTY_BYTE_ARRAY
|
syncCookie = SyncCookie(time = currentTimeSeconds).toByteArray(SyncCookie.serializer())
|
||||||
//SyncCookie(currentTimeSeconds, Random.nextLong().absoluteValue, Random.nextLong().absoluteValue).toByteArray(SyncCookie.serializer())
|
//SyncCookie(currentTimeSeconds, Random.nextLong().absoluteValue, Random.nextLong().absoluteValue).toByteArray(SyncCookie.serializer())
|
||||||
// msgVia = 1
|
// msgVia = 1
|
||||||
)
|
)
|
||||||
|
@ -16,7 +16,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
|
|||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
|
||||||
import net.mamoe.mirai.utils.io.discardExact
|
import net.mamoe.mirai.utils.io.debugIfFail
|
||||||
|
|
||||||
|
|
||||||
internal class FriendList {
|
internal class FriendList {
|
||||||
@ -120,8 +120,8 @@ internal class FriendList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||||
this.discardExact(4)
|
//this.discardExact(4)
|
||||||
val res = this.decodeUniPacket(GetFriendListResp.serializer())
|
val res = this.debugIfFail { this.decodeUniPacket(GetFriendListResp.serializer()) }
|
||||||
return Response(
|
return Response(
|
||||||
res.totoalFriendCount,
|
res.totoalFriendCount,
|
||||||
res.vecFriendInfo.orEmpty()
|
res.vecFriendInfo.orEmpty()
|
||||||
|
@ -4,7 +4,7 @@ import kotlinx.io.pool.DefaultPool
|
|||||||
import kotlinx.io.pool.ObjectPool
|
import kotlinx.io.pool.ObjectPool
|
||||||
|
|
||||||
internal const val DEFAULT_BYTE_ARRAY_POOL_SIZE = 256
|
internal const val DEFAULT_BYTE_ARRAY_POOL_SIZE = 256
|
||||||
internal const val DEFAULT_BYTE_ARRAY_SIZE = 8192
|
internal const val DEFAULT_BYTE_ARRAY_SIZE = 81920
|
||||||
|
|
||||||
val ByteArrayPool: ObjectPool<ByteArray> = ByteArrayPoolImpl
|
val ByteArrayPool: ObjectPool<ByteArray> = ByteArrayPoolImpl
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user