commonMain.message.RefinableMessage.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mirai-core-jvm Show documentation
Show all versions of mirai-core-jvm Show documentation
Mirai Protocol implementation for QQ Android
/*
* 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
import net.mamoe.mirai.Bot
import net.mamoe.mirai.internal.message.DeepMessageRefiner.refineDeep
import net.mamoe.mirai.internal.message.LightMessageRefiner.refineLight
import net.mamoe.mirai.internal.message.LightMessageRefiner.refineMessageSource
import net.mamoe.mirai.internal.message.flags.InternalFlagOnlyMessage
import net.mamoe.mirai.internal.message.source.IncomingMessageSourceInternal
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.utils.safeCast
/**
* 在接收解析消息后会经过一层转换的消息.
*
* @see DeepMessageRefiner.refineDeep
* @see LightMessageRefiner.refineLight
*/
internal interface RefinableMessage : SingleMessage {
/**
* Refine if possible (without suspension), returns self otherwise.
* @since 2.6
*/ // see #1157
fun tryRefine(
bot: Bot,
context: MessageChain,
refineContext: RefineContext = EmptyRefineContext,
): Message? = this
/**
* This message [RefinableMessage] will be replaced by return value of [refineLight]
*/
suspend fun refine(
bot: Bot,
context: MessageChain,
refineContext: RefineContext = EmptyRefineContext,
): Message? = tryRefine(bot, context, refineContext)
}
internal sealed class MessageRefiner {
protected inline fun MessageChain.refineImpl(
bot: Bot,
refineAction: (message: RefinableMessage) -> Message?,
): MessageChain {
val convertLineSeparator = bot.configuration.convertLineSeparator
if (none {
it is RefinableMessage
|| (it is PlainText && convertLineSeparator && it.content.contains('\r'))
}
) return this
val builder = MessageChainBuilder(this.size)
for (singleMessage in this) {
if (singleMessage is RefinableMessage) {
val v = refineAction(singleMessage)
if (v != null) builder.add(v)
} else if (singleMessage is PlainText && convertLineSeparator) {
val content = singleMessage.content
if (content.contains('\r')) {
builder.add(
PlainText(
content
.replace("\r\n", "\n")
.replace('\r', '\n')
)
)
} else {
builder.add(singleMessage)
}
} else {
builder.add(singleMessage)
}
}
return builder.build()
}
}
@Suppress("unused")
internal class RefineContextKey(
val name: String?,
) {
override fun toString(): String {
return buildString {
append("Key(")
name?.also(this@buildString::append) ?: kotlin.run {
append('#').append([email protected]())
}
append(')')
}
}
}
/**
* 转换消息时的上下文
*/
internal interface RefineContext {
operator fun contains(key: RefineContextKey<*>): Boolean
operator fun get(key: RefineContextKey): T?
fun getNotNull(key: RefineContextKey): T = get(key) ?: error("No such value of `$key`")
}
internal interface MutableRefineContext : RefineContext {
operator fun set(key: RefineContextKey, value: T)
fun remove(key: RefineContextKey<*>)
}
internal object EmptyRefineContext : RefineContext {
override fun contains(key: RefineContextKey<*>): Boolean = false
override fun get(key: RefineContextKey): T? = null
override fun toString(): String {
return "EmptyRefineContext"
}
}
@Suppress("UNCHECKED_CAST")
internal class SimpleRefineContext(
private val delegate: MutableMap, Any> = mutableMapOf(),
) : MutableRefineContext {
override fun contains(key: RefineContextKey<*>): Boolean = delegate.containsKey(key)
override fun get(key: RefineContextKey): T? {
return (delegate[key] ?: return null) as T
}
override fun set(key: RefineContextKey, value: T) {
delegate[key] = value
}
override fun remove(key: RefineContextKey<*>) {
delegate.remove(key)
}
}
/**
* 执行不需要 `suspend` 的 refine. 用于 [MessageSource.originalMessage].
*/
internal object LightMessageRefiner : MessageRefiner() {
/* note:
* 不在 refineLight 中处理的原因是 refineMessageSource
* 需要的是 **最终处理完成后** 的 MessageChain (即 refineDeep 后的 MessageChain)
*
* 在 refineLight/RefinableMessage.(try)refine 中直接处理将导致获取不到最终结果导致逻辑错误
*/
fun MessageChain.refineMessageSource(): MessageChain {
val source = this.sourceOrNull?.safeCast() ?: return this
val originalMessage = this
source.originalMessageLazy = lazy {
originalMessage.filterNot { it is MessageSource }.toMessageChain()
// @Suppress("INVISIBLE_MEMBER")
// createMessageChainImplOptimized(originalMessage.filterNot { it is MessageSource })
}
return this
}
fun MessageChain.refineLight(
bot: Bot,
refineContext: RefineContext = EmptyRefineContext,
): MessageChain {
return refineImpl(bot) { it.tryRefine(bot, this, refineContext) }
}
/**
* 去除 [MessageChain] 携带的内部标识
*
* 用于 [createMessageReceipt] <- `RemoteFile.uploadAndSend` (文件操作API v1)
*/
fun MessageChain.dropMiraiInternalFlags(): MessageChain {
return asSequence().filterNot { it is InternalFlagOnlyMessage }.toMessageChain()
}
}
/**
* 执行需要 `suspend` 的 refine. 用于解析到的消息.
*/
internal object DeepMessageRefiner : MessageRefiner() {
suspend fun MessageChain.refineDeep(
bot: Bot,
refineContext: RefineContext = EmptyRefineContext,
): MessageChain {
return refineImpl(bot) { it.refine(bot, this, refineContext) }
.refineMessageSource()
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy