mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-05 23:50:08 +08:00
[core] Fix quote replying; Fix message source time
This commit is contained in:
parent
1a8af784dc
commit
1169d7cf57
@ -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,
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
),
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
),
|
||||
),
|
||||
|
Loading…
Reference in New Issue
Block a user