This commit is contained in:
mzdluo123 2020-07-25 19:37:39 +08:00
parent 0a7ebffd95
commit 2ec431489e
No known key found for this signature in database
GPG Key ID: 9F7BC2C154107A1D
7 changed files with 77 additions and 28 deletions

View File

@ -411,7 +411,9 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
logger.info { "Syncing friend message history..." } logger.info { "Syncing friend message history..." }
withTimeoutOrNull(30000) { withTimeoutOrNull(30000) {
launch(CoroutineName("Syncing friend message history")) { syncFromEvent<MessageSvcPbGetMsg.GetMsgSuccess, Unit> { Unit } } launch(CoroutineName("Syncing friend message history")) { syncFromEvent<MessageSvcPbGetMsg.GetMsgSuccess, Unit> { Unit } }
MessageSvcPbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect<Packet>() // 别问我为什么要发两个 我也不知道 反正它能用
MessageSvcPbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds, null,firstSync = true).sendAndExpect<Packet>()
MessageSvcPbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds, null,firstSync = true).sendAndExpect<Packet>()
} ?: error("timeout syncing friend message history") } ?: error("timeout syncing friend message history")
logger.info { "Syncing friend message history: Success" } logger.info { "Syncing friend message history: Success" }
} }

View File

@ -11,6 +11,7 @@
package net.mamoe.mirai.qqandroid.network package net.mamoe.mirai.qqandroid.network
import kotlinx.atomicfu.AtomicBoolean
import kotlinx.atomicfu.AtomicInt import kotlinx.atomicfu.AtomicInt
import kotlinx.atomicfu.atomic import kotlinx.atomicfu.atomic
import kotlinx.io.core.* import kotlinx.io.core.*
@ -27,6 +28,7 @@ import net.mamoe.mirai.qqandroid.utils.*
import net.mamoe.mirai.qqandroid.utils.cryptor.ECDH import net.mamoe.mirai.qqandroid.utils.cryptor.ECDH
import net.mamoe.mirai.qqandroid.utils.cryptor.TEA import net.mamoe.mirai.qqandroid.utils.cryptor.TEA
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
import kotlin.jvm.Volatile
import kotlin.random.Random import kotlin.random.Random
internal val DeviceInfo.guid: ByteArray get() = generateGuid(androidId, macAddress) internal val DeviceInfo.guid: ByteArray get() = generateGuid(androidId, macAddress)
@ -204,6 +206,9 @@ internal open class QQAndroidClient(
val protocolVersion: Short = 8001 val protocolVersion: Short = 8001
class C2cMessageSyncData { class C2cMessageSyncData {
val firstNotify: AtomicBoolean = atomic(true)
@Volatile
var syncCookie: ByteArray? = null var syncCookie: ByteArray? = null
var pubAccountCookie = EMPTY_BYTE_ARRAY var pubAccountCookie = EMPTY_BYTE_ARRAY
var msgCtrlBuf: ByteArray = EMPTY_BYTE_ARRAY var msgCtrlBuf: ByteArray = EMPTY_BYTE_ARRAY

View File

@ -33,7 +33,7 @@ internal class RequestPushNotify(
@JceId(11) @JvmField val serverBuf: ByteArray?, @JceId(11) @JvmField val serverBuf: ByteArray?,
@JceId(12) @JvmField val pingFlag: Long?, @JceId(12) @JvmField val pingFlag: Long?,
@JceId(13) @JvmField val svrip: Int? @JceId(13) @JvmField val svrip: Int?
) : JceStruct, Packet, Packet.NoLog ) : JceStruct, Packet
@Serializable @Serializable
internal class MsgInfo( internal class MsgInfo(

View File

@ -16,6 +16,9 @@ import kotlin.jvm.JvmField
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
import kotlin.random.Random import kotlin.random.Random
// COMMENTED ON 2020/7/25
@Serializable @Serializable
internal class SyncCookie( internal class SyncCookie(
@ProtoId(1) @JvmField val time1: Long? = null, // 1580277992 @ProtoId(1) @JvmField val time1: Long? = null, // 1580277992
@ -31,6 +34,8 @@ internal class SyncCookie(
private val const1_: Long = Random.nextLong().absoluteValue private val const1_: Long = Random.nextLong().absoluteValue
private val const2_: Long = Random.nextLong().absoluteValue private val const2_: Long = Random.nextLong().absoluteValue
/* /*
@Serializable @Serializable

View File

@ -37,7 +37,6 @@ import net.mamoe.mirai.qqandroid.network.Packet
import net.mamoe.mirai.qqandroid.network.QQAndroidClient import net.mamoe.mirai.qqandroid.network.QQAndroidClient
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.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
@ -45,7 +44,6 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.GroupInfoImpl
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.NewContact import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.NewContact
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList
import net.mamoe.mirai.qqandroid.utils.io.serialization.readProtoBuf import net.mamoe.mirai.qqandroid.utils.io.serialization.readProtoBuf
import net.mamoe.mirai.qqandroid.utils.io.serialization.toByteArray
import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf
import net.mamoe.mirai.qqandroid.utils.read import net.mamoe.mirai.qqandroid.utils.read
import net.mamoe.mirai.qqandroid.utils.toInt import net.mamoe.mirai.qqandroid.utils.toInt
@ -59,15 +57,21 @@ import net.mamoe.mirai.utils.warning
* 获取好友消息和消息记录 * 获取好友消息和消息记录
*/ */
internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Response>("MessageSvc.PbGetMsg") { internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Response>("MessageSvc.PbGetMsg") {
private var firstSyncPackets = 0 // 启动时候仅将所有好友信息设为已读的包
@Suppress("SpellCheckingInspection") @Suppress("SpellCheckingInspection")
operator fun invoke( operator fun invoke(
client: QQAndroidClient, client: QQAndroidClient,
syncFlag: MsgSvc.SyncFlag = MsgSvc.SyncFlag.START, syncFlag: MsgSvc.SyncFlag = MsgSvc.SyncFlag.START,
msgTime: Long //PbPushMsg.msg.msgHead.msgTime msgTime: Long, //PbPushMsg.msg.msgHead.msgTime
syncCookie: ByteArray?,
firstSync: Boolean = false
): OutgoingPacket = buildOutgoingUniPacket( ): OutgoingPacket = buildOutgoingUniPacket(
client client
) { ) {
//println("syncCookie=${client.c2cMessageSync.syncCookie?.toUHexString()}") //println("syncCookie=${client.c2cMessageSync.syncCookie?.toUHexString()}")
if (firstSync) {
firstSyncPackets++
}
writeProtoBuf( writeProtoBuf(
MsgSvc.PbGetMsgReq.serializer(), MsgSvc.PbGetMsgReq.serializer(),
MsgSvc.PbGetMsgReq( MsgSvc.PbGetMsgReq(
@ -80,8 +84,8 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
whisperSessionId = 0, whisperSessionId = 0,
syncFlag = syncFlag, syncFlag = syncFlag,
// serverBuf = from.serverBuf ?: EMPTY_BYTE_ARRAY, // serverBuf = from.serverBuf ?: EMPTY_BYTE_ARRAY,
syncCookie = client.c2cMessageSync.syncCookie syncCookie = syncCookie ?: client.c2cMessageSync.syncCookie
?: SyncCookie(time = msgTime).toByteArray(SyncCookie.serializer())//.also { client.c2cMessageSync.syncCookie = it }, ?: byteArrayOf()//.also { client.c2cMessageSync.syncCookie = it },
// syncFlag = client.c2cMessageSync.syncFlag, // syncFlag = client.c2cMessageSync.syncFlag,
//msgCtrlBuf = client.c2cMessageSync.msgCtrlBuf, //msgCtrlBuf = client.c2cMessageSync.msgCtrlBuf,
//pubaccountCookie = client.c2cMessageSync.pubAccountCookie //pubaccountCookie = client.c2cMessageSync.pubAccountCookie
@ -89,7 +93,10 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
) )
} }
open class GetMsgSuccess(delegate: List<Packet>) : Response(MsgSvc.SyncFlag.STOP, delegate), Event, open class GetMsgSuccess(delegate: List<Packet>, syncCookie: ByteArray?) : Response(
MsgSvc.SyncFlag.STOP, delegate,
syncCookie
), Event,
Packet.NoLog { Packet.NoLog {
override fun toString(): String = "MessageSvcPbGetMsg.GetMsgSuccess(messages=<Iterable>))" override fun toString(): String = "MessageSvcPbGetMsg.GetMsgSuccess(messages=<Iterable>))"
} }
@ -97,7 +104,11 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
/** /**
* 不要直接 expect 这个 class. 它可能还没同步完成 * 不要直接 expect 这个 class. 它可能还没同步完成
*/ */
open class Response(internal val syncFlagFromServer: MsgSvc.SyncFlag, delegate: List<Packet>) : open class Response(
internal val syncFlagFromServer: MsgSvc.SyncFlag,
delegate: List<Packet>,
val syncCookie: ByteArray?
) :
AbstractEvent(), AbstractEvent(),
MultiPacket<Packet>, MultiPacket<Packet>,
Iterable<Packet> by (delegate) { Iterable<Packet> by (delegate) {
@ -106,7 +117,7 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
"MessageSvcPbGetMsg.Response(syncFlagFromServer=$syncFlagFromServer, messages=<Iterable>))" "MessageSvcPbGetMsg.Response(syncFlagFromServer=$syncFlagFromServer, messages=<Iterable>))"
} }
object EmptyResponse : GetMsgSuccess(emptyList()) object EmptyResponse : GetMsgSuccess(emptyList(), null)
private fun MsgComm.Msg.getNewMemberInfo(): MemberInfo { private fun MsgComm.Msg.getNewMemberInfo(): MemberInfo {
return object : MemberInfo { return object : MemberInfo {
@ -268,7 +279,9 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
*/ */
166 -> { 166 -> {
if (firstSyncPackets != 0) {
return@mapNotNull null
}
if (msg.msgHead.fromUin == bot.id) { if (msg.msgHead.fromUin == bot.id) {
loop@ while (true) { loop@ while (true) {
val instance = bot.client.getFriendSeq() val instance = bot.client.getFriendSeq()
@ -361,27 +374,41 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
} }
} }
} }
val list: List<Packet> = messages.toList() val list: List<Packet> = messages.toList()
if (resp.syncFlag == MsgSvc.SyncFlag.STOP) { if (resp.syncFlag == MsgSvc.SyncFlag.STOP) {
return GetMsgSuccess(list) return GetMsgSuccess(list, resp.syncCookie)
} }
return Response(resp.syncFlag, list) return Response(resp.syncFlag, list, resp.syncCookie)
} }
override suspend fun QQAndroidBot.handle(packet: Response) { override suspend fun QQAndroidBot.handle(packet: Response) {
when (packet.syncFlagFromServer) { when (packet.syncFlagFromServer) {
MsgSvc.SyncFlag.STOP -> return MsgSvc.SyncFlag.STOP -> {
if (firstSyncPackets != 0) {
firstSyncPackets--
}
}
MsgSvc.SyncFlag.START -> { MsgSvc.SyncFlag.START -> {
network.run { network.run {
MessageSvcPbGetMsg(client, MsgSvc.SyncFlag.CONTINUE, currentTimeSeconds).sendAndExpect<Packet>() MessageSvcPbGetMsg(
client,
MsgSvc.SyncFlag.CONTINUE,
currentTimeSeconds,
packet.syncCookie
).sendAndExpect<Packet>()
} }
return return
} }
MsgSvc.SyncFlag.CONTINUE -> { MsgSvc.SyncFlag.CONTINUE -> {
network.run { network.run {
MessageSvcPbGetMsg(client, MsgSvc.SyncFlag.CONTINUE, currentTimeSeconds).sendAndExpect<Packet>() MessageSvcPbGetMsg(
client,
MsgSvc.SyncFlag.CONTINUE,
currentTimeSeconds,
packet.syncCookie
).sendAndExpect<Packet>()
} }
return return
} }

View File

@ -25,14 +25,15 @@ import net.mamoe.mirai.qqandroid.message.MessageSourceToTempImpl
import net.mamoe.mirai.qqandroid.message.toRichTextElems import net.mamoe.mirai.qqandroid.message.toRichTextElems
import net.mamoe.mirai.qqandroid.network.Packet import net.mamoe.mirai.qqandroid.network.Packet
import net.mamoe.mirai.qqandroid.network.QQAndroidClient import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.* 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.MsgCtrl
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY 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.qqandroid.utils.hexToBytes
import net.mamoe.mirai.qqandroid.utils.io.serialization.readProtoBuf import net.mamoe.mirai.qqandroid.utils.io.serialization.readProtoBuf
import net.mamoe.mirai.qqandroid.utils.io.serialization.toByteArray
import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf
import net.mamoe.mirai.utils.currentTimeSeconds import net.mamoe.mirai.utils.currentTimeSeconds
import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind
@ -79,7 +80,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
), ),
msgSeq = source.sequenceId, msgSeq = source.sequenceId,
msgRand = source.internalId, msgRand = source.internalId,
syncCookie = SyncCookie(time = source.time.toLong()).toByteArray(SyncCookie.serializer()) syncCookie = client.c2cMessageSync.syncCookie ?: byteArrayOf()
// msgVia = 1 // msgVia = 1
) )
) )
@ -109,7 +110,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
), ),
msgSeq = source.sequenceId, msgSeq = source.sequenceId,
msgRand = source.internalId, msgRand = source.internalId,
syncCookie = SyncCookie(time = source.time.toLong()).toByteArray(SyncCookie.serializer()) syncCookie = client.c2cMessageSync.syncCookie ?: byteArrayOf()
) )
) )
} }

View File

@ -9,6 +9,7 @@
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
import kotlinx.atomicfu.loop
import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact import kotlinx.io.core.discardExact
import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.QQAndroidBot
@ -31,12 +32,20 @@ internal object MessageSvcPushNotify : IncomingPacketFactory<RequestPushNotify>(
override suspend fun QQAndroidBot.handle(packet: RequestPushNotify, sequenceId: Int): OutgoingPacket? { override suspend fun QQAndroidBot.handle(packet: RequestPushNotify, sequenceId: Int): OutgoingPacket? {
client.c2cMessageSync.firstNotify.loop { firstNotify ->
network.run { network.run {
return MessageSvcPbGetMsg( return MessageSvcPbGetMsg(
client, client,
MsgSvc.SyncFlag.START, MsgSvc.SyncFlag.START,
packet.stMsgInfo?.uMsgTime ?: currentTimeSeconds packet.stMsgInfo?.uMsgTime ?: currentTimeSeconds,
if (firstNotify) {
if (!client.c2cMessageSync.firstNotify.compareAndSet(firstNotify, false)) {
return@loop
}
null
} else packet.vNotifyCookie
) )
} }
} }
} }
}