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 9ab628bf1..3ce38b2f3 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 @@ -411,7 +411,9 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo logger.info { "Syncing friend message history..." } withTimeoutOrNull(30000) { launch(CoroutineName("Syncing friend message history")) { syncFromEvent { Unit } } - MessageSvcPbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect() + // 别问我为什么要发两个 我也不知道 反正它能用 + MessageSvcPbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds, null,firstSync = true).sendAndExpect() + MessageSvcPbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds, null,firstSync = true).sendAndExpect() } ?: error("timeout syncing friend message history") logger.info { "Syncing friend message history: Success" } } 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 cbe61edef..bb2224a66 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 @@ -11,6 +11,7 @@ package net.mamoe.mirai.qqandroid.network +import kotlinx.atomicfu.AtomicBoolean import kotlinx.atomicfu.AtomicInt import kotlinx.atomicfu.atomic 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.TEA import net.mamoe.mirai.utils.* +import kotlin.jvm.Volatile import kotlin.random.Random internal val DeviceInfo.guid: ByteArray get() = generateGuid(androidId, macAddress) @@ -204,6 +206,9 @@ internal open class QQAndroidClient( val protocolVersion: Short = 8001 class C2cMessageSyncData { + val firstNotify: AtomicBoolean = atomic(true) + + @Volatile var syncCookie: ByteArray? = null var pubAccountCookie = EMPTY_BYTE_ARRAY var msgCtrlBuf: ByteArray = EMPTY_BYTE_ARRAY diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/PushNotifyPack.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/PushNotifyPack.kt index 787afe458..dec460165 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/PushNotifyPack.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/PushNotifyPack.kt @@ -33,7 +33,7 @@ internal class RequestPushNotify( @JceId(11) @JvmField val serverBuf: ByteArray?, @JceId(12) @JvmField val pingFlag: Long?, @JceId(13) @JvmField val svrip: Int? -) : JceStruct, Packet, Packet.NoLog +) : JceStruct, Packet @Serializable internal class MsgInfo( diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/SyncCookie.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/SyncCookie.kt index 24c032e86..8526ebfc5 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/SyncCookie.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/SyncCookie.kt @@ -16,6 +16,9 @@ import kotlin.jvm.JvmField import kotlin.math.absoluteValue import kotlin.random.Random + +// COMMENTED ON 2020/7/25 + @Serializable internal class SyncCookie( @ProtoId(1) @JvmField val time1: Long? = null, // 1580277992 @@ -31,6 +34,8 @@ internal class SyncCookie( private val const1_: Long = Random.nextLong().absoluteValue private val const2_: Long = Random.nextLong().absoluteValue + + /* @Serializable diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.PbGetMsg.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.PbGetMsg.kt index 5771b393b..dcb4cd326 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.PbGetMsg.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.PbGetMsg.kt @@ -37,7 +37,6 @@ import net.mamoe.mirai.qqandroid.network.Packet 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.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.OutgoingPacketFactory 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.list.FriendList 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.read import net.mamoe.mirai.qqandroid.utils.toInt @@ -59,15 +57,21 @@ import net.mamoe.mirai.utils.warning * 获取好友消息和消息记录 */ internal object MessageSvcPbGetMsg : OutgoingPacketFactory("MessageSvc.PbGetMsg") { + private var firstSyncPackets = 0 // 启动时候仅将所有好友信息设为已读的包 @Suppress("SpellCheckingInspection") operator fun invoke( client: QQAndroidClient, 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( client ) { //println("syncCookie=${client.c2cMessageSync.syncCookie?.toUHexString()}") + if (firstSync) { + firstSyncPackets++ + } writeProtoBuf( MsgSvc.PbGetMsgReq.serializer(), MsgSvc.PbGetMsgReq( @@ -80,8 +84,8 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory) : Response(MsgSvc.SyncFlag.STOP, delegate), Event, + open class GetMsgSuccess(delegate: List, syncCookie: ByteArray?) : Response( + MsgSvc.SyncFlag.STOP, delegate, + syncCookie + ), Event, Packet.NoLog { override fun toString(): String = "MessageSvcPbGetMsg.GetMsgSuccess(messages=))" } @@ -97,7 +104,11 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory) : + open class Response( + internal val syncFlagFromServer: MsgSvc.SyncFlag, + delegate: List, + val syncCookie: ByteArray? + ) : AbstractEvent(), MultiPacket, Iterable by (delegate) { @@ -106,7 +117,7 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory))" } - object EmptyResponse : GetMsgSuccess(emptyList()) + object EmptyResponse : GetMsgSuccess(emptyList(), null) private fun MsgComm.Msg.getNewMemberInfo(): MemberInfo { return object : MemberInfo { @@ -268,7 +279,9 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory { - + if (firstSyncPackets != 0) { + return@mapNotNull null + } if (msg.msgHead.fromUin == bot.id) { loop@ while (true) { val instance = bot.client.getFriendSeq() @@ -361,27 +374,41 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory = messages.toList() 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) { when (packet.syncFlagFromServer) { - MsgSvc.SyncFlag.STOP -> return + MsgSvc.SyncFlag.STOP -> { + if (firstSyncPackets != 0) { + firstSyncPackets-- + } + } + MsgSvc.SyncFlag.START -> { network.run { - MessageSvcPbGetMsg(client, MsgSvc.SyncFlag.CONTINUE, currentTimeSeconds).sendAndExpect() + MessageSvcPbGetMsg( + client, + MsgSvc.SyncFlag.CONTINUE, + currentTimeSeconds, + packet.syncCookie + ).sendAndExpect() } return } MsgSvc.SyncFlag.CONTINUE -> { network.run { - MessageSvcPbGetMsg(client, MsgSvc.SyncFlag.CONTINUE, currentTimeSeconds).sendAndExpect() + MessageSvcPbGetMsg( + client, + MsgSvc.SyncFlag.CONTINUE, + currentTimeSeconds, + packet.syncCookie + ).sendAndExpect() } return } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.PbSendMsg.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.PbSendMsg.kt index 6e3a8610c..46723fb55 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.PbSendMsg.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.PbSendMsg.kt @@ -25,14 +25,15 @@ import net.mamoe.mirai.qqandroid.message.MessageSourceToTempImpl import net.mamoe.mirai.qqandroid.message.toRichTextElems import net.mamoe.mirai.qqandroid.network.Packet 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.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.hexToBytes 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.utils.currentTimeSeconds import kotlin.contracts.InvocationKind @@ -79,7 +80,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory( override suspend fun QQAndroidBot.handle(packet: RequestPushNotify, sequenceId: Int): OutgoingPacket? { - network.run { - return MessageSvcPbGetMsg( - client, - MsgSvc.SyncFlag.START, - packet.stMsgInfo?.uMsgTime ?: currentTimeSeconds - ) + client.c2cMessageSync.firstNotify.loop { firstNotify -> + network.run { + return MessageSvcPbGetMsg( + client, + MsgSvc.SyncFlag.START, + packet.stMsgInfo?.uMsgTime ?: currentTimeSeconds, + if (firstNotify) { + if (!client.c2cMessageSync.firstNotify.compareAndSet(firstNotify, false)) { + return@loop + } + null + } else packet.vNotifyCookie + ) + } } } } \ No newline at end of file