From f41b8315803ee80d7fb4d3f5bf53653034e7a096 Mon Sep 17 00:00:00 2001 From: ryoii Date: Sun, 23 Feb 2020 16:36:19 +0800 Subject: [PATCH 1/6] Graphic refactor plugin list --- .../controller/MiraiGraphicalUIController.kt | 12 ++++-------- .../console/graphical/model/PluginModel.kt | 15 ++++++++------- .../console/graphical/view/PluginsView.kt | 19 +++++++++++++++---- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt index 676fc8b5a..4a6d607df 100644 --- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt @@ -13,10 +13,7 @@ import net.mamoe.mirai.console.graphical.model.VerificationCodeModel import net.mamoe.mirai.console.graphical.view.VerificationCodeFragment import net.mamoe.mirai.console.utils.MiraiConsoleUI import net.mamoe.mirai.utils.LoginSolver -import tornadofx.Controller -import tornadofx.Scope -import tornadofx.find -import tornadofx.observableListOf +import tornadofx.* class MiraiGraphicalUIController : Controller(), MiraiConsoleUI { @@ -79,10 +76,9 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI { override fun createLoginSolver(): LoginSolver = loginSolver - private fun getPluginsFromConsole(): ObservableList { - // TODO - return observableListOf() - } + private fun getPluginsFromConsole(): ObservableList = + MiraiConsole.pluginManager.getAllPluginDescriptions().map(::PluginModel).toObservable() + } class GraphicalLoginSolver : LoginSolver() { diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/PluginModel.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/PluginModel.kt index 21a59e66b..e1323901f 100644 --- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/PluginModel.kt +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/PluginModel.kt @@ -3,16 +3,17 @@ package net.mamoe.mirai.console.graphical.model import com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject import javafx.beans.property.SimpleBooleanProperty import javafx.beans.property.SimpleStringProperty +import net.mamoe.mirai.console.plugins.PluginDescription import tornadofx.getValue import tornadofx.setValue -class PluginModel : RecursiveTreeObject() { - - val nameProperty = SimpleStringProperty(this, "nameProperty") - val name by nameProperty - - val descriptionProperty = SimpleStringProperty(this, "descriptionProperty") - val description by descriptionProperty +class PluginModel( + val name: String, + val version: String, + val author: String, + val description: String +) : RecursiveTreeObject() { + constructor(plugin: PluginDescription):this(plugin.name, plugin.version, plugin.author, plugin.info) val enabledProperty = SimpleBooleanProperty(this, "enabledProperty") var enabled by enabledProperty diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PluginsView.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PluginsView.kt index 5b3e4d163..7351b2480 100644 --- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PluginsView.kt +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PluginsView.kt @@ -13,10 +13,21 @@ class PluginsView : View() { override val root = jfxTreeTableView(plugins) { columns.addAll( - JFXTreeTableColumn("插件名").apply { }, - JFXTreeTableColumn("版本").apply { }, - JFXTreeTableColumn("作者").apply { }, - JFXTreeTableColumn("介绍").apply { } + JFXTreeTableColumn("插件名").apply { + prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.1)) + }, + JFXTreeTableColumn("版本").apply { + prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.1)) + }, + JFXTreeTableColumn("作者").apply { + prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.1)) + }, + JFXTreeTableColumn("介绍").apply { + prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.6)) + }, + JFXTreeTableColumn("操作").apply { + prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.08)) + } ) } } \ No newline at end of file From c33b0688e170799b87558270387659b8c4cb738c Mon Sep 17 00:00:00 2001 From: ryoii Date: Sun, 23 Feb 2020 18:12:21 +0800 Subject: [PATCH 2/6] Graphic daily dev a little bit --- .../controller/MiraiGraphicalUIController.kt | 2 -- .../console/graphical/view/SettingsView.kt | 35 +++++++++++++------ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt index 4a6d607df..159b62e92 100644 --- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt @@ -25,8 +25,6 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI { val botList = observableListOf() val pluginList: ObservableList by lazy(::getPluginsFromConsole) -// val consoleConfig : Map by lazy(::getConfigFromConsole) - val consoleInfo = ConsoleInfo() fun login(qq: String, psd: String) { diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/SettingsView.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/SettingsView.kt index a40c2234e..aa194d712 100644 --- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/SettingsView.kt +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/SettingsView.kt @@ -1,23 +1,36 @@ package net.mamoe.mirai.console.graphical.view import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController +import net.mamoe.mirai.console.graphical.util.jfxButton import net.mamoe.mirai.console.graphical.util.jfxTextfield -import tornadofx.View -import tornadofx.field -import tornadofx.fieldset -import tornadofx.form +import tornadofx.* class SettingsView : View() { private val controller = find() override val root = form { -// controller.consoleConfig.forEach { -// fieldset { -// field(it.key) { -// jfxTextfield(it.value.toString()) { isEditable = false } -// } -// } -// } + + fieldset { + field { + jfxButton("撤掉") { } + jfxButton("保存") { } + } + } + + fieldset("插件目录") { + field { + jfxTextfield("...") { isEditable = false } + jfxButton("打开目录") + } + } + + fieldset("最大日志容量") { + field { + jfxTextfield("...") { + + } + } + } } } \ No newline at end of file From 10da4990391070d5acf63fb7ca1179dd05621a3d Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 23 Feb 2020 18:14:26 +0800 Subject: [PATCH 3/6] Structured Message --- .../mirai/api/http/data/common/MessageDTO.kt | 5 +- .../mamoe/mirai/qqandroid/message/messages.kt | 6 +- .../kotlin/net.mamoe.mirai/contact/Contact.kt | 8 +- .../kotlin/net.mamoe.mirai/message/data/At.kt | 7 +- .../net.mamoe.mirai/message/data/AtAll.kt | 6 +- .../message/data/CombinedMessage.kt | 10 +- .../net.mamoe.mirai/message/data/Face.kt | 2 +- .../net.mamoe.mirai/message/data/Image.kt | 2 +- .../net.mamoe.mirai/message/data/Message.kt | 41 +++++++- .../message/data/MessageChain.kt | 93 ++++++------------- .../message/data/MessageSource.kt | 2 +- .../net.mamoe.mirai/message/data/PlainText.kt | 2 +- .../message/data/QuoteReply.kt | 10 +- .../net.mamoe.mirai/message/data/XML.kt | 4 +- .../net.mamoe.mirai/message/data/builder.kt | 6 +- 15 files changed, 105 insertions(+), 99 deletions(-) diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt index d13a97f17..4d1fb8ceb 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt @@ -17,6 +17,7 @@ import net.mamoe.mirai.message.FriendMessage import net.mamoe.mirai.message.GroupMessage import net.mamoe.mirai.message.MessagePacket import net.mamoe.mirai.message.data.* +import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.MiraiInternalAPI /* @@ -99,7 +100,7 @@ fun MessageChain.toDTOChain() = mutableListOf(this[MessageSource].toDTO()).apply fun MessageChainDTO.toMessageChain(contact: Contact) = buildMessageChain { this@toMessageChain.forEach { add(it.toMessage(contact)) } } -@UseExperimental(ExperimentalUnsignedTypes::class) +@UseExperimental(ExperimentalUnsignedTypes::class, MiraiExperimentalAPI::class) fun Message.toDTO() = when (this) { is MessageSource -> MessageSourceDTO(id) is At -> AtDTO(target, display) @@ -111,7 +112,7 @@ fun Message.toDTO() = when (this) { else -> UnknownMessageDTO } -@UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class) +@UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class, MiraiExperimentalAPI::class) fun MessageDTO.toMessage(contact: Contact) = when (this) { is AtDTO -> At((contact as Group)[target]) is AtAllDTO -> AtAll diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/messages.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/messages.kt index 86261c518..875502082 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/messages.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/messages.kt @@ -326,7 +326,7 @@ internal class NotOnlineImageFromServer( internal fun MsgComm.Msg.toMessageChain(): MessageChain { val elements = this.msgBody.richText.elems - val message = ArrayList(elements.size + 1) + val message = MessageChainBuilder(elements.size + 1) message.add(MessageSourceFromMsg(delegate = this)) elements.joinToMessageChain(message) return message.asMessageChain() @@ -338,7 +338,7 @@ internal fun MsgComm.Msg.toMessageChain(): MessageChain { internal fun ImMsgBody.SourceMsg.toMessageChain(): MessageChain { val elements = this.elems!! - val message = ArrayList(elements.size + 1) + val message = MessageChainBuilder(elements.size + 1) message.add(MessageSourceFromServer(delegate = this)) elements.joinToMessageChain(message) return message.asMessageChain() @@ -346,7 +346,7 @@ internal fun ImMsgBody.SourceMsg.toMessageChain(): MessageChain { @UseExperimental(MiraiInternalAPI::class, ExperimentalUnsignedTypes::class, MiraiDebugAPI::class) -internal fun List.joinToMessageChain(message: MutableList) { +internal fun List.joinToMessageChain(message: MessageChainBuilder) { this.forEach { when { it.srcMsg != null -> message.add(QuoteReply(MessageSourceFromServer(it.srcMsg))) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt index 07cf36239..d402edb1b 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt @@ -138,9 +138,5 @@ suspend inline fun C.sendMessage(message: Message): MessageReceipt /** * @see Contact.sendMessage */ -suspend inline fun C.sendMessage(plain: String): MessageReceipt = sendMessage(plain.toMessage()) - -/** - * @see Contact.sendMessage - */ -suspend inline fun C.sendMessage(plain: CombinedMessage): MessageReceipt = sendMessage(MessageChain(plain as Message)) as MessageReceipt \ No newline at end of file +@Suppress("UNCHECKED_CAST") +suspend inline fun C.sendMessage(plain: String): MessageReceipt = sendMessage(plain.toMessage()) as MessageReceipt \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt index e21f476ea..f2413eea3 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt @@ -26,7 +26,8 @@ import kotlin.jvm.JvmName * * @see AtAll 全体成员 */ -class At @MiraiInternalAPI constructor(val target: Long, val display: String) : Message { +class At +@MiraiInternalAPI constructor(val target: Long, val display: String) : Message, MessageContent { @UseExperimental(MiraiInternalAPI::class) constructor(member: Member) : this(member.id, "@${member.nameCardOrNick}") @@ -38,9 +39,9 @@ class At @MiraiInternalAPI constructor(val target: Long, val display: String) : override fun followedBy(tail: Message): CombinedMessage { if (tail is PlainText && tail.stringValue.startsWith(' ')) { - return super.followedBy(tail) + return super.followedBy(tail) } - return super.followedBy(PlainText(" ")) + tail + return super.followedBy(PlainText(" ")) + tail } } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt index 0b9369bdd..df748ddd5 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt @@ -22,15 +22,15 @@ import kotlin.jvm.JvmName * * @see At at 单个群成员 */ -object AtAll : Message, Message.Key { +object AtAll : Message, Message.Key, MessageContent { override fun toString(): String = "@全体成员" // 自动为消息补充 " " override fun followedBy(tail: Message): CombinedMessage { if (tail is PlainText && tail.stringValue.startsWith(' ')) { - return super.followedBy(tail) + return super.followedBy(tail) } - return super.followedBy(PlainText(" ")) + tail + return super.followedBy(PlainText(" ")) + tail } } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/CombinedMessage.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/CombinedMessage.kt index 081c1116b..c29b85149 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/CombinedMessage.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/CombinedMessage.kt @@ -7,8 +7,14 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ +@file:JvmMultifileClass +@file:JvmName("MessageUtils") + package net.mamoe.mirai.message.data +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName + /** * Left-biased list */ @@ -16,6 +22,8 @@ class CombinedMessage( val left: Message, val element: Message ) : Iterable, Message { + + // 不要把它用作 local function, 会编译错误 private suspend fun SequenceScope.yieldCombinedOrElements(message: Message) { when (message) { is CombinedMessage -> { @@ -36,6 +44,6 @@ class CombinedMessage( } override fun toString(): String { - return left.toString() + element.toString() + return element.toString() + left.toString() } } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Face.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Face.kt index 0578b7c9d..88da0932c 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Face.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Face.kt @@ -18,7 +18,7 @@ import kotlin.jvm.JvmName /** * QQ 自带表情 */ -class Face(val id: Int) : Message { +class Face(val id: Int) : Message, MessageContent { override fun toString(): String = "[mirai:face$id]" /** diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt index d11c80488..f86ff59b4 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt @@ -25,7 +25,7 @@ import kotlin.jvm.JvmStatic /** * 自定义表情 (收藏的表情), 图片 */ -sealed class Image : Message { +sealed class Image : Message, MessageContent { companion object Key : Message.Key { @JvmStatic @JsName("fromId") diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt index aba05812d..c1eeb4c33 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt @@ -20,6 +20,12 @@ import kotlin.jvm.JvmSynthetic * 可发送的或从服务器接收的消息. * 采用这样的消息模式是因为 QQ 的消息多元化, 一条消息中可包含 [纯文本][PlainText], [图片][Image] 等. * + * [消息][Message] 分为 + * - [MessageMetadata] 消息元数据, 包括: [消息来源][MessageSource] + * - [MessageContent] 单个消息, 包括: [纯文本][PlainText], [@群员][At], [@全体成员][AtAll] 等. + * - [CombinedMessage] 通过 [plus] 连接的两个消息. 可通过 [asMessageChain] 转换为 [MessageChain] + * - [MessageChain] 不可变消息链, 即 [List] 形式链接的多个 [Message] 实例. + * * **在 Kotlin 使用 [Message]** * 这与使用 [String] 的使用非常类似. * @@ -44,6 +50,10 @@ import kotlin.jvm.JvmSynthetic * @see PlainText 纯文本 * @see Image 图片 * @see Face 表情 + * @see At 引用一个群成员 + * @see AtAll 引用全体成员 + * @see QuoteReply 引用一条消息 + * * @see MessageChain 消息链(即 `List`) * * @see Contact.sendMessage 发送消息 @@ -86,8 +96,6 @@ interface Message { */ @JvmSynthetic // in java they should use `plus` instead fun followedBy(tail: Message): CombinedMessage { - require(tail !is SingleOnly) { "SingleOnly Message cannot follow another message" } - require(this !is SingleOnly) { "SingleOnly Message cannot be followed" } return CombinedMessage(tail, this) } @@ -100,12 +108,35 @@ interface Message { operator fun plus(another: CharSequence): CombinedMessage = this.followedBy(another.toString().toMessage()) } +suspend fun Message.sendTo(contact: C): MessageReceipt { + return contact.sendMessage(this) +} + /** - * 表示这个 [Message] 仅能单个存在, 无法被连接. + * 消息元数据, 即不含内容的元素. + * 包括: [MessageSource] */ -interface SingleOnly : Message +interface MessageMetadata : Message { + /* + fun iterator(): Iterator { + return object : Iterator { + var visited: Boolean = false + override fun hasNext(): Boolean = !visited + override fun next(): Message { + if (visited) throw NoSuchElementException() + return this@MessageMetadata.also { visited = true } + } + } + }*/ +} + +/** + * 消息内容 + */ +interface MessageContent : Message /** * 将 [this] 发送给指定联系人 */ -suspend inline fun Message.sendTo(contact: C): MessageReceipt = contact.sendMessage(this) \ No newline at end of file +@Suppress("UNCHECKED_CAST") +suspend inline fun MessageChain.sendTo(contact: C): MessageReceipt = contact.sendMessage(this) as MessageReceipt \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt index 529121372..aac7d95b9 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt @@ -16,27 +16,19 @@ import net.mamoe.mirai.message.data.NullMessageChain.toString import kotlin.js.JsName import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmName +import kotlin.jvm.JvmSynthetic import kotlin.reflect.KProperty /** - * 消息链. 即 MutableList. + * 消息链. * 它的一般实现为 [MessageChainImpl], `null` 实现为 [NullMessageChain] * - * 有关 [MessageChain] 的创建和连接: - * - 当任意两个不是 [MessageChain] 的 [Message] 相连接后, 将会产生一个 [MessageChain]. - * - 若两个 [MessageChain] 连接, 后一个将会被合并到第一个内. - * - 若一个 [MessageChain] 与一个其他 [Message] 连接, [Message] 将会被添加入 [MessageChain]. - * - 若一个 [Message] 与一个 [MessageChain] 连接, [Message] 将会被添加入 [MessageChain]. - * * 要获取更多信息, 请查看 [Message] * - * @see buildMessageChain + * @see buildMessageChain 构造一个 [MessageChain] */ -interface MessageChain : Message, List { - // region Message override +interface MessageChain : Message, Iterable { override operator fun contains(sub: String): Boolean - // endregion - override fun toString(): String /** @@ -51,29 +43,16 @@ interface MessageChain : Message, List { * 遍历每一个有内容的消息, 即 [At], [AtAll], [PlainText], [Image], [Face], [XMLMessage] */ inline fun MessageChain.foreachContent(block: (Message) -> Unit) { - this.forEachIndexed { index: Int, message: Message -> + var last: Message? = null + this.forEach { message: Message -> if (message is At) { - if (index == 0 || this[index - 1] !is QuoteReply) { + if (last != null || last !is QuoteReply) { block(message) } - } else if (message.hasContent()) { + } else if (message is MessageContent) { block(message) } - } -} - -/** - * 判断这个 [Message] 是否含有内容, 即是否为 [At], [AtAll], [PlainText], [Image], [Face], [XMLMessage] - */ -fun Message.hasContent(): Boolean { - return when (this) { - is At, - is AtAll, - is PlainText, - is Image, - is Face, - is XMLMessage -> true - else -> false + last = message } } @@ -109,7 +88,7 @@ fun MessageChain(vararg messages: Message): MessageChain = @JsName("newChain") @Suppress("FunctionName") fun MessageChain(message: Message): MessageChain = - MessageChainImpl(listOf(message)) + SingleMessageChainImpl(message) /** * 构造 [MessageChain] @@ -136,13 +115,19 @@ fun MessageChain(messages: List): MessageChain = * 否则将调用 [MessageChain] 构造一个 [MessageChainImpl] */ @Suppress("NOTHING_TO_INLINE") -inline fun Message.toChain(): MessageChain = if (this is MessageChain) this else MessageChain(this) +@JvmSynthetic +fun Message.toChain(): MessageChain = when (this) { + is MessageChain -> this + is CombinedMessage -> MessageChainImpl(this) + else -> SingleMessageChainImpl(this) +} /** * 构造 [MessageChain] */ +@JvmSynthetic @Suppress("unused", "NOTHING_TO_INLINE") -inline fun List.asMessageChain(): MessageChain = MessageChain(this) +fun Iterable.asMessageChain(): MessageChain = MessageChainImpl(this) /** * 获取第一个 [M] 类型的 [Message] 实例 @@ -200,45 +185,25 @@ object EmptyMessageChain : MessageChain by { * 除 [toString] 外, 其他方法均 [error] */ object NullMessageChain : MessageChain { - override fun subList(fromIndex: Int, toIndex: Int): MutableList = error("accessing NullMessageChain") - override fun toString(): String = "null" - override fun contains(sub: String): Boolean = error("accessing NullMessageChain") - override fun contains(element: Message): Boolean = error("accessing NullMessageChain") override fun followedBy(tail: Message): CombinedMessage = CombinedMessage(left = EmptyMessageChain, element = tail) - - override val size: Int get() = error("accessing NullMessageChain") - override fun containsAll(elements: Collection): Boolean = error("accessing NullMessageChain") - override fun get(index: Int): Message = error("accessing NullMessageChain") - override fun indexOf(element: Message): Int = error("accessing NullMessageChain") - override fun isEmpty(): Boolean = error("accessing NullMessageChain") override fun iterator(): MutableIterator = error("accessing NullMessageChain") - - override fun lastIndexOf(element: Message): Int = error("accessing NullMessageChain") - override fun listIterator(): MutableListIterator = error("accessing NullMessageChain") - - override fun listIterator(index: Int): MutableListIterator = error("accessing NullMessageChain") } -/** - * [MessageChain] 实现 - * 它是一个特殊的 [Message], 实现 [MutableList] 接口, 但将所有的接口调用都转到内部维护的另一个 [MutableList]. - */ +@PublishedApi internal class MessageChainImpl constructor( - /** - * Elements will not be instances of [MessageChain] - */ - private val delegate: List -) : Message, List by delegate, MessageChain { + private val delegate: Iterable +) : Message, Iterable by delegate, MessageChain { override fun toString(): String = this.delegate.joinToString("") { it.toString() } - override operator fun contains(sub: String): Boolean = delegate.any { it.contains(sub) } - override fun followedBy(tail: Message): CombinedMessage { - require(tail !is SingleOnly) { "SingleOnly Message cannot follow another message" } - // if (tail is MessageChain) tail.forEach { child -> this.followedBy(child) } - // else this.delegate.add(tail) - return CombinedMessage(tail, this) - } } +@PublishedApi +internal class SingleMessageChainImpl constructor( + private val delegate: Message +) : Message, Iterable by listOf(delegate), MessageChain { + override fun toString(): String = this.delegate.toString() + + override operator fun contains(sub: String): Boolean = sub in delegate +} \ No newline at end of file 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 e57f8711c..992129835 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 @@ -23,7 +23,7 @@ import kotlin.jvm.JvmName * * @see MessageSource.quote 引用这条消息, 创建 [MessageChain] */ -interface MessageSource : Message { +interface MessageSource : Message, MessageMetadata { companion object Key : Message.Key /** diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/PlainText.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/PlainText.kt index 36fc92c02..e76a34e2b 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/PlainText.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/PlainText.kt @@ -21,7 +21,7 @@ import kotlin.jvm.JvmStatic * * 一般不需要主动构造 [PlainText], [Message] 可直接与 [String] 相加. Java 用户请使用 [MessageChain.plus] */ -inline class PlainText(val stringValue: String) : Message { +inline class PlainText(val stringValue: String) : Message, MessageContent { constructor(charSequence: CharSequence) : this(charSequence.toString()) override operator fun contains(sub: String): Boolean = sub in stringValue diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt index 494a1f280..137389190 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt @@ -21,25 +21,27 @@ import kotlin.jvm.JvmName /** - * 群内的或好友的引用回复. + * 从服务器接收的或客户端构造用来发送的群内的或好友的引用回复. * * 可以引用一条群消息并发送给一个好友, 或是引用好友消息发送给群. * 可以引用自己发出的消息. 详见 [MessageReceipt.quote] * * 总是使用 [quote] 来构造这个实例. */ -open class QuoteReply @MiraiInternalAPI constructor(val source: MessageSource) : Message { +open class QuoteReply +@MiraiInternalAPI constructor(val source: MessageSource) : Message, MessageContent { companion object Key : Message.Key override fun toString(): String = "" } /** - * 群内的引用回复. + * 用于发送的引用回复. * 总是使用 [quote] 来构造实例. */ @UseExperimental(MiraiInternalAPI::class) -class QuoteReplyToSend @MiraiInternalAPI constructor(source: MessageSource, val sender: QQ) : QuoteReply(source) { +class QuoteReplyToSend +@MiraiInternalAPI constructor(source: MessageSource, val sender: QQ) : QuoteReply(source) { fun createAt(): At = At(sender as Member) } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/XML.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/XML.kt index 83bd973a5..fb01e7c6c 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/XML.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/XML.kt @@ -23,8 +23,8 @@ import kotlin.jvm.JvmName * * @see buildXMLMessage */ -inline class XMLMessage(val stringValue: String) : Message, - SingleOnly { +@MiraiExperimentalAPI +inline class XMLMessage(val stringValue: String) : Message, MessageContent { override fun followedBy(tail: Message): Nothing = error("XMLMessage Message cannot be followed") override fun toString(): String = stringValue } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/builder.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/builder.kt index d2d11b445..86060a517 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/builder.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/builder.kt @@ -22,8 +22,10 @@ inline fun buildMessageChain(block: MessageChainBuilder.() -> Unit): MessageChai } class MessageChainBuilder @JvmOverloads constructor( - private val container: MutableList = mutableListOf() -) : MutableList by container, Appendable { + private val container: MutableCollection = mutableListOf() +) : MutableCollection by container, Appendable { + constructor(initialSize: Int) : this(ArrayList(initialSize)) + operator fun Message.unaryPlus() { add(this) } From 11c1cfc5db29ba6636a70c7b051c8a7fdea76726 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 23 Feb 2020 18:17:00 +0800 Subject: [PATCH 4/6] Add `buildMessageChain` reference --- .../commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt index c1eeb4c33..61fd913e5 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt @@ -55,6 +55,7 @@ import kotlin.jvm.JvmSynthetic * @see QuoteReply 引用一条消息 * * @see MessageChain 消息链(即 `List`) + * @see buildMessageChain 构造一个 [MessageChain] * * @see Contact.sendMessage 发送消息 */ From babc21198c2ae1686522bd03c2a83b1182ec3834 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 23 Feb 2020 19:31:26 +0800 Subject: [PATCH 5/6] Add timeout --- .../network/protocol/packet/chat/receive/MessageSvc.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt index b2dab4e51..7207413db 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt @@ -285,7 +285,7 @@ internal class MessageSvc { @UseExperimental(MiraiExperimentalAPI::class) fun startWaitingSequenceId(contact: Contact) { - sequenceIdDeferred = contact.subscribingGetAsync { + sequenceIdDeferred = contact.subscribingGetAsync(timeoutMillis = 3000) { if (it.messageRandom == this@MessageSourceFromSend.messageRandom) { it.sequenceId } else null From 4d79a699b24e55ae9f1cbe1a9077cf340da90473 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 23 Feb 2020 20:06:45 +0800 Subject: [PATCH 6/6] Flatten messages --- .../kotlin/net.mamoe.mirai/contact/Contact.kt | 2 +- .../net.mamoe.mirai/message/data/Message.kt | 6 +- .../message/data/MessageChain.kt | 57 ++++++++++++------- .../mirai/utils/LockFreeLinkedListTest.kt | 1 + 4 files changed, 43 insertions(+), 23 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt index d402edb1b..678af1d00 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt @@ -139,4 +139,4 @@ suspend inline fun C.sendMessage(message: Message): MessageReceipt * @see Contact.sendMessage */ @Suppress("UNCHECKED_CAST") -suspend inline fun C.sendMessage(plain: String): MessageReceipt = sendMessage(plain.toMessage()) as MessageReceipt \ No newline at end of file +suspend inline fun C.sendMessage(plain: String): MessageReceipt = sendMessage(plain.toMessage()) \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt index 61fd913e5..95e068f0a 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt @@ -113,11 +113,13 @@ suspend fun Message.sendTo(contact: C): MessageReceipt { return contact.sendMessage(this) } +interface SingleMessage : Message + /** * 消息元数据, 即不含内容的元素. * 包括: [MessageSource] */ -interface MessageMetadata : Message { +interface MessageMetadata : SingleMessage { /* fun iterator(): Iterator { return object : Iterator { @@ -134,7 +136,7 @@ interface MessageMetadata : Message { /** * 消息内容 */ -interface MessageContent : Message +interface MessageContent : SingleMessage /** * 将 [this] 发送给指定联系人 diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt index aac7d95b9..54022e572 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt @@ -27,7 +27,7 @@ import kotlin.reflect.KProperty * * @see buildMessageChain 构造一个 [MessageChain] */ -interface MessageChain : Message, Iterable { +interface MessageChain : Message, Iterable { override operator fun contains(sub: String): Boolean override fun toString(): String @@ -78,7 +78,7 @@ fun MessageChain(): MessageChain = EmptyMessageChain @Suppress("FunctionName") fun MessageChain(vararg messages: Message): MessageChain = if (messages.isEmpty()) EmptyMessageChain - else MessageChainImpl(messages.toMutableList()) + else MessageChainImpl(messages.asSequence().flatten()) /** * 构造 [MessageChain] 的快速途径 (无 [Array] 创建) @@ -88,7 +88,10 @@ fun MessageChain(vararg messages: Message): MessageChain = @JsName("newChain") @Suppress("FunctionName") fun MessageChain(message: Message): MessageChain = - SingleMessageChainImpl(message) + when (message) { + is SingleMessage -> SingleMessageChainImpl(message) + else -> MessageChainImpl(message.flatten().asIterable()) + } /** * 构造 [MessageChain] @@ -97,7 +100,7 @@ fun MessageChain(message: Message): MessageChain = @JsName("newChain") @Suppress("FunctionName") fun MessageChain(messages: Iterable): MessageChain = - MessageChainImpl(messages.toList()) + MessageChainImpl(messages.flatten().asIterable()) /** * 构造 [MessageChain] @@ -106,7 +109,7 @@ fun MessageChain(messages: Iterable): MessageChain = @JsName("newChain") @Suppress("FunctionName") fun MessageChain(messages: List): MessageChain = - MessageChainImpl(messages) + MessageChainImpl(messages.flatten().asIterable()) /** @@ -114,20 +117,34 @@ fun MessageChain(messages: List): MessageChain = * 若 [this] 为 [MessageChain] 将直接返回 this * 否则将调用 [MessageChain] 构造一个 [MessageChainImpl] */ -@Suppress("NOTHING_TO_INLINE") +@Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST") @JvmSynthetic fun Message.toChain(): MessageChain = when (this) { is MessageChain -> this - is CombinedMessage -> MessageChainImpl(this) - else -> SingleMessageChainImpl(this) + is CombinedMessage -> MessageChainImpl((this as Iterable).flatten().asIterable()) + else -> SingleMessageChainImpl(this as SingleMessage) } -/** - * 构造 [MessageChain] - */ +@JvmName("asMessageChain1") @JvmSynthetic @Suppress("unused", "NOTHING_TO_INLINE") -fun Iterable.asMessageChain(): MessageChain = MessageChainImpl(this) +fun Iterable.asMessageChain(): MessageChain = MessageChainImpl(this) + +@JvmSynthetic +@Suppress("unused", "NOTHING_TO_INLINE") +fun Iterable.asMessageChain(): MessageChain = MessageChainImpl(this.flatten()) + +fun Iterable.flatten(): Sequence = asSequence().flatten() + +fun Sequence.flatten(): Sequence = flatMap { it.flatten() } + +fun Message.flatten(): Sequence { + return when (this) { + is MessageChain -> this.asSequence() + is CombinedMessage -> this.asSequence().flatten() + else -> sequenceOf(this as SingleMessage) + } +} /** * 获取第一个 [M] 类型的 [Message] 实例 @@ -174,9 +191,7 @@ fun MessageChain.first(key: Message.Key): M = firstOrNull(key) @Suppress("UNCHECKED_CAST") fun MessageChain.any(key: Message.Key): Boolean = firstOrNull(key) != null -object EmptyMessageChain : MessageChain by { - MessageChainImpl(emptyList()) -}() +object EmptyMessageChain : MessageChain by MessageChainImpl(emptyList()) /** * Null 的 [MessageChain]. @@ -188,21 +203,23 @@ object NullMessageChain : MessageChain { override fun toString(): String = "null" override fun contains(sub: String): Boolean = error("accessing NullMessageChain") override fun followedBy(tail: Message): CombinedMessage = CombinedMessage(left = EmptyMessageChain, element = tail) - override fun iterator(): MutableIterator = error("accessing NullMessageChain") + override fun iterator(): MutableIterator = error("accessing NullMessageChain") } @PublishedApi internal class MessageChainImpl constructor( - private val delegate: Iterable -) : Message, Iterable by delegate, MessageChain { + private val delegate: Iterable +) : Message, Iterable by delegate, MessageChain { + constructor(delegate: Sequence) : this(delegate.asIterable()) + override fun toString(): String = this.delegate.joinToString("") { it.toString() } override operator fun contains(sub: String): Boolean = delegate.any { it.contains(sub) } } @PublishedApi internal class SingleMessageChainImpl constructor( - private val delegate: Message -) : Message, Iterable by listOf(delegate), MessageChain { + private val delegate: SingleMessage +) : Message, Iterable by listOf(delegate), MessageChain { override fun toString(): String = this.delegate.toString() override operator fun contains(sub: String): Boolean = sub in delegate diff --git a/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/utils/LockFreeLinkedListTest.kt b/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/utils/LockFreeLinkedListTest.kt index 7de786955..de4c3b195 100644 --- a/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/utils/LockFreeLinkedListTest.kt +++ b/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/utils/LockFreeLinkedListTest.kt @@ -56,6 +56,7 @@ internal class LockFreeLinkedListTest { //} } + @Suppress("UNREACHABLE_CODE", "DeferredResultUnused") @Test fun `so many concurrent add remove and foreach`() = runBlocking { return@runBlocking // 测试通过了, 加快速度. 因为 kotlin 一些其他 bug