From 2f063987a99e079ddce8599c62aff1a545553b15 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 29 Mar 2020 14:28:32 +0800 Subject: [PATCH] Fix #129 --- .../mamoe/mirai/qqandroid/contact/QQImpl.kt | 27 +++++++++--- .../packet/chat/receive/MessageSvc.kt | 42 ++++++++++++------- 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/QQImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/QQImpl.kt index f82210552..41e34dc16 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/QQImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/QQImpl.kt @@ -12,6 +12,8 @@ package net.mamoe.mirai.qqandroid.contact +import kotlinx.atomicfu.AtomicInt +import kotlinx.atomicfu.atomic import kotlinx.io.core.Closeable import net.mamoe.mirai.LowLevelAPI import net.mamoe.mirai.contact.Contact @@ -37,6 +39,8 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.io.toUHexString +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract import kotlin.coroutines.CoroutineContext import kotlin.jvm.JvmSynthetic @@ -47,12 +51,23 @@ internal inline class FriendInfoImpl( override val uin: Long get() = jceFriendInfo.friendUin } +@OptIn(ExperimentalContracts::class) +internal fun QQ.checkIsQQImpl(): QQImpl { + contract { + returns() implies (this@checkIsQQImpl is QQImpl) + } + check(this is QQImpl) { "A QQ instance is not instance of QQImpl. Don't interlace two protocol implementations together!" } + return this +} + internal class QQImpl( bot: QQAndroidBot, override val coroutineContext: CoroutineContext, override val id: Long, private val friendInfo: FriendInfo ) : QQ() { + var lastMessageSequence: AtomicInt = atomic(-1) + override val bot: QQAndroidBot by bot.unsafeWeakRef() override val nick: String get() = friendInfo.nick @@ -68,12 +83,12 @@ internal class QQImpl( bot.network.run { check( MessageSvc.PbSendMsg.ToFriend( - bot.client, - id, - event.message - ) { - source = it - } + bot.client, + id, + event.message + ) { + source = it + } .sendAndExpect() is MessageSvc.PbSendMsg.Response.SUCCESS ) { "send message failed" } } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt index ebaa96325..d4624d95a 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt @@ -11,6 +11,7 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive +import kotlinx.atomicfu.loop import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.* import kotlinx.io.core.ByteReadPacket @@ -19,16 +20,15 @@ import net.mamoe.mirai.LowLevelAPI import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.MemberPermission import net.mamoe.mirai.data.MemberInfo -import net.mamoe.mirai.qqandroid.network.MultiPacketByIterable -import net.mamoe.mirai.qqandroid.network.Packet import net.mamoe.mirai.event.events.BotJoinGroupEvent import net.mamoe.mirai.event.events.BotOfflineEvent import net.mamoe.mirai.event.events.MemberJoinEvent import net.mamoe.mirai.getFriendOrNull import net.mamoe.mirai.message.FriendMessage import net.mamoe.mirai.message.data.MessageChain -import net.mamoe.mirai.qqandroid.contact.GroupImpl import net.mamoe.mirai.qqandroid.QQAndroidBot +import net.mamoe.mirai.qqandroid.contact.GroupImpl +import net.mamoe.mirai.qqandroid.contact.checkIsQQImpl import net.mamoe.mirai.qqandroid.io.serialization.decodeUniPacket import net.mamoe.mirai.qqandroid.io.serialization.readProtoBuf import net.mamoe.mirai.qqandroid.io.serialization.toByteArray @@ -37,6 +37,8 @@ import net.mamoe.mirai.qqandroid.message.MessageSourceFromSendFriend import net.mamoe.mirai.qqandroid.message.MessageSourceFromSendGroup import net.mamoe.mirai.qqandroid.message.toMessageChain import net.mamoe.mirai.qqandroid.message.toRichTextElems +import net.mamoe.mirai.qqandroid.network.MultiPacketByIterable +import net.mamoe.mirai.qqandroid.network.Packet import net.mamoe.mirai.qqandroid.network.QQAndroidClient import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPushForceOffline import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPushNotify @@ -195,9 +197,8 @@ internal class MessageSvc { bot.groups.delegate.addLast(newGroup) return@mapNotNull BotJoinGroupEvent(newGroup) } else { - if (group == null) { - return@mapNotNull null - } + group ?: return@mapNotNull null + if (group.members.contains(msg.msgHead.authUin)) { return@mapNotNull null } @@ -207,21 +208,30 @@ internal class MessageSvc { override val specialTitle: String get() = "" override val muteTimestamp: Int get() = 0 override val uin: Long get() = msg.msgHead.authUin - override val nick: String - get() = msg.msgHead.authNick.takeIf { it.isNotEmpty() } - ?: msg.msgHead.fromNick + override val nick: String = msg.msgHead.authNick.takeIf { it.isNotEmpty() } + ?: msg.msgHead.fromNick }).also { group.members.delegate.addLast(it) }) } } 166 -> { val friend = bot.getFriendOrNull(msg.msgHead.fromUin) ?: return@mapNotNull null - return@mapNotNull when { - msg.msgHead.fromUin == bot.uin -> null - !bot.firstLoginSucceed -> null - else -> FriendMessage( - friend, - msg.toMessageChain() - ) + friend.checkIsQQImpl() + + if (msg.msgHead.fromUin == bot.uin || !bot.firstLoginSucceed) { + return@mapNotNull null + } + + friend.lastMessageSequence.loop { instant -> + if (msg.msgHead.msgSeq > instant) { + println("bigger") + if (friend.lastMessageSequence.compareAndSet(instant, msg.msgHead.msgSeq)) { + println("set ok") + return@mapNotNull FriendMessage( + friend, + msg.toMessageChain() + ) + } + } else return@mapNotNull null } } else -> return@mapNotNull null