Ver código fonte

[core] Fix quote replying; Fix message source time

Karlatemp 3 anos atrás
pai
commit
1169d7cf57

+ 1 - 1
mirai-core/src/commonMain/kotlin/message/data/MultiMsgUploader.kt

@@ -256,7 +256,7 @@ internal open class MultiMsgUploader(
                     fromNick = pm.msg.senderName,
                     msgSeq = pm.seq,
                     msgTime = pm.msg.time,
-                    msgUid = 0x01000000000000000L or pm.uid.toLongUnsigned(),
+                    msgUid = 0x0100000000000000L or pm.uid.toLongUnsigned(),
                     mutiltransHead = MsgComm.MutilTransHead(
                         status = 0,
                         msgId = 1,

+ 21 - 4
mirai-core/src/commonMain/kotlin/message/protocol/impl/GeneralMessageSenderProtocol.kt

@@ -27,7 +27,9 @@ import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelin
 import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.components
 import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessageSender
 import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
+import net.mamoe.mirai.internal.message.source.OutgoingMessageSourceInternal
 import net.mamoe.mirai.internal.message.source.createMessageReceipt
+import net.mamoe.mirai.internal.network.components.ClockHolder.Companion.clock
 import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
 import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
 import net.mamoe.mirai.message.data.AtAll
@@ -69,8 +71,15 @@ internal class GeneralMessageSenderProtocol : MessageProtocol(PRIORITY_GENERAL_S
                 fragmented = step == SendMessageStep.FRAGMENTED || currentMessageChain.contains(ForceAsFragmentedMessage)
             ) { source = it }
 
-            if (sendAllPackets(bot, step, contact, packets)) {
+            var finalTime = bot.clock.server.currentTimeSeconds().toInt()
+            val sendPacketOk = sendAllPackets(bot, step, contact, packets) { idx, rsp ->
+                if (rsp is MessageSvcPbSendMsg.Response.SUCCESS) {
+                    finalTime = rsp.sendTime
+                }
+            }
+            if (sendPacketOk) {
                 val sourceAwait = source?.await() ?: error("Internal error: source is not initialized")
+                (sourceAwait as OutgoingMessageSourceInternal).time = finalTime
                 sourceAwait.tryEnsureSequenceIdAvailable()
                 collect(sourceAwait.createMessageReceipt(contact, true))
             }
@@ -83,14 +92,19 @@ internal class GeneralMessageSenderProtocol : MessageProtocol(PRIORITY_GENERAL_S
             bot: AbstractBot,
             step: SendMessageStep,
             contact: Contact,
-            packets: List<OutgoingPacket>
+            packets: List<OutgoingPacket>,
+            packetResponseConsumer: (Int, MessageSvcPbSendMsg.Response) -> Unit = { _, _ -> },
         ): Boolean {
             if (!step.allowMultiplePackets && packets.size != 1) {
                 throw IllegalStateException("Internal error: step $step doesn't allow multiple packets while found ${packets.size} ones.")
             }
 
-            packets.forEach { packet ->
-                if (!sendSinglePacket(bot, packet, step, contact)) return@sendAllPackets false
+            packets.forEachIndexed { index, packet ->
+                if (!sendSinglePacket(
+                        bot, packet, step, contact,
+                        index, packetResponseConsumer
+                    )
+                ) return@sendAllPackets false
             }
 
             return true
@@ -101,12 +115,15 @@ internal class GeneralMessageSenderProtocol : MessageProtocol(PRIORITY_GENERAL_S
             packet: OutgoingPacket,
             step: SendMessageStep,
             contact: Contact,
+            index: Int,
+            packetResponseConsumer: (Int, MessageSvcPbSendMsg.Response) -> Unit,
         ): Boolean {
             val originalMessage = attributes[ORIGINAL_MESSAGE]
             val protocolStrategy = components[MessageProtocolStrategy]
             val finalMessage = currentMessageChain
 
             val resp = protocolStrategy.sendPacket(bot, packet) as MessageSvcPbSendMsg.Response
+            packetResponseConsumer(index, resp)
             if (resp is MessageSvcPbSendMsg.Response.MessageTooLarge) {
                 logger.info { "STEP $step: message too large." }
                 val next = step.nextStepOrNull()

+ 5 - 0
mirai-core/src/commonMain/kotlin/message/source/MessageSourceInternal.kt

@@ -61,6 +61,11 @@ internal interface OutgoingMessageSourceInternal : MessageSourceInternal {
      * This 'overrides' [MessageSource.originalMessage].
      */
     var originalMessage: MessageChain
+
+    /**
+     * This for patch outgoing message source to real time (from server)
+     */
+    var time: Int
 }
 
 /**

+ 8 - 5
mirai-core/src/commonMain/kotlin/message/source/incomingSourceImpl.kt

@@ -48,7 +48,7 @@ internal class OnlineMessageSourceFromFriendImpl(
 ) : OnlineMessageSource.Incoming.FromFriend(), IncomingMessageSourceInternal {
     object Serializer : KSerializer<MessageSource> by MessageSourceSerializerImpl("OnlineMessageSourceFromFriend")
 
-    override val sequenceIds: IntArray = msg.mapToIntArray { it.msgHead.msgSeq }
+    override val sequenceIds: IntArray = msg.mapToIntArray { it.msgHead.msgSeq.and(0xFFFF) }
 
     private val _isRecalledOrPlanned = atomic(false)
 
@@ -119,10 +119,12 @@ internal class OnlineMessageSourceFromStrangerImpl(
 
 private fun List<MsgComm.Msg>.toJceDataPrivate(ids: IntArray): ImMsgBody.SourceMsg {
     val elements = flatMap { it.msgBody.richText.elems }.toMutableList().also {
-        if (it.last().elemFlags2 == null) it.add(ImMsgBody.Elem(elemFlags2 = ImMsgBody.ElemFlags2()))
+        if (it.lastOrNull()?.elemFlags2 == null) it.add(ImMsgBody.Elem(elemFlags2 = ImMsgBody.ElemFlags2()))
     }
 
-    first().msgHead.run {
+    val firstMsgMsgHead = first().msgHead
+
+    firstMsgMsgHead.run {
         return ImMsgBody.SourceMsg(
             origSeqs = mapToIntArray { it.msgHead.msgSeq },
             senderUin = fromUin,
@@ -132,7 +134,7 @@ private fun List<MsgComm.Msg>.toJceDataPrivate(ids: IntArray): ImMsgBody.SourceM
             type = 0,
             time = msgTime,
             pbReserve = SourceMsg.ResvAttr(
-                origUids = ids.map { it.toLong() and 0xFFFF_FFFF }
+                origUids = mutableListOf(firstMsgMsgHead.msgUid)
             ).toByteArray(SourceMsg.ResvAttr.serializer()),
             srcMsg = MsgComm.Msg(
                 msgHead = MsgComm.MsgHead(
@@ -142,7 +144,8 @@ private fun List<MsgComm.Msg>.toJceDataPrivate(ids: IntArray): ImMsgBody.SourceM
                     c2cCmd = c2cCmd,
                     msgSeq = msgSeq,
                     msgTime = msgTime,
-                    msgUid = ids.single().toLong() and 0xFFFF_FFFF, // ok
+                    msgUid = firstMsgMsgHead.msgUid, // ok
+//                    msgUid = ids.single().toLong() and 0xFFFF_FFFF, // ok
                     // groupInfo = MsgComm.GroupInfo(groupCode = msgHead.groupInfo.groupCode),
                     isSrcMsg = true
                 ),

+ 3 - 16
mirai-core/src/commonMain/kotlin/message/source/offlineSourceImpl.kt

@@ -16,7 +16,6 @@ import kotlinx.serialization.Serializable
 import kotlinx.serialization.Transient
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.internal.message.MessageSourceSerializerImpl
-import net.mamoe.mirai.internal.message.protocol.MessageProtocolFacade
 import net.mamoe.mirai.internal.message.toMessageChainNoSource
 import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
 import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
@@ -27,7 +26,6 @@ import net.mamoe.mirai.message.data.MessageSource
 import net.mamoe.mirai.message.data.MessageSourceKind
 import net.mamoe.mirai.message.data.OfflineMessageSource
 import net.mamoe.mirai.message.data.visitor.MessageVisitor
-import net.mamoe.mirai.utils.EMPTY_BYTE_ARRAY
 import net.mamoe.mirai.utils.isSameType
 import net.mamoe.mirai.utils.mapToIntArray
 
@@ -66,20 +64,9 @@ internal class OfflineMessageSourceImplData(
     override fun setRecalled(): Boolean = _isRecalledOrPlanned.compareAndSet(expect = false, update = true)
 
     override fun toJceData(): ImMsgBody.SourceMsg {
-        return jceData ?: ImMsgBody.SourceMsg(
-            origSeqs = sequenceIds,
-            senderUin = fromId,
-            toUin = 0,
-            flag = 1,
-            elems = originElems ?: MessageProtocolFacade.encode(
-                originalMessage, messageTarget = null, //forGroup = kind == MessageSourceKind.GROUP,
-                withGeneralFlags = false
-            ),
-            type = 0,
-            time = time,
-            pbReserve = EMPTY_BYTE_ARRAY,
-            srcMsg = EMPTY_BYTE_ARRAY
-        ).also { jceData = it }
+        jceData?.let { return it }
+
+        return toJceDataImpl(null).also { jceData = it }
     }
 
     override fun equals(other: Any?): Boolean {

+ 9 - 8
mirai-core/src/commonMain/kotlin/message/source/outgoingSourceImpl.kt

@@ -38,14 +38,15 @@ import net.mamoe.mirai.utils.loadService
 import net.mamoe.mirai.utils.toLongUnsigned
 
 
-private fun <T> T.toJceDataImpl(subject: ContactOrBot?): ImMsgBody.SourceMsg
+internal fun <T> T.toJceDataImpl(subject: ContactOrBot?): ImMsgBody.SourceMsg
         where T : MessageSourceInternal, T : MessageSource {
 
-    val elements = MessageProtocolFacade.encode(originalMessage, subject, withGeneralFlags = true)
+    val elements = MessageProtocolFacade.encode(originalMessage, subject, withGeneralFlags = false)
 
     val pdReserve = SourceMsg.ResvAttr(
-        origUids = sequenceIds.zip(internalIds)
-            .map { (seq, internal) -> seq.toLong().shl(32) or internal.toLongUnsigned() }
+        origUids = internalIds.map { 0x100000000000000 or it.toLongUnsigned() }
+//        origUids = sequenceIds.zip(internalIds)
+//            .map { (seq, internal) -> seq.toLong().shl(32) or internal.toLongUnsigned() }
     )
 
     return ImMsgBody.SourceMsg(
@@ -85,7 +86,7 @@ private fun <T> T.toJceDataImpl(subject: ContactOrBot?): ImMsgBody.SourceMsg
 internal class OnlineMessageSourceToFriendImpl(
     override val sequenceIds: IntArray,
     override val internalIds: IntArray,
-    override val time: Int,
+    override var time: Int,
     override var originalMessage: MessageChain,
     override val sender: Bot,
     override val target: Friend,
@@ -119,7 +120,7 @@ internal class OnlineMessageSourceToFriendImpl(
 internal class OnlineMessageSourceToStrangerImpl(
     override val sequenceIds: IntArray,
     override val internalIds: IntArray,
-    override val time: Int,
+    override var time: Int,
     override var originalMessage: MessageChain,
     override val sender: Bot,
     override val target: Stranger,
@@ -158,7 +159,7 @@ internal class OnlineMessageSourceToStrangerImpl(
 internal class OnlineMessageSourceToTempImpl(
     override val sequenceIds: IntArray,
     override val internalIds: IntArray,
-    override val time: Int,
+    override var time: Int,
     override var originalMessage: MessageChain,
     override val sender: Bot,
     override val target: Member,
@@ -197,7 +198,7 @@ internal class OnlineMessageSourceToTempImpl(
 internal class OnlineMessageSourceToGroupImpl(
     coroutineScope: CoroutineScope,
     override val internalIds: IntArray, // aka random
-    override val time: Int,
+    override var time: Int,
     override var originalMessage: MessageChain,
     override val sender: Bot,
     override val target: Group,

+ 5 - 3
mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PbSendMsg.kt

@@ -49,8 +49,10 @@ import kotlin.random.Random
 
 internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.Response>("MessageSvc.PbSendMsg") {
     sealed class Response : Packet {
-        object SUCCESS : Response() {
-            override fun toString(): String = "MessageSvcPbSendMsg.Response.SUCCESS"
+        class SUCCESS(
+            val sendTime: Int,
+        ) : Response() {
+            override fun toString(): String = "MessageSvcPbSendMsg.Response.SUCCESS(time=$sendTime)"
         }
 
         object MessageTooLarge : Response() {
@@ -486,7 +488,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
     override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
         val response = readProtoBuf(MsgSvc.PbSendMsgResp.serializer())
         return when (response.result) {
-            0 -> Response.SUCCESS
+            0 -> Response.SUCCESS(response.sendTime)
             10 -> Response.MessageTooLarge
             32 -> Response.ServiceUnavailable
             else -> Response.Failed(

+ 1 - 1
mirai-core/src/commonTest/kotlin/message/protocol/impl/AbstractMessageProtocolTest.kt

@@ -252,7 +252,7 @@ internal abstract class AbstractMessageProtocolTest : AbstractMockNetworkHandler
     open inner class TestMessageProtocolStrategy : MessageProtocolStrategy<AbstractContact> {
         override suspend fun sendPacket(bot: AbstractBot, packet: OutgoingPacket): Packet {
             assertEquals(0x123, packet.sequenceId)
-            return MessageSvcPbSendMsg.Response.SUCCESS
+            return MessageSvcPbSendMsg.Response.SUCCESS(123)
         }
 
         override suspend fun createPacketsForGeneralMessage(

+ 10 - 10
mirai-core/src/commonTest/kotlin/message/protocol/impl/QuoteReplyProtocolTest.kt

@@ -21,7 +21,6 @@ import net.mamoe.mirai.internal.testFramework.runDynamicTests
 import net.mamoe.mirai.internal.utils.runCoroutineInPlace
 import net.mamoe.mirai.message.data.*
 import net.mamoe.mirai.message.data.MessageSource.Key.quote
-import net.mamoe.mirai.utils.EMPTY_BYTE_ARRAY
 import net.mamoe.mirai.utils.hexToBytes
 import kotlin.test.Test
 
@@ -90,8 +89,9 @@ internal class QuoteReplyProtocolTest : AbstractMessageProtocolTest() {
                                 ),
                             ),
                         ),
-                        srcMsg = EMPTY_BYTE_ARRAY
-                        // mirai's OfflineMessageSource has no enough information to create 'srcMsg'
+                        pbReserve = "18 AE FB A2 F7 86 80 80 80 01".hexToBytes(),
+                        srcMsg = "0A 2C 08 B1 89 4B 10 DD F1 92 B7 07 18 09 20 0B 28 E7 8B FE FF FF FF FF FF FF 01 30 B2 85 AF 94 06 38 AE FB A2 F7 86 80 80 80 01 E0 01 01 1A 0D 0A 0B 12 05 0A 03 0A 01 61 12 02 4A 00".hexToBytes(),
+                        toUin = 1994701021,
                     ),
                 ),
                 net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem(
@@ -192,8 +192,8 @@ internal class QuoteReplyProtocolTest : AbstractMessageProtocolTest() {
                                 ),
                             ),
                         ),
-                        pbReserve = "18 BA 92 F1 A4 02".hexToBytes(),
-                        srcMsg = "0A 20 08 B1 89 4B 10 B2 89 4B 18 A6 01 20 0B 28 8D F4 01 30 B0 A7 AF 94 06 38 BA 92 F1 A4 02 E0 01 01 1A 2D 0A 2B 12 05 0A 03 0A 01 61 12 00 12 1C AA 02 19 9A 01 16 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 CA 04 00 D2 05 02 08 61 12 02 4A 00".hexToBytes(),
+                        pbReserve = "18 BA 92 F1 A4 82 80 80 80 01".hexToBytes(),
+                        srcMsg = "0A 24 08 B1 89 4B 10 B2 89 4B 18 A6 01 20 0B 28 8D F4 01 30 B0 A7 AF 94 06 38 BA 92 F1 A4 82 80 80 80 01 E0 01 01 1A 2D 0A 2B 12 05 0A 03 0A 01 61 12 00 12 1C AA 02 19 9A 01 16 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 CA 04 00 D2 05 02 08 61 12 02 4A 00".hexToBytes(),
                         toUin = 1230002,
                     ),
                 ),
@@ -330,8 +330,9 @@ internal class QuoteReplyProtocolTest : AbstractMessageProtocolTest() {
                                 ),
                             ),
                         ),
-                        srcMsg = EMPTY_BYTE_ARRAY
-                        // mirai's OfflineMessageSource has no enough information to create 'srcMsg'
+                        pbReserve = "18 AE FB A2 F7 86 80 80 80 01".hexToBytes(),
+                        srcMsg = "0A 2C 08 B1 89 4B 10 DD F1 92 B7 07 18 09 20 0B 28 E7 8B FE FF FF FF FF FF FF 01 30 B2 85 AF 94 06 38 AE FB A2 F7 86 80 80 80 01 E0 01 01 1A 0D 0A 0B 12 05 0A 03 0A 01 61 12 02 4A 00".hexToBytes(),
+                        toUin = 1994701021,
                     ),
                 ),
                 net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.Elem(
@@ -430,9 +431,8 @@ internal class QuoteReplyProtocolTest : AbstractMessageProtocolTest() {
                                 ),
                             ),
                         ),
-                        pbReserve = "18 BD F9 EF D7 06".hexToBytes(),
-                        // srcMsg is available for online source
-                        srcMsg = "0A 20 08 B1 89 4B 10 B2 89 4B 18 A6 01 20 0B 28 F6 F3 01 30 83 91 AF 94 06 38 BD F9 EF D7 06 E0 01 01 1A 2D 0A 2B 12 05 0A 03 0A 01 61 12 00 12 1C AA 02 19 9A 01 16 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 CA 04 00 D2 05 02 08 4F 12 02 4A 00".hexToBytes(),
+                        pbReserve = "18 BD F9 EF D7 86 80 80 80 01".hexToBytes(),
+                        srcMsg = "0A 24 08 B1 89 4B 10 B2 89 4B 18 A6 01 20 0B 28 F6 F3 01 30 83 91 AF 94 06 38 BD F9 EF D7 86 80 80 80 01 E0 01 01 1A 2D 0A 2B 12 05 0A 03 0A 01 61 12 00 12 1C AA 02 19 9A 01 16 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 CA 04 00 D2 05 02 08 4F 12 02 4A 00".hexToBytes(),
                         toUin = 1230002,
                     ),
                 ),