[core] Fix quote replying; Fix message source time

This commit is contained in:
Karlatemp 2023-02-17 23:27:32 +08:00
parent 1a8af784dc
commit 1169d7cf57
No known key found for this signature in database
GPG Key ID: BA173CA2B9956C59
9 changed files with 63 additions and 48 deletions

View File

@ -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,

View File

@ -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()

View File

@ -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
}
/**

View File

@ -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
),

View File

@ -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 {

View File

@ -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,

View File

@ -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(

View File

@ -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(

View File

@ -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,
),
),