Move toMessageChain and toRichTextElems to MessageProtocolFacade

This commit is contained in:
Him188 2022-04-30 17:44:38 +01:00
parent 089b403a06
commit 7e87376930
15 changed files with 174 additions and 101 deletions

View File

@ -298,7 +298,7 @@ internal abstract class SendMessageHandler<C : Contact> {
/**
* 处理需要 `suspend` 操作的消息转换. 这个转换只会在发送消息时进行, 而不会在处理合并转发 [net.mamoe.mirai.internal.network.protocol.packet.chat.calculateValidationData] 等其他操作时进行.
* 在发包前还会进行最后的 [net.mamoe.mirai.internal.message.toRichTextElems] 转换, 这个转换会为所有操作使用.
* 在发包前还会进行最后的 [net.mamoe.mirai.internal.message.protocol.MessageProtocolFacade.encode] 转换, 这个转换会为所有操作使用.
*
* - [ForwardMessage] -> [ForwardMessageInternal] (by uploading through highway)
* - ... any others for future

View File

@ -17,18 +17,13 @@ import net.mamoe.mirai.internal.message.ReceiveMessageTransformer.joinToMessageC
import net.mamoe.mirai.internal.message.ReceiveMessageTransformer.toAudio
import net.mamoe.mirai.internal.message.data.LongMessageInternal
import net.mamoe.mirai.internal.message.data.OnlineAudioImpl
import net.mamoe.mirai.internal.message.protocol.MessageDecoderContext.Companion.BOT
import net.mamoe.mirai.internal.message.protocol.MessageDecoderContext.Companion.GROUP_ID
import net.mamoe.mirai.internal.message.protocol.MessageDecoderContext.Companion.MESSAGE_SOURCE_KIND
import net.mamoe.mirai.internal.message.protocol.MessageProtocolFacade
import net.mamoe.mirai.internal.message.protocol.impl.PokeMessageProtocol.Companion.UNSUPPORTED_POKE_MESSAGE_PLAIN
import net.mamoe.mirai.internal.message.protocol.impl.RichMessageProtocol.Companion.UNSUPPORTED_MERGED_MESSAGE_PLAIN
import net.mamoe.mirai.internal.message.source.*
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
import net.mamoe.mirai.internal.utils.runCoroutineInPlace
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.utils.buildTypeSafeMap
import net.mamoe.mirai.utils.toLongUnsigned
/**
@ -155,17 +150,7 @@ internal object ReceiveMessageTransformer {
bot: Bot,
builder: MessageChainBuilder,
) {
val pipeline = MessageProtocolFacade.decoderPipeline
val attributes = buildTypeSafeMap {
set(BOT, bot)
set(MESSAGE_SOURCE_KIND, messageSourceKind)
set(GROUP_ID, groupIdOrZero)
}
runCoroutineInPlace {
elements.forEach { builder.addAll(pipeline.process(it, attributes)) }
}
return MessageProtocolFacade.decode(elements, groupIdOrZero, messageSourceKind, bot, builder)
}
fun MessageChainBuilder.compressContinuousPlainText() {

View File

@ -12,8 +12,8 @@ package net.mamoe.mirai.internal.message.data
import io.ktor.utils.io.core.*
import net.mamoe.mirai.internal.contact.SendMessageHandler
import net.mamoe.mirai.internal.contact.takeSingleContent
import net.mamoe.mirai.internal.message.protocol.MessageProtocolFacade
import net.mamoe.mirai.internal.message.source.MessageSourceInternal
import net.mamoe.mirai.internal.message.toRichTextElems
import net.mamoe.mirai.internal.network.QQAndroidClient
import net.mamoe.mirai.internal.network.highway.Highway
import net.mamoe.mirai.internal.network.highway.ResourceKind
@ -164,11 +164,11 @@ internal open class MultiMsgUploader(
),
msgBody = ImMsgBody.MsgBody(
richText = ImMsgBody.RichText(
elems = msgChain.toRichTextElems(
handler.contact,
elems = MessageProtocolFacade.encode(
msgChain, messageTarget = handler.contact,
withGeneralFlags = false,
isForward = true,
).toMutableList()
isForward = true
)
)
)
)

View File

@ -9,39 +9,8 @@
package net.mamoe.mirai.internal.message
import net.mamoe.mirai.contact.ContactOrBot
import net.mamoe.mirai.internal.message.protocol.MessageEncoderContext
import net.mamoe.mirai.internal.message.protocol.MessageProtocolFacade
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.internal.utils.runCoroutineInPlace
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.PlainText
import net.mamoe.mirai.utils.buildTypeSafeMap
internal val UNSUPPORTED_VOICE_MESSAGE_PLAIN = PlainText("收到语音消息你需要升级到最新版QQ才能接收升级地址https://im.qq.com")
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
internal fun MessageChain.toRichTextElems(
messageTarget: ContactOrBot?,
withGeneralFlags: Boolean,
isForward: Boolean = false,
): MutableList<ImMsgBody.Elem> {
val originalMessage = this
val pipeline = MessageProtocolFacade.encoderPipeline
val attributes = buildTypeSafeMap {
set(MessageEncoderContext.CONTACT, messageTarget)
set(MessageEncoderContext.ORIGINAL_MESSAGE, originalMessage)
set(MessageEncoderContext.ADD_GENERAL_FLAGS, withGeneralFlags)
set(MessageEncoderContext.IS_FORWARD, isForward)
}
val builder = ArrayList<ImMsgBody.Elem>(originalMessage.size)
runCoroutineInPlace {
originalMessage.forEach { builder.addAll(pipeline.process(it, attributes)) }
}
return builder
}

View File

@ -13,20 +13,13 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.internal.pipeline.AbstractProcessorPipeline
import net.mamoe.mirai.internal.pipeline.PipelineConfiguration
import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.TypeSafeMap
import net.mamoe.mirai.utils.systemProp
import net.mamoe.mirai.utils.withSwitch
private val defaultTraceLogging: MiraiLogger by lazy {
MiraiLogger.Factory.create(MessageDecoderPipelineImpl::class, "MessageDecoderPipeline")
.withSwitch(systemProp("mirai.message.decoder.pipeline.log.full", false))
}
import net.mamoe.mirai.utils.*
internal open class MessageDecoderPipelineImpl :
AbstractProcessorPipeline<MessageDecoderProcessor, MessageDecoderContext, ImMsgBody.Elem, Message>(
PipelineConfiguration(stopWhenConsumed = true),
@OptIn(TestOnly::class)
defaultTraceLogging
),
MessageDecoderPipeline {
@ -34,4 +27,12 @@ internal open class MessageDecoderPipelineImpl :
inner class MessageDecoderContextImpl(attributes: TypeSafeMap) : MessageDecoderContext, BaseContextImpl(attributes)
override fun createContext(attributes: TypeSafeMap): MessageDecoderContext = MessageDecoderContextImpl(attributes)
companion object {
@TestOnly
val defaultTraceLogging: MiraiLoggerWithSwitch by lazy {
MiraiLogger.Factory.create(MessageDecoderPipelineImpl::class, "MessageDecoderPipeline")
.withSwitch(systemProp("mirai.message.decoder.pipeline.log.full", false))
}
}
}

View File

@ -19,12 +19,14 @@ import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.SingleMessage
import net.mamoe.mirai.utils.TypeKey
import net.mamoe.mirai.utils.uncheckedCast
import kotlin.coroutines.RestrictsSuspension
import kotlin.reflect.KClass
internal interface MessageEncoderPipeline :
ProcessorPipeline<MessageEncoderProcessor<*>, SingleMessage, ImMsgBody.Elem> {
}
@RestrictsSuspension
internal interface MessageEncoderContext : ProcessorPipelineContext<SingleMessage, ImMsgBody.Elem> {
/**
@ -72,6 +74,7 @@ internal class MessageEncoderProcessor<T : SingleMessage>(
) : Processor<MessageEncoderContext, SingleMessage> {
override suspend fun process(context: MessageEncoderContext, data: SingleMessage) {
if (elementType.isInstance(data)) {
@Suppress("ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL")
encoder.run { context.process(data.uncheckedCast()) }
// TODO: 2022/4/27 handle exceptions
}

View File

@ -15,19 +15,16 @@ import net.mamoe.mirai.internal.pipeline.PipelineConfiguration
import net.mamoe.mirai.message.data.SingleMessage
import net.mamoe.mirai.utils.*
private val defaultTraceLogging: MiraiLogger by lazy {
MiraiLogger.Factory.create(MessageEncoderPipelineImpl::class, "MessageEncoderPipeline")
.withSwitch(systemProp("mirai.message.encoder.pipeline.log.full", false))
}
internal open class MessageEncoderPipelineImpl :
AbstractProcessorPipeline<MessageEncoderProcessor<*>, MessageEncoderContext, SingleMessage, ImMsgBody.Elem>(
PipelineConfiguration(stopWhenConsumed = true),
@OptIn(TestOnly::class)
defaultTraceLogging
),
MessageEncoderPipeline {
inner class MessageEncoderContextImpl(attributes: TypeSafeMap) : MessageEncoderContext,
private inner class MessageEncoderContextImpl(attributes: TypeSafeMap) : MessageEncoderContext,
BaseContextImpl(attributes) {
override var generalFlags: ImMsgBody.Elem by lateinitMutableProperty {
ImMsgBody.Elem(generalFlags = ImMsgBody.GeneralFlags(pbReserve = PB_RESERVE_FOR_ELSE))
@ -36,7 +33,13 @@ internal open class MessageEncoderPipelineImpl :
override fun createContext(attributes: TypeSafeMap): MessageEncoderContext = MessageEncoderContextImpl(attributes)
private companion object {
companion object {
private val PB_RESERVE_FOR_ELSE = "78 00 F8 01 00 C8 02 00".hexToBytes()
@TestOnly
val defaultTraceLogging: MiraiLoggerWithSwitch by lazy {
MiraiLogger.Factory.create(MessageEncoderPipelineImpl::class, "MessageEncoderPipeline")
.withSwitch(systemProp("mirai.message.encoder.pipeline.log.full", false))
}
}
}

View File

@ -9,7 +9,14 @@
package net.mamoe.mirai.internal.message.protocol
import net.mamoe.mirai.message.data.SingleMessage
import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.ContactOrBot
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.internal.utils.runCoroutineInPlace
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.message.data.visitor.RecursiveMessageVisitor
import net.mamoe.mirai.message.data.visitor.accept
import net.mamoe.mirai.utils.buildTypeSafeMap
import java.util.*
import kotlin.reflect.KClass
@ -18,32 +25,105 @@ internal interface MessageProtocolFacade {
val decoderPipeline: MessageDecoderPipeline
val loaded: List<MessageProtocol>
fun encode(
chain: MessageChain,
messageTarget: ContactOrBot?, // for At.display, QuoteReply, Image, and more.
withGeneralFlags: Boolean, // important for RichMessages, may also be helpful for others
isForward: Boolean = false, // is inside forward, for At.display
): List<ImMsgBody.Elem>
fun decode(
elements: List<ImMsgBody.Elem>,
groupIdOrZero: Long,
messageSourceKind: MessageSourceKind,
bot: Bot,
builder: MessageChainBuilder,
)
fun decode(
elements: List<ImMsgBody.Elem>,
groupIdOrZero: Long,
messageSourceKind: MessageSourceKind,
bot: Bot,
): MessageChain = buildMessageChain { decode(elements, groupIdOrZero, messageSourceKind, bot, this) }
companion object INSTANCE : MessageProtocolFacade by MessageProtocolFacadeImpl()
}
internal class MessageProtocolFacadeImpl : MessageProtocolFacade {
internal class MessageProtocolFacadeImpl(
protocols: Iterable<MessageProtocol> = ServiceLoader.load(MessageProtocol::class.java)
) : MessageProtocolFacade {
override val encoderPipeline: MessageEncoderPipeline = MessageEncoderPipelineImpl()
override val decoderPipeline: MessageDecoderPipeline = MessageDecoderPipelineImpl()
override val loaded: List<MessageProtocol> = initialize()
private fun initialize(): List<MessageProtocol> {
val instances = ServiceLoader.load(MessageProtocol::class.java).iterator().asSequence()
override val loaded: List<MessageProtocol> = kotlin.run {
val instances: PriorityQueue<MessageProtocol> = protocols
.toCollection(PriorityQueue(MessageProtocol.PriorityComparator.reversed()))
for (instance in instances) {
instance.collectProcessors(object : ProcessorCollector() {
override fun <T : SingleMessage> add(encoder: MessageEncoder<T>, elementType: KClass<T>) {
encoderPipeline.registerProcessor(MessageEncoderProcessor(encoder, elementType))
this@MessageProtocolFacadeImpl.encoderPipeline.registerProcessor(
MessageEncoderProcessor(
encoder,
elementType
)
)
}
override fun add(decoder: MessageDecoder) {
decoderPipeline.registerProcessor(MessageDecoderProcessor(decoder))
this@MessageProtocolFacadeImpl.decoderPipeline.registerProcessor(MessageDecoderProcessor(decoder))
}
})
}
instances.toList()
}
return instances.toList()
override fun encode(
chain: MessageChain,
messageTarget: ContactOrBot?,
withGeneralFlags: Boolean,
isForward: Boolean
): List<ImMsgBody.Elem> {
val pipeline = encoderPipeline
val attributes = buildTypeSafeMap {
set(MessageEncoderContext.CONTACT, messageTarget)
set(MessageEncoderContext.ORIGINAL_MESSAGE, chain)
set(MessageEncoderContext.ADD_GENERAL_FLAGS, withGeneralFlags)
set(MessageEncoderContext.IS_FORWARD, isForward)
}
val builder = ArrayList<ImMsgBody.Elem>(chain.size)
chain.accept(object : RecursiveMessageVisitor<Unit>() {
override fun visitSingleMessage(message: SingleMessage, data: Unit) {
runCoroutineInPlace {
builder.addAll(pipeline.process(message, attributes))
}
}
})
return builder
}
override fun decode(
elements: List<ImMsgBody.Elem>,
groupIdOrZero: Long,
messageSourceKind: MessageSourceKind,
bot: Bot,
builder: MessageChainBuilder
) {
val pipeline = decoderPipeline
val attributes = buildTypeSafeMap {
set(MessageDecoderContext.BOT, bot)
set(MessageDecoderContext.MESSAGE_SOURCE_KIND, messageSourceKind)
set(MessageDecoderContext.GROUP_ID, groupIdOrZero)
}
runCoroutineInPlace {
elements.forEach { builder.addAll(pipeline.process(it, attributes)) }
}
}
}

View File

@ -14,8 +14,8 @@ 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.message.toRichTextElems
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
import net.mamoe.mirai.internal.network.protocol.data.proto.SourceMsg
@ -64,8 +64,8 @@ internal class OfflineMessageSourceImplData(
senderUin = fromId,
toUin = 0,
flag = 1,
elems = originElems ?: originalMessage.toRichTextElems(
null, //forGroup = kind == MessageSourceKind.GROUP,
elems = originElems ?: MessageProtocolFacade.encode(
originalMessage, messageTarget = null, //forGroup = kind == MessageSourceKind.GROUP,
withGeneralFlags = false
),
type = 0,

View File

@ -20,7 +20,7 @@ import net.mamoe.mirai.event.GlobalEventChannel
import net.mamoe.mirai.event.syncFromEvent
import net.mamoe.mirai.internal.contact.uin
import net.mamoe.mirai.internal.message.MessageSourceSerializerImpl
import net.mamoe.mirai.internal.message.toRichTextElems
import net.mamoe.mirai.internal.message.protocol.MessageProtocolFacade
import net.mamoe.mirai.internal.network.notice.group.GroupMessageProcessor.SendGroupMessageReceipt
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
@ -37,7 +37,7 @@ import java.util.concurrent.atomic.AtomicBoolean
private fun <T> T.toJceDataImpl(subject: ContactOrBot?): ImMsgBody.SourceMsg
where T : MessageSourceInternal, T : MessageSource {
val elements = originalMessage.toRichTextElems(subject, withGeneralFlags = true)
val elements = MessageProtocolFacade.encode(originalMessage, subject, withGeneralFlags = true)
val pdReserve = SourceMsg.ResvAttr(
origUids = sequenceIds.zip(internalIds)
@ -215,7 +215,7 @@ internal class OnlineMessageSourceToGroupImpl(
suspend fun ensureSequenceIdAvailable() = kotlin.run { sequenceIdDeferred.await() }
private val jceData: ImMsgBody.SourceMsg by lazy {
val elements = originalMessage.toRichTextElems(subject, withGeneralFlags = true)
val elements = MessageProtocolFacade.encode(originalMessage, subject, withGeneralFlags = true)
ImMsgBody.SourceMsg(
origSeqs = sequenceIds,
senderUin = fromId,

View File

@ -14,7 +14,7 @@ import kotlinx.serialization.protobuf.ProtoIntegerType
import kotlinx.serialization.protobuf.ProtoNumber
import kotlinx.serialization.protobuf.ProtoType
import net.mamoe.mirai.internal.utils.io.ProtoBuf
import net.mamoe.mirai.internal.utils.structureToString
import net.mamoe.mirai.internal.utils.structureToStringIfAvailable
import net.mamoe.mirai.utils.EMPTY_BYTE_ARRAY
@Serializable
@ -383,7 +383,7 @@ internal class ImMsgBody : ProtoBuf {
@ProtoNumber(53) @JvmField val commonElem: CommonElem? = null,
) : ProtoBuf {
override fun toString(): String {
return this.structureToString()
return this.structureToStringIfAvailable() ?: super.toString()
}
}
@ -937,7 +937,7 @@ internal class ImMsgBody : ProtoBuf {
@Serializable
internal class RichText(
@ProtoNumber(1) @JvmField val attr: Attr? = null,
@ProtoNumber(2) @JvmField val elems: MutableList<Elem> = mutableListOf(),
@ProtoNumber(2) @JvmField val elems: List<Elem> = listOf(),
@ProtoNumber(3) @JvmField val notOnlineFile: NotOnlineFile? = null,
@ProtoNumber(4) @JvmField val ptt: Ptt? = null,
@ProtoNumber(5) @JvmField val tmpPtt: TmpPtt? = null,

View File

@ -15,8 +15,8 @@ import kotlinx.io.core.ByteReadPacket
import net.mamoe.mirai.internal.QQAndroidBot
import net.mamoe.mirai.internal.contact.SendMessageHandler
import net.mamoe.mirai.internal.message.contextualBugReportException
import net.mamoe.mirai.internal.message.protocol.MessageProtocolFacade
import net.mamoe.mirai.internal.message.source.MessageSourceInternal
import net.mamoe.mirai.internal.message.toRichTextElems
import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.internal.network.QQAndroidClient
import net.mamoe.mirai.internal.network.components.PacketCodec
@ -86,12 +86,12 @@ internal fun Collection<ForwardMessage.INode>.calculateValidationData(
),
msgBody = ImMsgBody.MsgBody(
richText = ImMsgBody.RichText(
elems = chain.messageChain.toMessageChain()
.toRichTextElems(
handler.contact,
withGeneralFlags = false,
isForward = true,
).toMutableList()
elems = MessageProtocolFacade.encode(
chain.messageChain.toMessageChain(),
handler.contact,
withGeneralFlags = false,
isForward = true
)
)
)
)

View File

@ -22,11 +22,11 @@ import net.mamoe.mirai.internal.contact.groupCode
import net.mamoe.mirai.internal.contact.uin
import net.mamoe.mirai.internal.message.data.ForwardMessageInternal
import net.mamoe.mirai.internal.message.data.toPtt
import net.mamoe.mirai.internal.message.protocol.MessageProtocolFacade
import net.mamoe.mirai.internal.message.source.OnlineMessageSourceToFriendImpl
import net.mamoe.mirai.internal.message.source.OnlineMessageSourceToGroupImpl
import net.mamoe.mirai.internal.message.source.OnlineMessageSourceToStrangerImpl
import net.mamoe.mirai.internal.message.source.OnlineMessageSourceToTempImpl
import net.mamoe.mirai.internal.message.toRichTextElems
import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.internal.network.QQAndroidClient
import net.mamoe.mirai.internal.network.components.ClockHolder.Companion.clock
@ -198,7 +198,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
fragmentTranslator = {
ImMsgBody.MsgBody(
richText = ImMsgBody.RichText(
elems = it.toRichTextElems(messageTarget = target, withGeneralFlags = true),
elems = MessageProtocolFacade.encode(it, messageTarget = target, withGeneralFlags = true),
),
)
},
@ -257,7 +257,11 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
fragmentTranslator = { subChain ->
ImMsgBody.MsgBody(
richText = ImMsgBody.RichText(
elems = subChain.toRichTextElems(messageTarget = targetFriend, withGeneralFlags = true),
elems = MessageProtocolFacade.encode(
subChain,
messageTarget = targetFriend,
withGeneralFlags = true
),
ptt = subChain.findPtt(),
),
)
@ -345,7 +349,11 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
contentHead = MsgComm.ContentHead(pkgNum = 1),
msgBody = ImMsgBody.MsgBody(
richText = ImMsgBody.RichText(
elems = message.toRichTextElems(messageTarget = targetMember, withGeneralFlags = true),
elems = MessageProtocolFacade.encode(
message,
messageTarget = targetMember,
withGeneralFlags = true
),
),
),
msgSeq = source.sequenceIds.single(),
@ -375,7 +383,11 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
fragmentTranslator = { subChain ->
ImMsgBody.MsgBody(
richText = ImMsgBody.RichText(
elems = subChain.toRichTextElems(messageTarget = targetGroup, withGeneralFlags = true),
elems = MessageProtocolFacade.encode(
subChain,
messageTarget = targetGroup,
withGeneralFlags = true
),
ptt = subChain.findPtt(),
),

View File

@ -14,6 +14,7 @@ import net.mamoe.mirai.internal.network.components.NoticeProcessor
import net.mamoe.mirai.utils.*
import java.io.Closeable
import java.util.*
import java.util.concurrent.ConcurrentLinkedDeque
import java.util.concurrent.ConcurrentLinkedQueue
internal interface Processor<C : ProcessorPipelineContext<D, *>, D> : PipelineConsumptionMarker {
@ -31,7 +32,9 @@ internal interface ProcessorPipeline<P : Processor<out ProcessorPipelineContext<
}
}
fun registerProcessor(processor: P): DisposableRegistry
fun registerProcessor(processor: P): DisposableRegistry // after
fun registerBefore(processor: P): DisposableRegistry
suspend fun process(
data: D,
@ -153,7 +156,7 @@ protected constructor(
/**
* Must be ordered
*/
override val processors = ConcurrentLinkedQueue<P>()
override val processors = ConcurrentLinkedDeque<P>()
override fun registerProcessor(processor: P): ProcessorPipeline.DisposableRegistry {
processors.add(processor)
@ -162,6 +165,13 @@ protected constructor(
}
}
override fun registerBefore(processor: P): ProcessorPipeline.DisposableRegistry {
processors.addFirst(processor)
return ProcessorPipeline.DisposableRegistry {
processors.remove(processor)
}
}
protected abstract fun createContext(attributes: TypeSafeMap): C
abstract inner class BaseContextImpl(

View File

@ -16,7 +16,15 @@ import net.mamoe.mirai.utils.debug
import net.mamoe.mirai.utils.loadService
/**
* Do not call this inside [Any.toString]. [StackOverflowError] may happen. Call [structureToStringIfAvailable] instead.
*/
internal fun Any?.structureToString(): String = StructureToStringTransformer.instance.transform(this)
internal fun Any?.structureToStringIfAvailable(): String? {
return if (StructureToStringTransformer.available) {
StructureToStringTransformer.instance.transform(this)
} else null
}
private val SoutvLogger: MiraiLogger by lazy {
MiraiLogger.Factory.create(
@ -40,6 +48,8 @@ internal fun interface StructureToStringTransformer {
val instance by lazy {
loadService(StructureToStringTransformer::class) { ObjectToStringStructureToStringTransformer() }
}
val available = instance !is ObjectToStringStructureToStringTransformer
}
}