mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-11 13:20:09 +08:00
try to fix #249
This commit is contained in:
parent
0a7ebffd95
commit
2ec431489e
@ -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" }
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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(
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user