From 0acb89cd36b61b5757a7dbb5cd5c6297a233f07c Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 22 Apr 2020 17:13:09 +0800 Subject: [PATCH] Extract implementations; Introduce `OnlineMessageSource.toOffline` --- .../message/data/MessageSource.kt | 209 ++---------------- .../message/data/OfflineMessageSource.kt | 120 ++++++++++ .../message/data/OnlineMessageSource.kt | 209 ++++++++++++++++++ 3 files changed, 343 insertions(+), 195 deletions(-) create mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/OfflineMessageSource.kt create mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/OnlineMessageSource.kt diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt index 0e7806620..b48693c6d 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt @@ -9,17 +9,20 @@ @file:JvmMultifileClass @file:JvmName("MessageUtils") -@file:Suppress("NOTHING_TO_INLINE", "unused", "INAPPLICABLE_JVM_NAME") +@file:Suppress("NOTHING_TO_INLINE", "unused", "INAPPLICABLE_JVM_NAME", "DEPRECATION_ERROR") package net.mamoe.mirai.message.data import kotlinx.coroutines.Job import net.mamoe.mirai.Bot -import net.mamoe.mirai.contact.* -import net.mamoe.mirai.message.ContactMessage -import net.mamoe.mirai.message.MessageReceipt +import net.mamoe.mirai.contact.Group +import net.mamoe.mirai.contact.Member +import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.recallIn -import net.mamoe.mirai.utils.* +import net.mamoe.mirai.utils.LazyProperty +import net.mamoe.mirai.utils.MiraiExperimentalAPI +import net.mamoe.mirai.utils.MiraiInternalAPI +import net.mamoe.mirai.utils.SinceMirai import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext import kotlin.jvm.JvmMultifileClass @@ -57,6 +60,12 @@ sealed class MessageSource : Message, MessageMetadata, ConstrainSingle { - override val typeName: String get() = "OnlineMessageSource" - } - - /** - * 消息发送人. 可能为 [机器人][Bot] 或 [好友][QQ] 或 [群员][Member]. - * 即类型必定为 [Bot], [QQ] 或 [Member] - */ - abstract val sender: ContactOrBot - - /** - * 消息发送目标. 可能为 [机器人][Bot] 或 [好友][QQ] 或 [群][Group]. - * 即类型必定为 [Bot], [QQ] 或 [Group] - */ - abstract val target: ContactOrBot - - /** - * 消息主体. 群消息时为 [Group]. 好友消息时为 [QQ], 临时消息为 [Member] - * 不论是机器人接收的消息还是发送的消息, 此属性都指向机器人能进行回复的目标. - */ - abstract val subject: Contact - - /** - * 由 [机器人主动发送消息][Contact.sendMessage] 产生的 [MessageSource] - */ - sealed class Outgoing : OnlineMessageSource() { - companion object Key : Message.Key { - override val typeName: String get() = "OnlineMessageSource.Outgoing" - } - - abstract override val sender: Bot - abstract override val target: Contact - - final override val fromId: Long get() = sender.id - final override val targetId: Long get() = target.id - - abstract class ToFriend : Outgoing() { - companion object Key : Message.Key { - override val typeName: String get() = "OnlineMessageSource.Outgoing.ToFriend" - } - - abstract override val target: Friend - final override val subject: Friend get() = target - // final override fun toString(): String = "OnlineMessageSource.ToFriend(target=${target.id})" - } - - abstract class ToTemp : Outgoing() { - companion object Key : Message.Key { - override val typeName: String get() = "OnlineMessageSource.Outgoing.ToTemp" - } - - abstract override val target: Member - val group: Group get() = target.group - final override val subject: Member get() = target - } - - abstract class ToGroup : Outgoing() { - companion object Key : Message.Key { - override val typeName: String get() = "OnlineMessageSource.Outgoing.ToGroup" - } - - abstract override val target: Group - final override val subject: Group get() = target - // final override fun toString(): String = "OnlineMessageSource.ToGroup(group=${target.id})" - } - } - - /** - * 接收到的一条消息的 [MessageSource] - */ - sealed class Incoming : OnlineMessageSource() { - companion object Key : Message.Key { - override val typeName: String get() = "OnlineMessageSource.Incoming" - } - - abstract override val sender: User - - final override val fromId: Long get() = sender.id - final override val targetId: Long get() = target.id - - abstract class FromFriend : Incoming() { - companion object Key : Message.Key { - override val typeName: String get() = "OnlineMessageSource.Incoming.FromFriend" - } - - abstract override val sender: Friend - final override val subject: Friend get() = sender - final override val target: Bot get() = sender.bot - // final override fun toString(): String = "OnlineMessageSource.FromFriend(from=${sender.id})" - } - - abstract class FromTemp : Incoming() { - companion object Key : Message.Key { - override val typeName: String get() = "OnlineMessageSource.Incoming.FromTemp" - } - - abstract override val sender: Member - inline val group: Group get() = sender.group - final override val subject: Member get() = sender - final override val target: Bot get() = sender.bot - } - - abstract class FromGroup : Incoming() { - companion object Key : Message.Key { - override val typeName: String get() = "OnlineMessageSource.Incoming.FromGroup" - } - - abstract override val sender: Member - final override val subject: Group get() = sender.group - final override val target: Group get() = group - inline val group: Group get() = sender.group - } - - - ////////////////////////////////// - //// FOR BINARY COMPATIBILITY //// - ////////////////////////////////// - - - @PlannedRemoval("1.0.0") - @Deprecated("for binary compatibility until 1.0.0", level = DeprecationLevel.HIDDEN) - @get:JvmName("target") - @get:JvmSynthetic - final override val target2: Any - get() = target - } - - @PlannedRemoval("1.0.0") - @Deprecated("for binary compatibility until 1.0.0", level = DeprecationLevel.HIDDEN) - @get:JvmName("target") - @get:JvmSynthetic - open val target2: Any - get() = target - - @PlannedRemoval("1.0.0") - @Deprecated("for binary compatibility until 1.0.0", level = DeprecationLevel.HIDDEN) - @get:JvmName("sender") - @get:JvmSynthetic - open val sender2: Any - get() = sender -} // inline for future removal inline fun MessageSource.isAboutGroup(): Boolean { @@ -301,36 +150,6 @@ inline fun MessageSource.recallIn( coroutineContext: CoroutineContext = EmptyCoroutineContext ): Job = bot.recallIn(this, timeMillis, coroutineContext) - -// OFFLINE - -/** - * 由一条消息中的 [QuoteReply] 得到的 [MessageSource]. - * 此消息源可能来自一条与机器人无关的消息. 因此无法提供对象化的 `sender` 或 `target` 获取. - */ -@SinceMirai("0.33.0") -abstract class OfflineMessageSource : MessageSource() { - companion object Key : Message.Key { - override val typeName: String - get() = "OfflineMessageSource" - } - - enum class Kind { - GROUP, - FRIEND, - - @SinceMirai("0.36.0") - TEMP - } - - /** - * 消息种类 - */ - abstract val kind: Kind - - // final override fun toString(): String = "OfflineMessageSource(sender=$senderId, target=$targetId)" -} - // For MessageChain /** diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/OfflineMessageSource.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/OfflineMessageSource.kt new file mode 100644 index 000000000..fb88ebb58 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/OfflineMessageSource.kt @@ -0,0 +1,120 @@ +/* + * Copyright 2020 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/master/LICENSE + */ + +@file:JvmMultifileClass +@file:JvmName("MessageUtils") +@file:Suppress("NOTHING_TO_INLINE", "unused", "INAPPLICABLE_JVM_NAME", "INVISIBLE_MEMBER") + +package net.mamoe.mirai.message.data + +import net.mamoe.mirai.BotImpl +import net.mamoe.mirai.contact.Contact +import net.mamoe.mirai.contact.Group +import net.mamoe.mirai.utils.MiraiExperimentalAPI +import net.mamoe.mirai.utils.MiraiInternalAPI +import net.mamoe.mirai.utils.SinceMirai +import net.mamoe.mirai.utils.asSequence +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName +import kotlin.jvm.JvmSynthetic + + +/** + * 由一条消息中的 [QuoteReply] 得到的 [MessageSource]. + * 此消息源可能来自一条与机器人无关的消息. 因此无法提供对象化的 `sender` 或 `target` 获取. + */ +@SinceMirai("0.33.0") +abstract class OfflineMessageSource : MessageSource() { + companion object Key : Message.Key { + override val typeName: String + get() = "OfflineMessageSource" + } + + enum class Kind { + GROUP, + FRIEND, + + @SinceMirai("0.36.0") + TEMP + } + + /** + * 消息种类 + */ + abstract val kind: Kind + + // final override fun toString(): String = "OfflineMessageSource(sender=$senderId, target=$targetId)" +} + + +/** + * 复制这个消息源, 并修改 + */ +@JvmName("copySource") +inline fun MessageSource.copyAmend( + block: MessageSourceBuilder.() -> Unit +): OfflineMessageSource { + return constructMessageSource() +} + +@MiraiExperimentalAPI +@SinceMirai("0.39.0") +@OptIn(MiraiInternalAPI::class) +fun constructMessageSource( + kind: OfflineMessageSource.Kind, + fromUin: Long, targetUin: Long, + id: Int, time: Int, internalId: Int, + originalMessage: MessageChain +): OfflineMessageSource { + val bot = BotImpl.instances.asSequence().mapNotNull { it.get() }.firstOrNull() + ?: error("no Bot instance available") + + return bot.constructMessageSource(kind, fromUin, targetUin, id, time, internalId, originalMessage) +} + +@JvmSynthetic +@MiraiExperimentalAPI +inline fun buildMessageSource(block: MessageSourceBuilder.() -> Unit): MessageSource { + val builder = MessageSourceBuilder().apply(block) + return constructMessageSource( + builder.kind ?: error("found "), + block + ) +} + +@DslMarker +annotation class SourceBuilderDsl + +class MessageSourceBuilder( + source: OfflineMessageSource +) : MessageChainBuilder() { + var kind: OfflineMessageSource.Kind = source.kind + var fromUin: Long = source.fromId + var targetUin: Long = source.targetId + var id: Int = source.id + var time: Int = source.time + var internalId: Int = source.internalId + var originalMessage: MessageChain = source.originalMessage + + fun from(sender: Contact): MessageSourceBuilder { + fromUin = if (sender is Group) { + Group.calculateGroupUinByGroupCode(sender.id) + } else sender.id + return this + } + + fun target(target: Contact): MessageSourceBuilder { + targetUin = if (target is Group) { + Group.calculateGroupUinByGroupCode(target.id) + } else target.id + return this + } + + fun +} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/OnlineMessageSource.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/OnlineMessageSource.kt new file mode 100644 index 000000000..74909187f --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/OnlineMessageSource.kt @@ -0,0 +1,209 @@ +/* + * Copyright 2020 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/master/LICENSE + */ + +@file:JvmMultifileClass +@file:JvmName("MessageUtils") +@file:Suppress("NOTHING_TO_INLINE", "unused", "INAPPLICABLE_JVM_NAME", "INVISIBLE_MEMBER") + +package net.mamoe.mirai.message.data + +import net.mamoe.mirai.Bot +import net.mamoe.mirai.contact.* +import net.mamoe.mirai.message.ContactMessage +import net.mamoe.mirai.message.MessageReceipt +import net.mamoe.mirai.utils.MiraiExperimentalAPI +import net.mamoe.mirai.utils.PlannedRemoval +import net.mamoe.mirai.utils.SinceMirai +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName +import kotlin.jvm.JvmSynthetic + + +/** + * 在线消息的 [MessageSource]. + * 拥有对象化的 [sender], [target], 也可以直接 [recall] 和 [quote] + * + * ### 来源 + * **必定是一个发出去的消息或接收到的消息的 [MessageChain] 中的一个元数据 [MessageMetadata].** + * + * #### 机器人主动发送消息 + * 当机器人 [主动发出消息][Member.sendMessage], 将会得到一个 [消息回执][MessageReceipt]. + * 此回执的 [消息源][MessageReceipt.source] 即为一个 [外向消息源][OnlineMessageSource.Outgoing], 代表着刚刚发出的那条消息的来源. + * + * #### 机器人接受消息 + * 当机器人接收一条消息 [ContactMessage], 这条消息包含一个 [内向消息源][OnlineMessageSource.Incoming], 代表着接收到的这条消息的来源. + */ +@SinceMirai("0.33.0") +@OptIn(MiraiExperimentalAPI::class) +sealed class OnlineMessageSource : MessageSource() { + companion object Key : Message.Key { + override val typeName: String get() = "OnlineMessageSource" + } + + /** + * 消息发送人. 可能为 [机器人][Bot] 或 [好友][QQ] 或 [群员][Member]. + * 即类型必定为 [Bot], [QQ] 或 [Member] + */ + abstract val sender: ContactOrBot + + /** + * 消息发送目标. 可能为 [机器人][Bot] 或 [好友][QQ] 或 [群][Group]. + * 即类型必定为 [Bot], [QQ] 或 [Group] + */ + abstract val target: ContactOrBot + + /** + * 消息主体. 群消息时为 [Group]. 好友消息时为 [QQ], 临时消息为 [Member] + * 不论是机器人接收的消息还是发送的消息, 此属性都指向机器人能进行回复的目标. + */ + abstract val subject: Contact + + /** + * 由 [机器人主动发送消息][Contact.sendMessage] 产生的 [MessageSource] + */ + sealed class Outgoing : OnlineMessageSource() { + companion object Key : Message.Key { + override val typeName: String get() = "OnlineMessageSource.Outgoing" + } + + abstract override val sender: Bot + abstract override val target: Contact + + final override val fromId: Long get() = sender.id + final override val targetId: Long get() = target.id + + abstract class ToFriend : Outgoing() { + companion object Key : Message.Key { + override val typeName: String get() = "OnlineMessageSource.Outgoing.ToFriend" + } + + abstract override val target: Friend + final override val subject: Friend get() = target + // final override fun toString(): String = "OnlineMessageSource.ToFriend(target=${target.id})" + } + + abstract class ToTemp : Outgoing() { + companion object Key : Message.Key { + override val typeName: String get() = "OnlineMessageSource.Outgoing.ToTemp" + } + + abstract override val target: Member + val group: Group get() = target.group + final override val subject: Member get() = target + } + + abstract class ToGroup : Outgoing() { + companion object Key : Message.Key { + override val typeName: String get() = "OnlineMessageSource.Outgoing.ToGroup" + } + + abstract override val target: Group + final override val subject: Group get() = target + // final override fun toString(): String = "OnlineMessageSource.ToGroup(group=${target.id})" + } + } + + /** + * 接收到的一条消息的 [MessageSource] + */ + sealed class Incoming : OnlineMessageSource() { + companion object Key : Message.Key { + override val typeName: String get() = "OnlineMessageSource.Incoming" + } + + abstract override val sender: User + + final override val fromId: Long get() = sender.id + final override val targetId: Long get() = target.id + + abstract class FromFriend : Incoming() { + companion object Key : Message.Key { + override val typeName: String get() = "OnlineMessageSource.Incoming.FromFriend" + } + + abstract override val sender: Friend + final override val subject: Friend get() = sender + final override val target: Bot get() = sender.bot + // final override fun toString(): String = "OnlineMessageSource.FromFriend(from=${sender.id})" + } + + abstract class FromTemp : Incoming() { + companion object Key : Message.Key { + override val typeName: String get() = "OnlineMessageSource.Incoming.FromTemp" + } + + abstract override val sender: Member + inline val group: Group get() = sender.group + final override val subject: Member get() = sender + final override val target: Bot get() = sender.bot + } + + abstract class FromGroup : Incoming() { + companion object Key : Message.Key { + override val typeName: String get() = "OnlineMessageSource.Incoming.FromGroup" + } + + abstract override val sender: Member + final override val subject: Group get() = sender.group + final override val target: Group get() = group + inline val group: Group get() = sender.group + } + + + ////////////////////////////////// + //// FOR BINARY COMPATIBILITY //// + ////////////////////////////////// + + + @PlannedRemoval("1.0.0") + @Deprecated("for binary compatibility until 1.0.0", level = DeprecationLevel.HIDDEN) + @get:JvmName("target") + @get:JvmSynthetic + final override val target2: Any + get() = target + } + + @PlannedRemoval("1.0.0") + @Deprecated("for binary compatibility until 1.0.0", level = DeprecationLevel.HIDDEN) + @get:JvmName("target") + @get:JvmSynthetic + open val target2: Any + get() = target + + @PlannedRemoval("1.0.0") + @Deprecated("for binary compatibility until 1.0.0", level = DeprecationLevel.HIDDEN) + @get:JvmName("sender") + @get:JvmSynthetic + open val sender2: Any + get() = sender +} + +@SinceMirai("0.39.0") +@JvmName("toOfflineMessageSource") +fun OnlineMessageSource.toOffline(): OfflineMessageSource = + OfflineMessageSourceByOnline(this) + +internal class OfflineMessageSourceByOnline( + private val onlineMessageSource: OnlineMessageSource +) : OfflineMessageSource() { + override val kind: Kind + get() = when { + onlineMessageSource.isAboutGroup() -> Kind.GROUP + onlineMessageSource.isAboutFriend() -> Kind.FRIEND + onlineMessageSource.isAboutTemp() -> Kind.TEMP + else -> error("stub") + } + override val bot: Bot get() = onlineMessageSource.bot + override val id: Int get() = onlineMessageSource.id + override val internalId: Int get() = onlineMessageSource.internalId + override val time: Int get() = onlineMessageSource.time + override val fromId: Long get() = onlineMessageSource.fromId + override val targetId: Long get() = onlineMessageSource.targetId + override val originalMessage: MessageChain get() = onlineMessageSource.originalMessage +} \ No newline at end of file