mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-05 23:50:08 +08:00
Add LongMessageProtocolTest and various improvements:
Change attributes carrying helper objects to components Make ClockHolder open Use originalMessage for MessageReceipt
This commit is contained in:
parent
3b7eb40529
commit
c8fb354d13
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||||
*
|
*
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
@ -11,7 +11,7 @@ package net.mamoe.mirai.utils
|
|||||||
|
|
||||||
public interface Clock {
|
public interface Clock {
|
||||||
public fun currentTimeMillis(): Long
|
public fun currentTimeMillis(): Long
|
||||||
public fun currentTimeSeconds(): Long
|
public fun currentTimeSeconds(): Long = currentTimeMillis() / 1000
|
||||||
|
|
||||||
public object SystemDefault : Clock {
|
public object SystemDefault : Clock {
|
||||||
override fun currentTimeMillis(): Long = net.mamoe.mirai.utils.currentTimeMillis()
|
override fun currentTimeMillis(): Long = net.mamoe.mirai.utils.currentTimeMillis()
|
||||||
|
@ -26,6 +26,7 @@ import net.mamoe.mirai.internal.message.protocol.outgoing.HighwayUploader
|
|||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.MessageProtocolStrategy
|
import net.mamoe.mirai.internal.message.protocol.outgoing.MessageProtocolStrategy
|
||||||
import net.mamoe.mirai.internal.network.component.buildComponentStorage
|
import net.mamoe.mirai.internal.network.component.buildComponentStorage
|
||||||
import net.mamoe.mirai.internal.network.components.BdhSession
|
import net.mamoe.mirai.internal.network.components.BdhSession
|
||||||
|
import net.mamoe.mirai.internal.network.components.ClockHolder
|
||||||
import net.mamoe.mirai.internal.network.highway.ChannelKind
|
import net.mamoe.mirai.internal.network.highway.ChannelKind
|
||||||
import net.mamoe.mirai.internal.network.highway.Highway
|
import net.mamoe.mirai.internal.network.highway.Highway
|
||||||
import net.mamoe.mirai.internal.network.highway.ResourceKind.PRIVATE_IMAGE
|
import net.mamoe.mirai.internal.network.highway.ResourceKind.PRIVATE_IMAGE
|
||||||
@ -261,6 +262,7 @@ internal suspend fun <C : AbstractContact> C.sendMessageImpl(
|
|||||||
MessageProtocolFacade.preprocessAndSendOutgoing(this, message, buildComponentStorage {
|
MessageProtocolFacade.preprocessAndSendOutgoing(this, message, buildComponentStorage {
|
||||||
set(MessageProtocolStrategy, messageProtocolStrategy)
|
set(MessageProtocolStrategy, messageProtocolStrategy)
|
||||||
set(HighwayUploader, HighwayUploader.Default)
|
set(HighwayUploader, HighwayUploader.Default)
|
||||||
|
set(ClockHolder, bot.components[ClockHolder])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,16 +45,27 @@ internal suspend fun <C : Contact> C.broadcastMessagePreSendEvent(
|
|||||||
|
|
||||||
|
|
||||||
internal enum class SendMessageStep {
|
internal enum class SendMessageStep {
|
||||||
|
/**
|
||||||
|
* 尝试单包直接发送全部消息
|
||||||
|
*/
|
||||||
FIRST {
|
FIRST {
|
||||||
override fun nextStepOrNull(): SendMessageStep {
|
override fun nextStepOrNull(): SendMessageStep {
|
||||||
return LONG_MESSAGE
|
return LONG_MESSAGE
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试通过长消息通道上传长消息取得 resId 后再通过普通消息通道发送长消息标识
|
||||||
|
*/
|
||||||
LONG_MESSAGE {
|
LONG_MESSAGE {
|
||||||
override fun nextStepOrNull(): SendMessageStep {
|
override fun nextStepOrNull(): SendMessageStep {
|
||||||
return FRAGMENTED
|
return FRAGMENTED
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送分片多包发送
|
||||||
|
*/
|
||||||
FRAGMENTED {
|
FRAGMENTED {
|
||||||
override fun nextStepOrNull(): SendMessageStep? {
|
override fun nextStepOrNull(): SendMessageStep? {
|
||||||
return null
|
return null
|
||||||
|
@ -152,34 +152,6 @@ internal data class ForwardMessageInternal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal fun RichMessage.Key.longMessage(brief: String, resId: String, timeSeconds: Long): LongMessageInternal {
|
|
||||||
val limited: String = if (brief.length > 30) {
|
|
||||||
brief.take(30) + "…"
|
|
||||||
} else {
|
|
||||||
brief
|
|
||||||
}
|
|
||||||
|
|
||||||
val template = """
|
|
||||||
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
|
|
||||||
<msg serviceID="35" templateID="1" action="viewMultiMsg"
|
|
||||||
brief="$limited"
|
|
||||||
m_resid="$resId"
|
|
||||||
m_fileName="$timeSeconds" sourceMsgId="0" url=""
|
|
||||||
flag="3" adverSign="0" multiMsgFlag="1">
|
|
||||||
<item layout="1">
|
|
||||||
<title>$limited</title>
|
|
||||||
<hr hidden="false" style="0"/>
|
|
||||||
<summary>点击查看完整消息</summary>
|
|
||||||
</item>
|
|
||||||
<source name="聊天记录" icon="" action="" appid="-1"/>
|
|
||||||
</msg>
|
|
||||||
""".trimIndent().trim()
|
|
||||||
|
|
||||||
return LongMessageInternal(template, resId)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun String.xmlEnc(): String {
|
private fun String.xmlEnc(): String {
|
||||||
return this.replace("&", "&")
|
return this.replace("&", "&")
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,9 @@ import net.mamoe.mirai.internal.contact.impl
|
|||||||
import net.mamoe.mirai.internal.contact.uin
|
import net.mamoe.mirai.internal.contact.uin
|
||||||
import net.mamoe.mirai.internal.contact.userIdOrNull
|
import net.mamoe.mirai.internal.contact.userIdOrNull
|
||||||
import net.mamoe.mirai.internal.message.protocol.MessageProtocolFacade
|
import net.mamoe.mirai.internal.message.protocol.MessageProtocolFacade
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.HighwayUploader
|
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.MessageProtocolStrategy
|
|
||||||
import net.mamoe.mirai.internal.message.source.MessageSourceInternal
|
import net.mamoe.mirai.internal.message.source.MessageSourceInternal
|
||||||
import net.mamoe.mirai.internal.network.QQAndroidClient
|
import net.mamoe.mirai.internal.network.QQAndroidClient
|
||||||
import net.mamoe.mirai.internal.network.component.buildComponentStorage
|
import net.mamoe.mirai.internal.network.component.ComponentStorage
|
||||||
import net.mamoe.mirai.internal.network.highway.Highway
|
import net.mamoe.mirai.internal.network.highway.Highway
|
||||||
import net.mamoe.mirai.internal.network.highway.ResourceKind
|
import net.mamoe.mirai.internal.network.highway.ResourceKind
|
||||||
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
||||||
@ -42,21 +40,19 @@ import kotlin.random.Random
|
|||||||
internal open class MultiMsgUploader(
|
internal open class MultiMsgUploader(
|
||||||
val client: QQAndroidClient,
|
val client: QQAndroidClient,
|
||||||
val isLong: Boolean,
|
val isLong: Boolean,
|
||||||
val tmpRand: Random = Random.Default,
|
val random: Random,
|
||||||
val facade: MessageProtocolFacade,
|
|
||||||
val contact: Contact,
|
val contact: Contact,
|
||||||
val strategy: MessageProtocolStrategy<*>,
|
val components: ComponentStorage,
|
||||||
val senderName: String
|
val senderName: String
|
||||||
) {
|
) {
|
||||||
|
|
||||||
protected open fun newUploader(): MultiMsgUploader = MultiMsgUploader(
|
protected open fun newUploader(): MultiMsgUploader = MultiMsgUploader(
|
||||||
isLong = isLong,
|
|
||||||
client = client,
|
client = client,
|
||||||
tmpRand = tmpRand,
|
isLong = isLong,
|
||||||
facade = facade,
|
random = random,
|
||||||
contact = contact,
|
contact = contact,
|
||||||
senderName = senderName,
|
components = components,
|
||||||
strategy = strategy
|
senderName = senderName
|
||||||
)
|
)
|
||||||
|
|
||||||
val mainMsg = mutableListOf<MsgComm.Msg>()
|
val mainMsg = mutableListOf<MsgComm.Msg>()
|
||||||
@ -69,7 +65,7 @@ internal open class MultiMsgUploader(
|
|||||||
protected open fun newNid(): String {
|
protected open fun newNid(): String {
|
||||||
var nid: String
|
var nid: String
|
||||||
do {
|
do {
|
||||||
nid = "${tmpRand.nextInt().absoluteValue}"
|
nid = "${random.nextInt().absoluteValue}"
|
||||||
} while (nestedMsgs.containsKey(nid))
|
} while (nestedMsgs.containsKey(nid))
|
||||||
return nid
|
return nid
|
||||||
}
|
}
|
||||||
@ -140,10 +136,7 @@ internal open class MultiMsgUploader(
|
|||||||
msgChain = convertNestedForwardMessage(nestedForward, msgChain)
|
msgChain = convertNestedForwardMessage(nestedForward, msgChain)
|
||||||
}
|
}
|
||||||
|
|
||||||
msgChain = facade.preprocess(contact.impl(), msgChain, buildComponentStorage {
|
msgChain = components[MessageProtocolFacade].preprocess(contact.impl(), msgChain, components)
|
||||||
set(MessageProtocolStrategy, strategy)
|
|
||||||
set(HighwayUploader, HighwayUploader.Default)
|
|
||||||
})
|
|
||||||
|
|
||||||
var seq: Int = -1
|
var seq: Int = -1
|
||||||
var uid: Int = -1
|
var uid: Int = -1
|
||||||
@ -157,8 +150,8 @@ internal open class MultiMsgUploader(
|
|||||||
if (seq != -1 && uid != -1) {
|
if (seq != -1 && uid != -1) {
|
||||||
if (existsIds.add(seq.concatAsLong(uid))) break
|
if (existsIds.add(seq.concatAsLong(uid))) break
|
||||||
}
|
}
|
||||||
seq = tmpRand.nextInt().absoluteValue
|
seq = random.nextInt().absoluteValue
|
||||||
uid = tmpRand.nextInt().absoluteValue
|
uid = random.nextInt().absoluteValue
|
||||||
}
|
}
|
||||||
|
|
||||||
val msg0 = MsgComm.Msg(
|
val msg0 = MsgComm.Msg(
|
||||||
@ -176,18 +169,13 @@ internal open class MultiMsgUploader(
|
|||||||
),
|
),
|
||||||
msgType = 82, // troop,
|
msgType = 82, // troop,
|
||||||
groupInfo = if (contact is Group) MsgComm.GroupInfo(
|
groupInfo = if (contact is Group) MsgComm.GroupInfo(
|
||||||
groupCode = contact.groupCode,
|
groupCode = contact.groupCode, groupCard = senderName // Cinnamon
|
||||||
groupCard = senderName // Cinnamon
|
|
||||||
) else null,
|
) else null,
|
||||||
isSrcMsg = false,
|
isSrcMsg = false,
|
||||||
),
|
), msgBody = ImMsgBody.MsgBody(
|
||||||
msgBody = ImMsgBody.MsgBody(
|
|
||||||
richText = ImMsgBody.RichText(
|
richText = ImMsgBody.RichText(
|
||||||
elems = MessageProtocolFacade.encode(
|
elems = MessageProtocolFacade.encode(
|
||||||
msgChain,
|
msgChain, messageTarget = contact, withGeneralFlags = false, isForward = true
|
||||||
messageTarget = contact,
|
|
||||||
withGeneralFlags = false,
|
|
||||||
isForward = true
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -197,17 +185,13 @@ internal open class MultiMsgUploader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
open fun toMessageValidationData(): MessageValidationData {
|
open fun toMessageValidationData(): MessageValidationData {
|
||||||
val msgTransmit = MsgTransmit.PbMultiMsgTransmit(
|
val msgTransmit =
|
||||||
msg = mainMsg,
|
MsgTransmit.PbMultiMsgTransmit(msg = mainMsg, pbItemList = nestedMsgs.asSequence().map { (name, msgList) ->
|
||||||
pbItemList = nestedMsgs.asSequence()
|
MsgTransmit.PbMultiMsgItem(
|
||||||
.map { (name, msgList) ->
|
fileName = name,
|
||||||
MsgTransmit.PbMultiMsgItem(
|
buffer = MsgTransmit.PbMultiMsgNew(msgList).toByteArray(MsgTransmit.PbMultiMsgNew.serializer())
|
||||||
fileName = name,
|
)
|
||||||
buffer = MsgTransmit.PbMultiMsgNew(msgList).toByteArray(MsgTransmit.PbMultiMsgNew.serializer())
|
}.toList())
|
||||||
)
|
|
||||||
}
|
|
||||||
.toList()
|
|
||||||
)
|
|
||||||
val bytes = msgTransmit.toByteArray(MsgTransmit.PbMultiMsgTransmit.serializer())
|
val bytes = msgTransmit.toByteArray(MsgTransmit.PbMultiMsgTransmit.serializer())
|
||||||
|
|
||||||
return MessageValidationData(bytes.gzip())
|
return MessageValidationData(bytes.gzip())
|
||||||
@ -218,27 +202,20 @@ internal open class MultiMsgUploader(
|
|||||||
|
|
||||||
val response = client.bot.network.sendAndExpect(
|
val response = client.bot.network.sendAndExpect(
|
||||||
MultiMsg.ApplyUp.createForGroup(
|
MultiMsg.ApplyUp.createForGroup(
|
||||||
buType = if (isLong) 1 else 2,
|
buType = if (isLong) 1 else 2, client = client, messageData = data, dstUin = contact.uin
|
||||||
client = client,
|
|
||||||
messageData = data,
|
|
||||||
dstUin = contact.uin
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
lateinit var resId: String
|
lateinit var resId: String
|
||||||
when (response) {
|
when (response) {
|
||||||
is MultiMsg.ApplyUp.Response.MessageTooLarge ->
|
is MultiMsg.ApplyUp.Response.MessageTooLarge -> error(
|
||||||
error(
|
"Internal error: message is too large, but this should be handled before sending. "
|
||||||
"Internal error: message is too large, but this should be handled before sending. "
|
)
|
||||||
)
|
|
||||||
is MultiMsg.ApplyUp.Response.RequireUpload -> {
|
is MultiMsg.ApplyUp.Response.RequireUpload -> {
|
||||||
resId = response.proto.msgResid
|
resId = response.proto.msgResid
|
||||||
|
|
||||||
val body = LongMsg.ReqBody(
|
val body = LongMsg.ReqBody(
|
||||||
subcmd = 1,
|
subcmd = 1, platformType = 9, termType = 5, msgUpReq = listOf(
|
||||||
platformType = 9,
|
|
||||||
termType = 5,
|
|
||||||
msgUpReq = listOf(
|
|
||||||
LongMsg.MsgUpReq(
|
LongMsg.MsgUpReq(
|
||||||
msgType = 3, // group
|
msgType = 3, // group
|
||||||
dstUin = contact.uin,
|
dstUin = contact.uin,
|
||||||
@ -253,14 +230,10 @@ internal open class MultiMsgUploader(
|
|||||||
|
|
||||||
body.toExternalResource().use { resource ->
|
body.toExternalResource().use { resource ->
|
||||||
Highway.uploadResourceBdh(
|
Highway.uploadResourceBdh(
|
||||||
bot = client.bot,
|
bot = client.bot, resource = resource, kind = when (isLong) {
|
||||||
resource = resource,
|
|
||||||
kind = when (isLong) {
|
|
||||||
true -> ResourceKind.LONG_MESSAGE
|
true -> ResourceKind.LONG_MESSAGE
|
||||||
false -> ResourceKind.FORWARD_MESSAGE
|
false -> ResourceKind.FORWARD_MESSAGE
|
||||||
},
|
}, commandId = 27, initialTicket = response.proto.msgSig
|
||||||
commandId = 27,
|
|
||||||
initialTicket = response.proto.msgSig
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,10 @@ import net.mamoe.mirai.internal.message.contextualBugReportException
|
|||||||
import net.mamoe.mirai.internal.message.protocol.decode.*
|
import net.mamoe.mirai.internal.message.protocol.decode.*
|
||||||
import net.mamoe.mirai.internal.message.protocol.encode.*
|
import net.mamoe.mirai.internal.message.protocol.encode.*
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.*
|
import net.mamoe.mirai.internal.message.protocol.outgoing.*
|
||||||
|
import net.mamoe.mirai.internal.network.component.ComponentKey
|
||||||
import net.mamoe.mirai.internal.network.component.ComponentStorage
|
import net.mamoe.mirai.internal.network.component.ComponentStorage
|
||||||
|
import net.mamoe.mirai.internal.network.component.buildComponentStorage
|
||||||
|
import net.mamoe.mirai.internal.network.component.withFallback
|
||||||
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
||||||
import net.mamoe.mirai.internal.pipeline.ProcessResult
|
import net.mamoe.mirai.internal.pipeline.ProcessResult
|
||||||
import net.mamoe.mirai.internal.utils.runCoroutineInPlace
|
import net.mamoe.mirai.internal.utils.runCoroutineInPlace
|
||||||
@ -39,6 +42,8 @@ import java.util.*
|
|||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
internal interface MessageProtocolFacade {
|
internal interface MessageProtocolFacade {
|
||||||
|
val remark: String get() = "MessageProtocolFacade"
|
||||||
|
|
||||||
val encoderPipeline: MessageEncoderPipeline
|
val encoderPipeline: MessageEncoderPipeline
|
||||||
val decoderPipeline: MessageDecoderPipeline
|
val decoderPipeline: MessageDecoderPipeline
|
||||||
val preprocessorPipeline: OutgoingMessagePipeline
|
val preprocessorPipeline: OutgoingMessagePipeline
|
||||||
@ -129,7 +134,8 @@ internal interface MessageProtocolFacade {
|
|||||||
/**
|
/**
|
||||||
* The default global instance.
|
* The default global instance.
|
||||||
*/
|
*/
|
||||||
companion object INSTANCE : MessageProtocolFacade by MessageProtocolFacadeImpl()
|
companion object INSTANCE : MessageProtocolFacade by MessageProtocolFacadeImpl(),
|
||||||
|
ComponentKey<MessageProtocolFacade>
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun MessageProtocolFacade.decodeAndRefineLight(
|
internal fun MessageProtocolFacade.decodeAndRefineLight(
|
||||||
@ -150,7 +156,8 @@ internal suspend fun MessageProtocolFacade.decodeAndRefineDeep(
|
|||||||
|
|
||||||
|
|
||||||
internal class MessageProtocolFacadeImpl(
|
internal class MessageProtocolFacadeImpl(
|
||||||
private val protocols: Iterable<MessageProtocol> = ServiceLoader.load(MessageProtocol::class.java)
|
private val protocols: Iterable<MessageProtocol> = ServiceLoader.load(MessageProtocol::class.java),
|
||||||
|
override val remark: String = "MessageProtocolFacade"
|
||||||
) : MessageProtocolFacade {
|
) : MessageProtocolFacade {
|
||||||
override val encoderPipeline: MessageEncoderPipeline = MessageEncoderPipelineImpl()
|
override val encoderPipeline: MessageEncoderPipeline = MessageEncoderPipelineImpl()
|
||||||
override val decoderPipeline: MessageDecoderPipeline = MessageDecoderPipelineImpl()
|
override val decoderPipeline: MessageDecoderPipeline = MessageDecoderPipelineImpl()
|
||||||
@ -243,6 +250,15 @@ internal class MessageProtocolFacadeImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val thisComponentStorage by lazy {
|
||||||
|
buildComponentStorage {
|
||||||
|
set(
|
||||||
|
MessageProtocolFacade,
|
||||||
|
this@MessageProtocolFacadeImpl
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun <C : AbstractContact> preprocess(
|
override suspend fun <C : AbstractContact> preprocess(
|
||||||
target: C,
|
target: C,
|
||||||
message: Message,
|
message: Message,
|
||||||
@ -314,9 +330,9 @@ internal class MessageProtocolFacadeImpl(
|
|||||||
val attributes = buildTypeSafeMap {
|
val attributes = buildTypeSafeMap {
|
||||||
set(OutgoingMessagePipelineContext.CONTACT, target.impl())
|
set(OutgoingMessagePipelineContext.CONTACT, target.impl())
|
||||||
set(OutgoingMessagePipelineContext.ORIGINAL_MESSAGE, message)
|
set(OutgoingMessagePipelineContext.ORIGINAL_MESSAGE, message)
|
||||||
|
set(OutgoingMessagePipelineContext.ORIGINAL_MESSAGE_AS_CHAIN, message.toMessageChain())
|
||||||
set(OutgoingMessagePipelineContext.STEP, SendMessageStep.FIRST)
|
set(OutgoingMessagePipelineContext.STEP, SendMessageStep.FIRST)
|
||||||
set(OutgoingMessagePipelineContext.PROTOCOL_STRATEGY, context[MessageProtocolStrategy].castUp())
|
set(OutgoingMessagePipelineContext.COMPONENTS, thisComponentStorage.withFallback(context))
|
||||||
set(OutgoingMessagePipelineContext.HIGHWAY_UPLOADER, context[HighwayUploader])
|
|
||||||
}
|
}
|
||||||
return attributes
|
return attributes
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,11 @@ import net.mamoe.mirai.internal.message.protocol.MessageProtocol
|
|||||||
import net.mamoe.mirai.internal.message.protocol.ProcessorCollector
|
import net.mamoe.mirai.internal.message.protocol.ProcessorCollector
|
||||||
import net.mamoe.mirai.internal.message.protocol.decode.MessageDecoder
|
import net.mamoe.mirai.internal.message.protocol.decode.MessageDecoder
|
||||||
import net.mamoe.mirai.internal.message.protocol.decode.MessageDecoderContext
|
import net.mamoe.mirai.internal.message.protocol.decode.MessageDecoderContext
|
||||||
|
import net.mamoe.mirai.internal.message.protocol.outgoing.MessageProtocolStrategy
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.CONTACT
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.CONTACT
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.PROTOCOL_STRATEGY
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.ORIGINAL_MESSAGE_AS_CHAIN
|
||||||
|
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.outgoing.OutgoingMessageSender
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessageTransformer
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessageTransformer
|
||||||
import net.mamoe.mirai.internal.message.source.createMessageReceipt
|
import net.mamoe.mirai.internal.message.source.createMessageReceipt
|
||||||
@ -81,11 +83,11 @@ internal class FileMessageProtocol : MessageProtocol() {
|
|||||||
val contact = attributes[CONTACT]
|
val contact = attributes[CONTACT]
|
||||||
val bot = contact.bot
|
val bot = contact.bot
|
||||||
|
|
||||||
val strategy = attributes[PROTOCOL_STRATEGY]
|
val strategy = components[MessageProtocolStrategy]
|
||||||
|
|
||||||
val source = coroutineScope {
|
val source = coroutineScope {
|
||||||
val source = async {
|
val source = async {
|
||||||
strategy.constructSourceForSpecialMessage(currentMessageChain, 2021)
|
strategy.constructSourceForSpecialMessage(attributes[ORIGINAL_MESSAGE_AS_CHAIN], 2021)
|
||||||
}
|
}
|
||||||
|
|
||||||
bot.network.sendAndExpect(FileManagement.Feed(bot.client, contact.id, file.busId, file.id))
|
bot.network.sendAndExpect(FileManagement.Feed(bot.client, contact.id, file.busId, file.id))
|
||||||
|
@ -14,15 +14,15 @@ import net.mamoe.mirai.internal.message.data.forwardMessage
|
|||||||
import net.mamoe.mirai.internal.message.flags.IgnoreLengthCheck
|
import net.mamoe.mirai.internal.message.flags.IgnoreLengthCheck
|
||||||
import net.mamoe.mirai.internal.message.protocol.MessageProtocol
|
import net.mamoe.mirai.internal.message.protocol.MessageProtocol
|
||||||
import net.mamoe.mirai.internal.message.protocol.ProcessorCollector
|
import net.mamoe.mirai.internal.message.protocol.ProcessorCollector
|
||||||
|
import net.mamoe.mirai.internal.message.protocol.outgoing.HighwayUploader
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.CONTACT
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.CONTACT
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.HIGHWAY_UPLOADER
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.components
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.PROTOCOL_STRATEGY
|
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePreprocessor
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePreprocessor
|
||||||
|
import net.mamoe.mirai.internal.network.components.ClockHolder
|
||||||
import net.mamoe.mirai.message.data.ForwardMessage
|
import net.mamoe.mirai.message.data.ForwardMessage
|
||||||
import net.mamoe.mirai.message.data.RichMessage
|
import net.mamoe.mirai.message.data.RichMessage
|
||||||
import net.mamoe.mirai.message.data.toMessageChain
|
import net.mamoe.mirai.message.data.toMessageChain
|
||||||
import net.mamoe.mirai.utils.currentTimeSeconds
|
|
||||||
|
|
||||||
internal class ForwardMessageProtocol : MessageProtocol() {
|
internal class ForwardMessageProtocol : MessageProtocol() {
|
||||||
override fun ProcessorCollector.collectProcessorsImpl() {
|
override fun ProcessorCollector.collectProcessorsImpl() {
|
||||||
@ -46,16 +46,16 @@ internal class ForwardMessageProtocol : MessageProtocol() {
|
|||||||
}.asIterable().verifyLength(forward, contact)
|
}.asIterable().verifyLength(forward, contact)
|
||||||
}
|
}
|
||||||
|
|
||||||
val resId = attributes[HIGHWAY_UPLOADER].uploadMessages(
|
val resId = components[HighwayUploader].uploadMessages(
|
||||||
contact,
|
contact,
|
||||||
attributes[PROTOCOL_STRATEGY],
|
components,
|
||||||
forward.nodeList,
|
forward.nodeList,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
currentMessageChain = RichMessage.forwardMessage(
|
currentMessageChain = RichMessage.forwardMessage(
|
||||||
resId = resId,
|
resId = resId,
|
||||||
fileName = currentTimeSeconds().toString(),
|
fileName = components[ClockHolder].local.currentTimeSeconds().toString(),
|
||||||
forwardMessage = forward,
|
forwardMessage = forward,
|
||||||
).toMessageChain()
|
).toMessageChain()
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,17 @@ package net.mamoe.mirai.internal.message.protocol.impl
|
|||||||
import kotlinx.coroutines.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
import net.mamoe.mirai.contact.*
|
import net.mamoe.mirai.contact.*
|
||||||
import net.mamoe.mirai.internal.AbstractBot
|
import net.mamoe.mirai.internal.AbstractBot
|
||||||
|
import net.mamoe.mirai.internal.contact.AbstractContact
|
||||||
import net.mamoe.mirai.internal.contact.SendMessageStep
|
import net.mamoe.mirai.internal.contact.SendMessageStep
|
||||||
import net.mamoe.mirai.internal.message.protocol.MessageProtocol
|
import net.mamoe.mirai.internal.message.protocol.MessageProtocol
|
||||||
import net.mamoe.mirai.internal.message.protocol.ProcessorCollector
|
import net.mamoe.mirai.internal.message.protocol.ProcessorCollector
|
||||||
|
import net.mamoe.mirai.internal.message.protocol.outgoing.MessageProtocolStrategy
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.CONTACT
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.CONTACT
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.ORIGINAL_MESSAGE
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.ORIGINAL_MESSAGE
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.PROTOCOL_STRATEGY
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.ORIGINAL_MESSAGE_AS_CHAIN
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.STEP
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.STEP
|
||||||
|
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.outgoing.OutgoingMessageSender
|
||||||
import net.mamoe.mirai.internal.message.source.createMessageReceipt
|
import net.mamoe.mirai.internal.message.source.createMessageReceipt
|
||||||
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
|
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
|
||||||
@ -41,7 +44,8 @@ internal class GeneralMessageSenderProtocol : MessageProtocol(PRIORITY_GENERAL_S
|
|||||||
override suspend fun OutgoingMessagePipelineContext.process() {
|
override suspend fun OutgoingMessagePipelineContext.process() {
|
||||||
markAsConsumed()
|
markAsConsumed()
|
||||||
|
|
||||||
val strategy = attributes[PROTOCOL_STRATEGY]
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val strategy = components[MessageProtocolStrategy] as MessageProtocolStrategy<AbstractContact>
|
||||||
val step = attributes[STEP]
|
val step = attributes[STEP]
|
||||||
val contact = attributes[CONTACT]
|
val contact = attributes[CONTACT]
|
||||||
val bot = contact.bot
|
val bot = contact.bot
|
||||||
@ -52,9 +56,9 @@ internal class GeneralMessageSenderProtocol : MessageProtocol(PRIORITY_GENERAL_S
|
|||||||
client = bot.client,
|
client = bot.client,
|
||||||
contact = contact,
|
contact = contact,
|
||||||
message = currentMessageChain,
|
message = currentMessageChain,
|
||||||
fragmented = step == SendMessageStep.FRAGMENTED,
|
originalMessage = attributes[ORIGINAL_MESSAGE_AS_CHAIN],
|
||||||
sourceCallback = { source = it }
|
fragmented = step == SendMessageStep.FRAGMENTED
|
||||||
)
|
) { source = it }
|
||||||
|
|
||||||
sendAllPackets(bot, step, contact, packets)
|
sendAllPackets(bot, step, contact, packets)
|
||||||
|
|
||||||
@ -70,7 +74,7 @@ internal class GeneralMessageSenderProtocol : MessageProtocol(PRIORITY_GENERAL_S
|
|||||||
packets: List<OutgoingPacket>
|
packets: List<OutgoingPacket>
|
||||||
) = packets.forEach { packet ->
|
) = packets.forEach { packet ->
|
||||||
val originalMessage = attributes[ORIGINAL_MESSAGE]
|
val originalMessage = attributes[ORIGINAL_MESSAGE]
|
||||||
val protocolStrategy = attributes[PROTOCOL_STRATEGY]
|
val protocolStrategy = components[MessageProtocolStrategy]
|
||||||
val finalMessage = currentMessageChain
|
val finalMessage = currentMessageChain
|
||||||
|
|
||||||
val resp = protocolStrategy.sendPacket(bot, packet) as MessageSvcPbSendMsg.Response
|
val resp = protocolStrategy.sendPacket(bot, packet) as MessageSvcPbSendMsg.Response
|
||||||
|
@ -12,22 +12,21 @@ package net.mamoe.mirai.internal.message.protocol.impl
|
|||||||
import net.mamoe.mirai.internal.contact.AbstractContact
|
import net.mamoe.mirai.internal.contact.AbstractContact
|
||||||
import net.mamoe.mirai.internal.contact.SendMessageStep
|
import net.mamoe.mirai.internal.contact.SendMessageStep
|
||||||
import net.mamoe.mirai.internal.contact.takeContent
|
import net.mamoe.mirai.internal.contact.takeContent
|
||||||
import net.mamoe.mirai.internal.message.data.longMessage
|
import net.mamoe.mirai.internal.message.data.LongMessageInternal
|
||||||
import net.mamoe.mirai.internal.message.flags.DontAsLongMessage
|
import net.mamoe.mirai.internal.message.flags.DontAsLongMessage
|
||||||
import net.mamoe.mirai.internal.message.flags.ForceAsLongMessage
|
import net.mamoe.mirai.internal.message.flags.ForceAsLongMessage
|
||||||
import net.mamoe.mirai.internal.message.flags.IgnoreLengthCheck
|
import net.mamoe.mirai.internal.message.flags.IgnoreLengthCheck
|
||||||
import net.mamoe.mirai.internal.message.protocol.MessageProtocol
|
import net.mamoe.mirai.internal.message.protocol.MessageProtocol
|
||||||
import net.mamoe.mirai.internal.message.protocol.ProcessorCollector
|
import net.mamoe.mirai.internal.message.protocol.ProcessorCollector
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.MessageProtocolStrategy
|
import net.mamoe.mirai.internal.message.protocol.outgoing.HighwayUploader
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.CONTACT
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.CONTACT
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.HIGHWAY_UPLOADER
|
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.PROTOCOL_STRATEGY
|
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.STEP
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.STEP
|
||||||
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.components
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessageTransformer
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessageTransformer
|
||||||
|
import net.mamoe.mirai.internal.network.components.ClockHolder
|
||||||
import net.mamoe.mirai.message.data.MessageChain
|
import net.mamoe.mirai.message.data.MessageChain
|
||||||
import net.mamoe.mirai.message.data.RichMessage
|
import net.mamoe.mirai.utils.truncated
|
||||||
import net.mamoe.mirai.utils.currentTimeSeconds
|
|
||||||
|
|
||||||
internal class LongMessageProtocol : MessageProtocol() {
|
internal class LongMessageProtocol : MessageProtocol() {
|
||||||
override fun ProcessorCollector.collectProcessorsImpl() {
|
override fun ProcessorCollector.collectProcessorsImpl() {
|
||||||
@ -36,24 +35,25 @@ internal class LongMessageProtocol : MessageProtocol() {
|
|||||||
convertToLongMessageIfNeeded(
|
convertToLongMessageIfNeeded(
|
||||||
currentMessageChain,
|
currentMessageChain,
|
||||||
attributes[STEP],
|
attributes[STEP],
|
||||||
attributes[CONTACT],
|
attributes[CONTACT]
|
||||||
attributes[PROTOCOL_STRATEGY]
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert to [LongMessageInternal] iff [SendMessageStep.FIRST] has failed.
|
||||||
|
*/
|
||||||
private suspend fun OutgoingMessagePipelineContext.convertToLongMessageIfNeeded(
|
private suspend fun OutgoingMessagePipelineContext.convertToLongMessageIfNeeded(
|
||||||
chain: MessageChain,
|
chain: MessageChain,
|
||||||
step: SendMessageStep,
|
step: SendMessageStep,
|
||||||
contact: AbstractContact,
|
contact: AbstractContact,
|
||||||
strategy: MessageProtocolStrategy<*>
|
|
||||||
): MessageChain {
|
): MessageChain {
|
||||||
val uploader = attributes[HIGHWAY_UPLOADER]
|
val uploader = components[HighwayUploader]
|
||||||
|
|
||||||
suspend fun sendLongImpl(): MessageChain {
|
suspend fun sendLongImpl(): MessageChain {
|
||||||
val time = currentTimeSeconds()
|
val time = components[ClockHolder].local.currentTimeSeconds()
|
||||||
val resId = uploader.uploadLongMessage(contact, strategy, chain, time.toInt())
|
val resId = uploader.uploadLongMessage(contact, components, chain, time.toInt())
|
||||||
return chain + RichMessage.longMessage(
|
return chain + createLongMessage(
|
||||||
brief = chain.takeContent(27),
|
brief = chain.takeContent(27),
|
||||||
resId = resId,
|
resId = resId,
|
||||||
timeSeconds = time
|
timeSeconds = time
|
||||||
@ -81,4 +81,26 @@ internal class LongMessageProtocol : MessageProtocol() {
|
|||||||
SendMessageStep.FRAGMENTED -> chain
|
SendMessageStep.FRAGMENTED -> chain
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createLongMessage(brief: String, resId: String, timeSeconds: Long): LongMessageInternal {
|
||||||
|
val limited: String = brief.truncated(30)
|
||||||
|
val template = """
|
||||||
|
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
|
||||||
|
<msg serviceID="35" templateID="1" action="viewMultiMsg"
|
||||||
|
brief="$limited"
|
||||||
|
m_resid="$resId"
|
||||||
|
m_fileName="$timeSeconds" sourceMsgId="0" url=""
|
||||||
|
flag="3" adverSign="0" multiMsgFlag="1">
|
||||||
|
<item layout="1">
|
||||||
|
<title>$limited</title>
|
||||||
|
<hr hidden="false" style="0"/>
|
||||||
|
<summary>点击查看完整消息</summary>
|
||||||
|
</item>
|
||||||
|
<source name="聊天记录" icon="" action="" appid="-1"/>
|
||||||
|
</msg>
|
||||||
|
""".trimIndent().trim()
|
||||||
|
|
||||||
|
return LongMessageInternal(template, resId)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -14,8 +14,11 @@ import net.mamoe.mirai.internal.message.protocol.MessageProtocol
|
|||||||
import net.mamoe.mirai.internal.message.protocol.ProcessorCollector
|
import net.mamoe.mirai.internal.message.protocol.ProcessorCollector
|
||||||
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoder
|
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoder
|
||||||
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext
|
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext
|
||||||
|
import net.mamoe.mirai.internal.message.protocol.outgoing.MessageProtocolStrategy
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext
|
||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.CONTACT
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.CONTACT
|
||||||
|
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.ORIGINAL_MESSAGE_AS_CHAIN
|
||||||
|
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.outgoing.OutgoingMessageSender
|
||||||
import net.mamoe.mirai.internal.message.source.createMessageReceipt
|
import net.mamoe.mirai.internal.message.source.createMessageReceipt
|
||||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.MusicSharePacket
|
import net.mamoe.mirai.internal.network.protocol.packet.chat.MusicSharePacket
|
||||||
@ -55,8 +58,8 @@ internal class MusicShareProtocol : MessageProtocol() {
|
|||||||
val result = bot.network.sendAndExpect(packet)
|
val result = bot.network.sendAndExpect(packet)
|
||||||
result.pkg.checkSuccess("send music share")
|
result.pkg.checkSuccess("send music share")
|
||||||
|
|
||||||
val strategy = attributes[OutgoingMessagePipelineContext.PROTOCOL_STRATEGY]
|
val strategy = components[MessageProtocolStrategy]
|
||||||
val source = strategy.constructSourceForSpecialMessage(currentMessageChain, 3116)
|
val source = strategy.constructSourceForSpecialMessage(attributes[ORIGINAL_MESSAGE_AS_CHAIN], 3116)
|
||||||
source.tryEnsureSequenceIdAvailable()
|
source.tryEnsureSequenceIdAvailable()
|
||||||
|
|
||||||
collect(source.createMessageReceipt(contact, true))
|
collect(source.createMessageReceipt(contact, true))
|
||||||
|
@ -12,19 +12,20 @@ package net.mamoe.mirai.internal.message.protocol.outgoing
|
|||||||
import net.mamoe.mirai.internal.contact.AbstractContact
|
import net.mamoe.mirai.internal.contact.AbstractContact
|
||||||
import net.mamoe.mirai.internal.contact.nickIn
|
import net.mamoe.mirai.internal.contact.nickIn
|
||||||
import net.mamoe.mirai.internal.message.data.MultiMsgUploader
|
import net.mamoe.mirai.internal.message.data.MultiMsgUploader
|
||||||
import net.mamoe.mirai.internal.message.protocol.MessageProtocolFacade
|
|
||||||
import net.mamoe.mirai.internal.message.source.ensureSequenceIdAvailable
|
import net.mamoe.mirai.internal.message.source.ensureSequenceIdAvailable
|
||||||
import net.mamoe.mirai.internal.network.component.ComponentKey
|
import net.mamoe.mirai.internal.network.component.ComponentKey
|
||||||
|
import net.mamoe.mirai.internal.network.component.ComponentStorage
|
||||||
|
import net.mamoe.mirai.internal.network.components.ClockHolder
|
||||||
import net.mamoe.mirai.message.data.ForwardMessage
|
import net.mamoe.mirai.message.data.ForwardMessage
|
||||||
import net.mamoe.mirai.message.data.MessageChain
|
import net.mamoe.mirai.message.data.MessageChain
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
internal interface HighwayUploader {
|
internal interface HighwayUploader {
|
||||||
suspend fun uploadMessages(
|
suspend fun uploadMessages(
|
||||||
contact: AbstractContact,
|
contact: AbstractContact,
|
||||||
strategy: MessageProtocolStrategy<*>,
|
components: ComponentStorage,
|
||||||
nodes: Collection<ForwardMessage.INode>,
|
nodes: Collection<ForwardMessage.INode>,
|
||||||
isLong: Boolean,
|
isLong: Boolean,
|
||||||
facade: MessageProtocolFacade = MessageProtocolFacade,
|
|
||||||
senderName: String = contact.bot.nickIn(contact),
|
senderName: String = contact.bot.nickIn(contact),
|
||||||
): String {
|
): String {
|
||||||
nodes.forEach { it.messageChain.ensureSequenceIdAvailable() }
|
nodes.forEach { it.messageChain.ensureSequenceIdAvailable() }
|
||||||
@ -32,10 +33,10 @@ internal interface HighwayUploader {
|
|||||||
val uploader = MultiMsgUploader(
|
val uploader = MultiMsgUploader(
|
||||||
client = contact.bot.client,
|
client = contact.bot.client,
|
||||||
isLong = isLong,
|
isLong = isLong,
|
||||||
facade = facade,
|
|
||||||
contact = contact,
|
contact = contact,
|
||||||
|
random = Random(components[ClockHolder].local.currentTimeSeconds()),
|
||||||
senderName = senderName,
|
senderName = senderName,
|
||||||
strategy = strategy
|
components = components
|
||||||
).also { it.emitMain(nodes) }
|
).also { it.emitMain(nodes) }
|
||||||
|
|
||||||
return uploader.uploadAndReturnResId()
|
return uploader.uploadAndReturnResId()
|
||||||
@ -43,7 +44,7 @@ internal interface HighwayUploader {
|
|||||||
|
|
||||||
suspend fun uploadLongMessage(
|
suspend fun uploadLongMessage(
|
||||||
contact: AbstractContact,
|
contact: AbstractContact,
|
||||||
strategy: MessageProtocolStrategy<*>,
|
components: ComponentStorage,
|
||||||
chain: MessageChain,
|
chain: MessageChain,
|
||||||
timeSeconds: Int,
|
timeSeconds: Int,
|
||||||
senderName: String = contact.bot.nickIn(contact),
|
senderName: String = contact.bot.nickIn(contact),
|
||||||
@ -51,7 +52,7 @@ internal interface HighwayUploader {
|
|||||||
val bot = contact.bot
|
val bot = contact.bot
|
||||||
return uploadMessages(
|
return uploadMessages(
|
||||||
contact,
|
contact,
|
||||||
strategy,
|
components,
|
||||||
listOf(
|
listOf(
|
||||||
ForwardMessage.Node(
|
ForwardMessage.Node(
|
||||||
senderId = bot.id,
|
senderId = bot.id,
|
||||||
@ -61,7 +62,7 @@ internal interface HighwayUploader {
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
true,
|
true,
|
||||||
senderName = senderName
|
senderName = senderName,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,13 +37,14 @@ internal interface MessageProtocolStrategy<in C : AbstractContact> {
|
|||||||
suspend fun createPacketsForGeneralMessage(
|
suspend fun createPacketsForGeneralMessage(
|
||||||
client: QQAndroidClient,
|
client: QQAndroidClient,
|
||||||
contact: C,
|
contact: C,
|
||||||
message: MessageChain,
|
message: MessageChain, // to send
|
||||||
|
originalMessage: MessageChain, // to create Receipt
|
||||||
fragmented: Boolean,
|
fragmented: Boolean,
|
||||||
sourceCallback: (Deferred<OnlineMessageSource.Outgoing>) -> Unit,
|
sourceCallback: (Deferred<OnlineMessageSource.Outgoing>) -> Unit,
|
||||||
): List<OutgoingPacket>
|
): List<OutgoingPacket>
|
||||||
|
|
||||||
suspend fun constructSourceForSpecialMessage(
|
suspend fun constructSourceForSpecialMessage(
|
||||||
finalMessage: MessageChain,
|
originalMessage: MessageChain,
|
||||||
fromAppId: Int,
|
fromAppId: Int,
|
||||||
): OnlineMessageSource.Outgoing
|
): OnlineMessageSource.Outgoing
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ internal interface MessageProtocolStrategy<in C : AbstractContact> {
|
|||||||
|
|
||||||
internal sealed class UserMessageProtocolStrategy<C : AbstractUser> : MessageProtocolStrategy<C> {
|
internal sealed class UserMessageProtocolStrategy<C : AbstractUser> : MessageProtocolStrategy<C> {
|
||||||
override suspend fun constructSourceForSpecialMessage(
|
override suspend fun constructSourceForSpecialMessage(
|
||||||
finalMessage: MessageChain,
|
originalMessage: MessageChain,
|
||||||
fromAppId: Int
|
fromAppId: Int
|
||||||
): OnlineMessageSource.Outgoing {
|
): OnlineMessageSource.Outgoing {
|
||||||
throw UnsupportedOperationException("Sending MusicShare or FileMessage to User is not yet supported")
|
throw UnsupportedOperationException("Sending MusicShare or FileMessage to User is not yet supported")
|
||||||
@ -66,14 +67,15 @@ internal class FriendMessageProtocolStrategy(
|
|||||||
client: QQAndroidClient,
|
client: QQAndroidClient,
|
||||||
contact: FriendImpl,
|
contact: FriendImpl,
|
||||||
message: MessageChain,
|
message: MessageChain,
|
||||||
|
originalMessage: MessageChain,
|
||||||
fragmented: Boolean,
|
fragmented: Boolean,
|
||||||
sourceCallback: (Deferred<OnlineMessageSource.Outgoing>) -> Unit
|
sourceCallback: (Deferred<OnlineMessageSource.Outgoing>) -> Unit
|
||||||
): List<OutgoingPacket> {
|
): List<OutgoingPacket> {
|
||||||
return MessageSvcPbSendMsg.createToFriend(client, contact, message, fragmented, sourceCallback)
|
return MessageSvcPbSendMsg.createToFriend(client, contact, message, originalMessage, fragmented, sourceCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun constructSourceForSpecialMessage(
|
override suspend fun constructSourceForSpecialMessage(
|
||||||
finalMessage: MessageChain,
|
originalMessage: MessageChain,
|
||||||
fromAppId: Int
|
fromAppId: Int
|
||||||
): OnlineMessageSource.Outgoing {
|
): OnlineMessageSource.Outgoing {
|
||||||
val receipt: PrivateMessageProcessor.SendPrivateMessageReceipt = withTimeoutOrNull(3000) {
|
val receipt: PrivateMessageProcessor.SendPrivateMessageReceipt = withTimeoutOrNull(3000) {
|
||||||
@ -88,7 +90,7 @@ internal class FriendMessageProtocolStrategy(
|
|||||||
sender = contact.bot,
|
sender = contact.bot,
|
||||||
target = contact,
|
target = contact,
|
||||||
time = contact.bot.clock.server.currentTimeSeconds().toInt(),
|
time = contact.bot.clock.server.currentTimeSeconds().toInt(),
|
||||||
originalMessage = finalMessage
|
originalMessage = originalMessage
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,10 +100,18 @@ internal object StrangerMessageProtocolStrategy : UserMessageProtocolStrategy<St
|
|||||||
client: QQAndroidClient,
|
client: QQAndroidClient,
|
||||||
contact: StrangerImpl,
|
contact: StrangerImpl,
|
||||||
message: MessageChain,
|
message: MessageChain,
|
||||||
|
originalMessage: MessageChain,
|
||||||
fragmented: Boolean,
|
fragmented: Boolean,
|
||||||
sourceCallback: (Deferred<OnlineMessageSource.Outgoing>) -> Unit
|
sourceCallback: (Deferred<OnlineMessageSource.Outgoing>) -> Unit
|
||||||
): List<OutgoingPacket> {
|
): List<OutgoingPacket> {
|
||||||
return MessageSvcPbSendMsg.createToStranger(client, contact, message, fragmented, sourceCallback)
|
return MessageSvcPbSendMsg.createToStranger(
|
||||||
|
client,
|
||||||
|
contact,
|
||||||
|
message,
|
||||||
|
originalMessage,
|
||||||
|
fragmented,
|
||||||
|
sourceCallback
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,10 +120,11 @@ internal object GroupTempMessageProtocolStrategy : UserMessageProtocolStrategy<N
|
|||||||
client: QQAndroidClient,
|
client: QQAndroidClient,
|
||||||
contact: NormalMemberImpl,
|
contact: NormalMemberImpl,
|
||||||
message: MessageChain,
|
message: MessageChain,
|
||||||
|
originalMessage: MessageChain,
|
||||||
fragmented: Boolean,
|
fragmented: Boolean,
|
||||||
sourceCallback: (Deferred<OnlineMessageSource.Outgoing>) -> Unit
|
sourceCallback: (Deferred<OnlineMessageSource.Outgoing>) -> Unit
|
||||||
): List<OutgoingPacket> {
|
): List<OutgoingPacket> {
|
||||||
return MessageSvcPbSendMsg.createToTemp(client, contact, message, fragmented, sourceCallback)
|
return MessageSvcPbSendMsg.createToTemp(client, contact, message, originalMessage, fragmented, sourceCallback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,14 +135,15 @@ internal open class GroupMessageProtocolStrategy(
|
|||||||
client: QQAndroidClient,
|
client: QQAndroidClient,
|
||||||
contact: GroupImpl,
|
contact: GroupImpl,
|
||||||
message: MessageChain,
|
message: MessageChain,
|
||||||
|
originalMessage: MessageChain,
|
||||||
fragmented: Boolean,
|
fragmented: Boolean,
|
||||||
sourceCallback: (Deferred<OnlineMessageSource.Outgoing>) -> Unit
|
sourceCallback: (Deferred<OnlineMessageSource.Outgoing>) -> Unit
|
||||||
): List<OutgoingPacket> {
|
): List<OutgoingPacket> {
|
||||||
return MessageSvcPbSendMsg.createToGroup(client, contact, message, fragmented, sourceCallback)
|
return MessageSvcPbSendMsg.createToGroup(client, contact, message, originalMessage, fragmented, sourceCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun constructSourceForSpecialMessage(
|
override suspend fun constructSourceForSpecialMessage(
|
||||||
finalMessage: MessageChain,
|
originalMessage: MessageChain,
|
||||||
fromAppId: Int
|
fromAppId: Int
|
||||||
): OnlineMessageSource.Outgoing {
|
): OnlineMessageSource.Outgoing {
|
||||||
val receipt: GroupMessageProcessor.SendGroupMessageReceipt = withTimeoutOrNull(3000) {
|
val receipt: GroupMessageProcessor.SendGroupMessageReceipt = withTimeoutOrNull(3000) {
|
||||||
@ -147,7 +159,7 @@ internal open class GroupMessageProtocolStrategy(
|
|||||||
sender = contact.bot,
|
sender = contact.bot,
|
||||||
target = contact,
|
target = contact,
|
||||||
time = contact.bot.clock.server.currentTimeSeconds().toInt(),
|
time = contact.bot.clock.server.currentTimeSeconds().toInt(),
|
||||||
originalMessage = finalMessage
|
originalMessage = originalMessage
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import net.mamoe.mirai.contact.MessageTooLargeException
|
|||||||
import net.mamoe.mirai.internal.contact.AbstractContact
|
import net.mamoe.mirai.internal.contact.AbstractContact
|
||||||
import net.mamoe.mirai.internal.contact.SendMessageStep
|
import net.mamoe.mirai.internal.contact.SendMessageStep
|
||||||
import net.mamoe.mirai.internal.message.source.ensureSequenceIdAvailable
|
import net.mamoe.mirai.internal.message.source.ensureSequenceIdAvailable
|
||||||
|
import net.mamoe.mirai.internal.network.component.ComponentStorage
|
||||||
import net.mamoe.mirai.internal.network.handler.logger
|
import net.mamoe.mirai.internal.network.handler.logger
|
||||||
import net.mamoe.mirai.internal.pipeline.AbstractProcessorPipeline
|
import net.mamoe.mirai.internal.pipeline.AbstractProcessorPipeline
|
||||||
import net.mamoe.mirai.internal.pipeline.PipelineConfiguration
|
import net.mamoe.mirai.internal.pipeline.PipelineConfiguration
|
||||||
@ -104,6 +105,11 @@ internal interface OutgoingMessagePipelineContext :
|
|||||||
*/
|
*/
|
||||||
val ORIGINAL_MESSAGE = TypeKey<Message>("originalMessage")
|
val ORIGINAL_MESSAGE = TypeKey<Message>("originalMessage")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You should only use [ORIGINAL_MESSAGE_AS_CHAIN] if you can't use [ORIGINAL_MESSAGE]
|
||||||
|
*/
|
||||||
|
val ORIGINAL_MESSAGE_AS_CHAIN = TypeKey<MessageChain>("originalMessageAsChain")
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Message target
|
* Message target
|
||||||
@ -112,9 +118,8 @@ internal interface OutgoingMessagePipelineContext :
|
|||||||
|
|
||||||
val STEP = TypeKey<SendMessageStep>("step")
|
val STEP = TypeKey<SendMessageStep>("step")
|
||||||
|
|
||||||
val PROTOCOL_STRATEGY = TypeKey<MessageProtocolStrategy<AbstractContact>>("protocolStrategy")
|
val COMPONENTS = TypeKey<ComponentStorage>("components")
|
||||||
|
val OutgoingMessagePipelineContext.components: ComponentStorage get() = attributes[COMPONENTS]
|
||||||
val HIGHWAY_UPLOADER = TypeKey<HighwayUploader>("highwayUploader")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
package net.mamoe.mirai.internal.network.component
|
package net.mamoe.mirai.internal.network.component
|
||||||
|
|
||||||
import org.jetbrains.annotations.TestOnly
|
import org.jetbrains.annotations.TestOnly
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mediator for [component][ComponentKey]s accessing each other.
|
* Mediator for [component][ComponentKey]s accessing each other.
|
||||||
@ -38,6 +40,7 @@ internal interface ComponentStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun buildComponentStorage(builderAction: MutableComponentStorage.() -> Unit): ComponentStorage {
|
internal fun buildComponentStorage(builderAction: MutableComponentStorage.() -> Unit): ComponentStorage {
|
||||||
|
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
|
||||||
return ConcurrentComponentStorage(builderAction)
|
return ConcurrentComponentStorage(builderAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||||
*
|
*
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
@ -12,10 +12,11 @@ package net.mamoe.mirai.internal.network.components
|
|||||||
import net.mamoe.mirai.internal.QQAndroidBot
|
import net.mamoe.mirai.internal.QQAndroidBot
|
||||||
import net.mamoe.mirai.internal.network.component.ComponentKey
|
import net.mamoe.mirai.internal.network.component.ComponentKey
|
||||||
import net.mamoe.mirai.utils.Clock
|
import net.mamoe.mirai.utils.Clock
|
||||||
|
import net.mamoe.mirai.utils.lateinitMutableProperty
|
||||||
|
|
||||||
internal class ClockHolder {
|
internal open class ClockHolder {
|
||||||
val local: Clock get() = Clock.SystemDefault
|
open val local: Clock get() = Clock.SystemDefault
|
||||||
var server: Clock = local
|
open var server: Clock by lateinitMutableProperty { local }
|
||||||
|
|
||||||
companion object : ComponentKey<ClockHolder> {
|
companion object : ComponentKey<ClockHolder> {
|
||||||
val QQAndroidBot.clock get() = components[ClockHolder]
|
val QQAndroidBot.clock get() = components[ClockHolder]
|
||||||
|
@ -186,6 +186,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
|||||||
client: QQAndroidClient,
|
client: QQAndroidClient,
|
||||||
target: Stranger,
|
target: Stranger,
|
||||||
message: MessageChain,
|
message: MessageChain,
|
||||||
|
originalMessage: MessageChain,
|
||||||
fragmented: Boolean,
|
fragmented: Boolean,
|
||||||
source: (OnlineMessageSourceToStrangerImpl) -> Unit,
|
source: (OnlineMessageSourceToStrangerImpl) -> Unit,
|
||||||
): List<OutgoingPacket> {
|
): List<OutgoingPacket> {
|
||||||
@ -226,7 +227,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
|||||||
target = target,
|
target = target,
|
||||||
time = client.bot.clock.server.currentTimeSeconds().toInt(),
|
time = client.bot.clock.server.currentTimeSeconds().toInt(),
|
||||||
sequenceIds = sequenceIds.get(),
|
sequenceIds = sequenceIds.get(),
|
||||||
originalMessage = message,
|
originalMessage = originalMessage,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -242,6 +243,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
|||||||
client: QQAndroidClient,
|
client: QQAndroidClient,
|
||||||
targetFriend: Friend,
|
targetFriend: Friend,
|
||||||
message: MessageChain,
|
message: MessageChain,
|
||||||
|
originalMessage: MessageChain,
|
||||||
fragmented: Boolean,
|
fragmented: Boolean,
|
||||||
crossinline sourceCallback: (OnlineMessageSourceToFriendImpl) -> Unit,
|
crossinline sourceCallback: (OnlineMessageSourceToFriendImpl) -> Unit,
|
||||||
): List<OutgoingPacket> {
|
): List<OutgoingPacket> {
|
||||||
@ -290,7 +292,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
|||||||
target = targetFriend,
|
target = targetFriend,
|
||||||
time = client.bot.clock.server.currentTimeSeconds().toInt(),
|
time = client.bot.clock.server.currentTimeSeconds().toInt(),
|
||||||
sequenceIds = sequenceIds.get(),
|
sequenceIds = sequenceIds.get(),
|
||||||
originalMessage = message,
|
originalMessage = originalMessage,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -372,6 +374,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
|||||||
client: QQAndroidClient,
|
client: QQAndroidClient,
|
||||||
targetGroup: Group,
|
targetGroup: Group,
|
||||||
message: MessageChain,
|
message: MessageChain,
|
||||||
|
originalMessage: MessageChain,
|
||||||
fragmented: Boolean,
|
fragmented: Boolean,
|
||||||
crossinline sourceCallback: (OnlineMessageSourceToGroupImpl) -> Unit,
|
crossinline sourceCallback: (OnlineMessageSourceToGroupImpl) -> Unit,
|
||||||
): List<OutgoingPacket> {
|
): List<OutgoingPacket> {
|
||||||
@ -422,7 +425,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
|||||||
sender = client.bot,
|
sender = client.bot,
|
||||||
target = targetGroup,
|
target = targetGroup,
|
||||||
time = client.bot.clock.server.currentTimeSeconds().toInt(),
|
time = client.bot.clock.server.currentTimeSeconds().toInt(),
|
||||||
originalMessage = message, //,
|
originalMessage = originalMessage, //,
|
||||||
// sourceMessage = message
|
// sourceMessage = message
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -500,6 +503,7 @@ internal inline fun MessageSvcPbSendMsg.createToTemp(
|
|||||||
client: QQAndroidClient,
|
client: QQAndroidClient,
|
||||||
member: Member,
|
member: Member,
|
||||||
message: MessageChain,
|
message: MessageChain,
|
||||||
|
originalMessage: MessageChain,
|
||||||
fragmented: Boolean,
|
fragmented: Boolean,
|
||||||
crossinline sourceCallback: (Deferred<OnlineMessageSourceToTempImpl>) -> Unit,
|
crossinline sourceCallback: (Deferred<OnlineMessageSourceToTempImpl>) -> Unit,
|
||||||
): List<OutgoingPacket> {
|
): List<OutgoingPacket> {
|
||||||
@ -512,7 +516,7 @@ internal inline fun MessageSvcPbSendMsg.createToTemp(
|
|||||||
target = member,
|
target = member,
|
||||||
time = client.bot.clock.server.currentTimeSeconds().toInt(),
|
time = client.bot.clock.server.currentTimeSeconds().toInt(),
|
||||||
sequenceIds = intArrayOf(client.atomicNextMessageSequenceId()),
|
sequenceIds = intArrayOf(client.atomicNextMessageSequenceId()),
|
||||||
originalMessage = message,
|
originalMessage = originalMessage,
|
||||||
)
|
)
|
||||||
sourceCallback(CompletableDeferred(source))
|
sourceCallback(CompletableDeferred(source))
|
||||||
return createToTempImpl(
|
return createToTempImpl(
|
||||||
@ -526,7 +530,8 @@ internal inline fun MessageSvcPbSendMsg.createToTemp(
|
|||||||
internal inline fun MessageSvcPbSendMsg.createToStranger(
|
internal inline fun MessageSvcPbSendMsg.createToStranger(
|
||||||
client: QQAndroidClient,
|
client: QQAndroidClient,
|
||||||
stranger: Stranger,
|
stranger: Stranger,
|
||||||
message: MessageChain,
|
message: MessageChain, // to send
|
||||||
|
originalMessage: MessageChain, // for Receipt
|
||||||
fragmented: Boolean,
|
fragmented: Boolean,
|
||||||
crossinline sourceCallback: (Deferred<OnlineMessageSourceToStrangerImpl>) -> Unit,
|
crossinline sourceCallback: (Deferred<OnlineMessageSourceToStrangerImpl>) -> Unit,
|
||||||
): List<OutgoingPacket> {
|
): List<OutgoingPacket> {
|
||||||
@ -537,6 +542,7 @@ internal inline fun MessageSvcPbSendMsg.createToStranger(
|
|||||||
client,
|
client,
|
||||||
stranger,
|
stranger,
|
||||||
message,
|
message,
|
||||||
|
originalMessage,
|
||||||
fragmented,
|
fragmented,
|
||||||
) { sourceCallback(CompletableDeferred(it)) }
|
) { sourceCallback(CompletableDeferred(it)) }
|
||||||
}
|
}
|
||||||
@ -545,6 +551,7 @@ internal inline fun MessageSvcPbSendMsg.createToFriend(
|
|||||||
client: QQAndroidClient,
|
client: QQAndroidClient,
|
||||||
qq: Friend,
|
qq: Friend,
|
||||||
message: MessageChain,
|
message: MessageChain,
|
||||||
|
originalMessage: MessageChain,
|
||||||
fragmented: Boolean,
|
fragmented: Boolean,
|
||||||
crossinline sourceCallback: (Deferred<OnlineMessageSourceToFriendImpl>) -> Unit,
|
crossinline sourceCallback: (Deferred<OnlineMessageSourceToFriendImpl>) -> Unit,
|
||||||
): List<OutgoingPacket> {
|
): List<OutgoingPacket> {
|
||||||
@ -555,6 +562,7 @@ internal inline fun MessageSvcPbSendMsg.createToFriend(
|
|||||||
client,
|
client,
|
||||||
qq,
|
qq,
|
||||||
message,
|
message,
|
||||||
|
originalMessage,
|
||||||
fragmented,
|
fragmented,
|
||||||
) { sourceCallback(CompletableDeferred(it)) }
|
) { sourceCallback(CompletableDeferred(it)) }
|
||||||
}
|
}
|
||||||
@ -564,6 +572,7 @@ internal inline fun MessageSvcPbSendMsg.createToGroup(
|
|||||||
client: QQAndroidClient,
|
client: QQAndroidClient,
|
||||||
group: Group,
|
group: Group,
|
||||||
message: MessageChain,
|
message: MessageChain,
|
||||||
|
originalMessage: MessageChain,
|
||||||
fragmented: Boolean,
|
fragmented: Boolean,
|
||||||
crossinline sourceCallback: (Deferred<OnlineMessageSourceToGroupImpl>) -> Unit,
|
crossinline sourceCallback: (Deferred<OnlineMessageSourceToGroupImpl>) -> Unit,
|
||||||
): List<OutgoingPacket> {
|
): List<OutgoingPacket> {
|
||||||
@ -574,6 +583,7 @@ internal inline fun MessageSvcPbSendMsg.createToGroup(
|
|||||||
client,
|
client,
|
||||||
group,
|
group,
|
||||||
message,
|
message,
|
||||||
|
originalMessage,
|
||||||
fragmented,
|
fragmented,
|
||||||
) { sourceCallback(CompletableDeferred(it)) }
|
) { sourceCallback(CompletableDeferred(it)) }
|
||||||
}
|
}
|
@ -33,8 +33,11 @@ internal class MessageProtocolFacadeTest : AbstractTest() {
|
|||||||
PttMessageProtocol
|
PttMessageProtocol
|
||||||
RichMessageProtocol
|
RichMessageProtocol
|
||||||
TextProtocol
|
TextProtocol
|
||||||
UnsupportedMessageProtocol
|
|
||||||
VipFaceProtocol
|
VipFaceProtocol
|
||||||
|
ForwardMessageProtocol
|
||||||
|
LongMessageProtocol
|
||||||
|
UnsupportedMessageProtocol
|
||||||
|
GeneralMessageSenderProtocol
|
||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
MessageProtocolFacadeImpl().loaded.joinToString("\n") { it::class.simpleName.toString() }
|
MessageProtocolFacadeImpl().loaded.joinToString("\n") { it::class.simpleName.toString() }
|
||||||
)
|
)
|
||||||
|
@ -12,8 +12,12 @@ package net.mamoe.mirai.internal.message.protocol.impl
|
|||||||
import kotlinx.coroutines.CompletableDeferred
|
import kotlinx.coroutines.CompletableDeferred
|
||||||
import kotlinx.coroutines.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.io.core.ByteReadPacket
|
||||||
import net.mamoe.mirai.contact.ContactOrBot
|
import net.mamoe.mirai.contact.ContactOrBot
|
||||||
|
import net.mamoe.mirai.contact.Friend
|
||||||
import net.mamoe.mirai.contact.Group
|
import net.mamoe.mirai.contact.Group
|
||||||
|
import net.mamoe.mirai.internal.AbstractBot
|
||||||
|
import net.mamoe.mirai.internal.contact.AbstractContact
|
||||||
import net.mamoe.mirai.internal.message.data.inferMessageSourceKind
|
import net.mamoe.mirai.internal.message.data.inferMessageSourceKind
|
||||||
import net.mamoe.mirai.internal.message.protocol.MessageProtocol
|
import net.mamoe.mirai.internal.message.protocol.MessageProtocol
|
||||||
import net.mamoe.mirai.internal.message.protocol.MessageProtocolFacade
|
import net.mamoe.mirai.internal.message.protocol.MessageProtocolFacade
|
||||||
@ -21,17 +25,31 @@ import net.mamoe.mirai.internal.message.protocol.MessageProtocolFacadeImpl
|
|||||||
import net.mamoe.mirai.internal.message.protocol.decode.MessageDecoderPipelineImpl
|
import net.mamoe.mirai.internal.message.protocol.decode.MessageDecoderPipelineImpl
|
||||||
import net.mamoe.mirai.internal.message.protocol.decodeAndRefineLight
|
import net.mamoe.mirai.internal.message.protocol.decodeAndRefineLight
|
||||||
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderPipelineImpl
|
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderPipelineImpl
|
||||||
|
import net.mamoe.mirai.internal.message.protocol.outgoing.HighwayUploader
|
||||||
|
import net.mamoe.mirai.internal.message.protocol.outgoing.MessageProtocolStrategy
|
||||||
|
import net.mamoe.mirai.internal.message.source.OnlineMessageSourceToFriendImpl
|
||||||
|
import net.mamoe.mirai.internal.message.source.OnlineMessageSourceToGroupImpl
|
||||||
|
import net.mamoe.mirai.internal.network.Packet
|
||||||
|
import net.mamoe.mirai.internal.network.QQAndroidClient
|
||||||
|
import net.mamoe.mirai.internal.network.component.ComponentStorage
|
||||||
|
import net.mamoe.mirai.internal.network.components.ClockHolder
|
||||||
import net.mamoe.mirai.internal.network.framework.AbstractMockNetworkHandlerTest
|
import net.mamoe.mirai.internal.network.framework.AbstractMockNetworkHandlerTest
|
||||||
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
||||||
|
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
|
||||||
|
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
|
||||||
import net.mamoe.mirai.internal.notice.processors.GroupExtensions
|
import net.mamoe.mirai.internal.notice.processors.GroupExtensions
|
||||||
import net.mamoe.mirai.message.data.MessageChain
|
import net.mamoe.mirai.internal.test.runBlockingUnit
|
||||||
import net.mamoe.mirai.message.data.MessageChainBuilder
|
import net.mamoe.mirai.message.data.*
|
||||||
import net.mamoe.mirai.message.data.MessageSourceKind
|
import net.mamoe.mirai.utils.Clock
|
||||||
import net.mamoe.mirai.message.data.SingleMessage
|
import net.mamoe.mirai.utils.md5
|
||||||
|
import net.mamoe.mirai.utils.toUHexString
|
||||||
import org.junit.jupiter.api.AfterEach
|
import org.junit.jupiter.api.AfterEach
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
|
import kotlin.test.Asserter
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.asserter
|
||||||
|
|
||||||
internal abstract class AbstractMessageProtocolTest : AbstractMockNetworkHandlerTest(), GroupExtensions {
|
internal abstract class AbstractMessageProtocolTest : AbstractMockNetworkHandlerTest(), GroupExtensions {
|
||||||
|
|
||||||
@ -60,7 +78,10 @@ internal abstract class AbstractMessageProtocolTest : AbstractMockNetworkHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected fun facadeOf(vararg protocols: MessageProtocol): MessageProtocolFacade {
|
protected fun facadeOf(vararg protocols: MessageProtocol): MessageProtocolFacade {
|
||||||
return MessageProtocolFacadeImpl(protocols.toList())
|
return MessageProtocolFacadeImpl(
|
||||||
|
protocols.toList(),
|
||||||
|
remark = "MessageProtocolFacade with ${protocols.joinToString { it::class.simpleName!! }}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
@ -211,5 +232,121 @@ internal abstract class AbstractMessageProtocolTest : AbstractMockNetworkHandler
|
|||||||
// sending
|
// sending
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
init {
|
||||||
|
components[MessageProtocolStrategy] = object : MessageProtocolStrategy<AbstractContact> {
|
||||||
|
override suspend fun sendPacket(bot: AbstractBot, packet: OutgoingPacket): Packet {
|
||||||
|
assertEquals(0x123, packet.sequenceId)
|
||||||
|
return MessageSvcPbSendMsg.Response.SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun createPacketsForGeneralMessage(
|
||||||
|
client: QQAndroidClient,
|
||||||
|
contact: AbstractContact,
|
||||||
|
message: MessageChain,
|
||||||
|
originalMessage: MessageChain,
|
||||||
|
fragmented: Boolean,
|
||||||
|
sourceCallback: (Deferred<OnlineMessageSource.Outgoing>) -> Unit
|
||||||
|
): List<OutgoingPacket> {
|
||||||
|
sourceCallback(CompletableDeferred(constructSourceForSpecialMessage(originalMessage, 1000)))
|
||||||
|
return listOf(OutgoingPacket("Test", "test", 0x123, ByteReadPacket.Empty))
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun constructSourceForSpecialMessage(
|
||||||
|
originalMessage: MessageChain,
|
||||||
|
fromAppId: Int
|
||||||
|
): OnlineMessageSource.Outgoing {
|
||||||
|
return when (val defaultTarget = defaultTarget) {
|
||||||
|
is Group -> OnlineMessageSourceToGroupImpl(
|
||||||
|
coroutineScope = defaultTarget,
|
||||||
|
internalIds = intArrayOf(1),
|
||||||
|
time = 1,
|
||||||
|
originalMessage = originalMessage,
|
||||||
|
sender = bot,
|
||||||
|
target = defaultTarget
|
||||||
|
)
|
||||||
|
is Friend -> OnlineMessageSourceToFriendImpl(
|
||||||
|
sequenceIds = intArrayOf(1),
|
||||||
|
internalIds = intArrayOf(1),
|
||||||
|
time = 1,
|
||||||
|
originalMessage = originalMessage,
|
||||||
|
sender = bot,
|
||||||
|
target = defaultTarget
|
||||||
|
)
|
||||||
|
else -> error("Unexpected target: $defaultTarget")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
components[HighwayUploader] = object : HighwayUploader {
|
||||||
|
override suspend fun uploadMessages(
|
||||||
|
contact: AbstractContact,
|
||||||
|
components: ComponentStorage,
|
||||||
|
nodes: Collection<ForwardMessage.INode>,
|
||||||
|
isLong: Boolean,
|
||||||
|
senderName: String
|
||||||
|
): String {
|
||||||
|
return "(size=${nodes.size})${
|
||||||
|
nodes.joinToString().replace(bot.id.toString(), "123123").md5().toUHexString("")
|
||||||
|
}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
components[ClockHolder] = object : ClockHolder() {
|
||||||
|
override val local: Clock = object : Clock {
|
||||||
|
override fun currentTimeMillis(): Long = 160023456
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun runWithFacade(action: suspend MessageProtocolFacade.() -> Unit) {
|
||||||
|
runBlockingUnit {
|
||||||
|
facadeOf(*protocols).run { action() }
|
||||||
|
MessageProtocolFacade.INSTANCE.run { action() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun assertMessageEquals(expected: Message, actual: Message) {
|
||||||
|
val expectedChain = expected.toMessageChain()
|
||||||
|
val actualChain = actual.toMessageChain()
|
||||||
|
|
||||||
|
val message = String.format(
|
||||||
|
"""
|
||||||
|
Expected: %s
|
||||||
|
|
||||||
|
Actual: %s
|
||||||
|
""".trimIndent(), expectedChain.render(), actualChain.render()
|
||||||
|
)
|
||||||
|
assertEquals(expectedChain.size, actualChain.size, message)
|
||||||
|
asserter.assertEquals(message, expectedChain, actualChain)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun MessageProtocolFacade.assertMessageEquals(expected: Message, actual: Message) {
|
||||||
|
val expectedChain = expected.toMessageChain()
|
||||||
|
val actualChain = actual.toMessageChain()
|
||||||
|
|
||||||
|
val message = String.format(
|
||||||
|
"""
|
||||||
|
Facade: ${this.remark}
|
||||||
|
Expected: %s
|
||||||
|
|
||||||
|
Actual: %s
|
||||||
|
""".trimIndent(), expectedChain.render(), actualChain.render()
|
||||||
|
)
|
||||||
|
assertEquals(expectedChain.size, actualChain.size, message)
|
||||||
|
asserter.assertEquals(message, expectedChain, actualChain)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun Asserter.assertEquals(crossinline message: () -> String, expected: Any?, actual: Any?) {
|
||||||
|
assertTrue({ message() + ". Expected <$expected>, actual <$actual>." }, actual == expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun MessageChain.render(): String = buildString {
|
||||||
|
appendLine("size = $size")
|
||||||
|
for (singleMessage in distinct()) {
|
||||||
|
val count = this@render.count { it == singleMessage }
|
||||||
|
appendLine("$count x [${singleMessage::class.simpleName}] $singleMessage")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||||
|
*
|
||||||
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
|
*
|
||||||
|
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.internal.message.protocol.impl
|
||||||
|
|
||||||
|
import net.mamoe.mirai.contact.MemberPermission
|
||||||
|
import net.mamoe.mirai.internal.message.LightMessageRefiner.dropMiraiInternalFlags
|
||||||
|
import net.mamoe.mirai.internal.message.data.LongMessageInternal
|
||||||
|
import net.mamoe.mirai.internal.message.flags.ForceAsLongMessage
|
||||||
|
import net.mamoe.mirai.internal.message.flags.IgnoreLengthCheck
|
||||||
|
import net.mamoe.mirai.internal.message.protocol.MessageProtocol
|
||||||
|
import net.mamoe.mirai.message.data.Image
|
||||||
|
import net.mamoe.mirai.message.data.repeat
|
||||||
|
import net.mamoe.mirai.message.data.toPlainText
|
||||||
|
import net.mamoe.mirai.utils.castUp
|
||||||
|
import net.mamoe.mirai.utils.getRandomString
|
||||||
|
import kotlin.random.Random
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
internal class LongMessageProtocolTest : AbstractMessageProtocolTest() {
|
||||||
|
override val protocols: Array<out MessageProtocol> =
|
||||||
|
arrayOf(
|
||||||
|
TextProtocol(),
|
||||||
|
ImageProtocol(),
|
||||||
|
LongMessageProtocol(),
|
||||||
|
GeneralMessageSenderProtocol(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
defaultTarget = bot.addGroup(123, 1230003).apply {
|
||||||
|
addMember(1230003, "user3", MemberPermission.OWNER)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun precondition() {
|
||||||
|
assertEquals(getRandomString(5000, Random(1)), getRandomString(5000, Random(1)))
|
||||||
|
assertMessageEquals(
|
||||||
|
"test".toPlainText() + getRandomString(5000, Random(1)) +
|
||||||
|
Image("{40A7C56B-45C9-23AE-0CFA-23F095B71035}.jpg").repeat(200),
|
||||||
|
"test".toPlainText() + getRandomString(5000, Random(1)) +
|
||||||
|
Image("{40A7C56B-45C9-23AE-0CFA-23F095B71035}.jpg").repeat(200)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `can convert messages to LongMessageInternal`() {
|
||||||
|
var message = "test".toPlainText() + getRandomString(5000, Random(1)) +
|
||||||
|
Image("{40A7C56B-45C9-23AE-0CFA-23F095B71035}.jpg").repeat(200)
|
||||||
|
|
||||||
|
message += IgnoreLengthCheck
|
||||||
|
message += ForceAsLongMessage
|
||||||
|
|
||||||
|
runWithFacade {
|
||||||
|
preprocessAndSendOutgoingImpl(defaultTarget.castUp(), message, components).let { (context, receipts) ->
|
||||||
|
val receipt = receipts.single()
|
||||||
|
assertMessageEquals(message.dropMiraiInternalFlags(), receipt.source.originalMessage)
|
||||||
|
|
||||||
|
assertMessageEquals(
|
||||||
|
LongMessageInternal(
|
||||||
|
"""
|
||||||
|
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
|
||||||
|
<msg serviceID="35" templateID="1" action="viewMultiMsg"
|
||||||
|
brief="testqGnJ1R..."
|
||||||
|
m_resid="(size=1)DBD2AB20196EEB631C95DEF40E20C709"
|
||||||
|
m_fileName="160023" sourceMsgId="0" url=""
|
||||||
|
flag="3" adverSign="0" multiMsgFlag="1">
|
||||||
|
<item layout="1">
|
||||||
|
<title>testqGnJ1R...</title>
|
||||||
|
<hr hidden="false" style="0"/>
|
||||||
|
<summary>点击查看完整消息</summary>
|
||||||
|
</item>
|
||||||
|
<source name="聊天记录" icon="" action="" appid="-1"/>
|
||||||
|
</msg>
|
||||||
|
""".trimIndent(), "(size=1)DBD2AB20196EEB631C95DEF40E20C709"
|
||||||
|
) + IgnoreLengthCheck + ForceAsLongMessage, context.currentMessageChain
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,10 @@ import net.mamoe.mirai.internal.MockBot
|
|||||||
import net.mamoe.mirai.internal.QQAndroidBot
|
import net.mamoe.mirai.internal.QQAndroidBot
|
||||||
import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage
|
import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage
|
||||||
import net.mamoe.mirai.internal.network.components.EventDispatcher
|
import net.mamoe.mirai.internal.network.components.EventDispatcher
|
||||||
|
import net.mamoe.mirai.internal.network.components.PacketLoggingStrategy
|
||||||
|
import net.mamoe.mirai.internal.network.components.PacketLoggingStrategyImpl
|
||||||
import net.mamoe.mirai.internal.network.components.SsoProcessor
|
import net.mamoe.mirai.internal.network.components.SsoProcessor
|
||||||
|
import net.mamoe.mirai.internal.network.framework.components.TestImagePatcher
|
||||||
import net.mamoe.mirai.internal.network.framework.components.TestSsoProcessor
|
import net.mamoe.mirai.internal.network.framework.components.TestSsoProcessor
|
||||||
import net.mamoe.mirai.internal.network.handler.NetworkHandler
|
import net.mamoe.mirai.internal.network.handler.NetworkHandler
|
||||||
import net.mamoe.mirai.internal.network.handler.state.LoggingStateObserver
|
import net.mamoe.mirai.internal.network.handler.state.LoggingStateObserver
|
||||||
@ -61,7 +64,8 @@ internal abstract class AbstractMockNetworkHandlerTest : AbstractNetworkHandlerT
|
|||||||
MiraiLogger.Factory.create(SafeStateObserver::class, "StateObserver errors")
|
MiraiLogger.Factory.create(SafeStateObserver::class, "StateObserver errors")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
set(ImagePatcher, ImagePatcher())
|
set(ImagePatcher, TestImagePatcher())
|
||||||
|
set(PacketLoggingStrategy, PacketLoggingStrategyImpl(bot))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun NetworkHandler.assertState(state: NetworkHandler.State) {
|
fun NetworkHandler.assertState(state: NetworkHandler.State) {
|
||||||
|
@ -16,7 +16,9 @@ import net.mamoe.mirai.internal.message.protocol.impl.GeneralMessageSenderProtoc
|
|||||||
import net.mamoe.mirai.internal.message.protocol.outgoing.*
|
import net.mamoe.mirai.internal.message.protocol.outgoing.*
|
||||||
import net.mamoe.mirai.internal.message.source.OnlineMessageSourceToGroupImpl
|
import net.mamoe.mirai.internal.message.source.OnlineMessageSourceToGroupImpl
|
||||||
import net.mamoe.mirai.internal.message.source.createMessageReceipt
|
import net.mamoe.mirai.internal.message.source.createMessageReceipt
|
||||||
|
import net.mamoe.mirai.internal.network.component.ComponentStorage
|
||||||
import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage
|
import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage
|
||||||
|
import net.mamoe.mirai.internal.network.components.ClockHolder
|
||||||
import net.mamoe.mirai.internal.notice.processors.GroupExtensions
|
import net.mamoe.mirai.internal.notice.processors.GroupExtensions
|
||||||
import net.mamoe.mirai.internal.pipeline.replaceProcessor
|
import net.mamoe.mirai.internal.pipeline.replaceProcessor
|
||||||
import net.mamoe.mirai.internal.test.AbstractTest
|
import net.mamoe.mirai.internal.test.AbstractTest
|
||||||
@ -24,6 +26,7 @@ import net.mamoe.mirai.internal.test.runBlockingUnit
|
|||||||
import net.mamoe.mirai.message.data.ForwardMessage
|
import net.mamoe.mirai.message.data.ForwardMessage
|
||||||
import net.mamoe.mirai.message.data.buildForwardMessage
|
import net.mamoe.mirai.message.data.buildForwardMessage
|
||||||
import net.mamoe.mirai.message.data.toMessageChain
|
import net.mamoe.mirai.message.data.toMessageChain
|
||||||
|
import net.mamoe.mirai.utils.Clock
|
||||||
import net.mamoe.mirai.utils.currentTimeSeconds
|
import net.mamoe.mirai.utils.currentTimeSeconds
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -79,15 +82,21 @@ internal class MessageReceiptTest : AbstractTest(), GroupExtensions {
|
|||||||
set(HighwayUploader, object : HighwayUploader {
|
set(HighwayUploader, object : HighwayUploader {
|
||||||
override suspend fun uploadMessages(
|
override suspend fun uploadMessages(
|
||||||
contact: AbstractContact,
|
contact: AbstractContact,
|
||||||
strategy: MessageProtocolStrategy<*>,
|
components: ComponentStorage,
|
||||||
nodes: Collection<ForwardMessage.INode>,
|
nodes: Collection<ForwardMessage.INode>,
|
||||||
isLong: Boolean,
|
isLong: Boolean,
|
||||||
facade: MessageProtocolFacade,
|
|
||||||
senderName: String
|
senderName: String
|
||||||
): String {
|
): String {
|
||||||
return "id"
|
return "id"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
set(ClockHolder, object : ClockHolder() {
|
||||||
|
override val local: Clock = object : Clock {
|
||||||
|
override fun currentTimeMillis(): Long {
|
||||||
|
return 160023456
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
assertIs<ForwardMessage>(result.source.originalMessage[ForwardMessage])
|
assertIs<ForwardMessage>(result.source.originalMessage[ForwardMessage])
|
||||||
|
Loading…
Reference in New Issue
Block a user