Commit 3dfaa4ee authored by Him188's avatar Him188

Powerful MessageChains

parent ffe8339c
...@@ -24,15 +24,8 @@ sealed class Contact(val bot: Bot, val id: UInt) { ...@@ -24,15 +24,8 @@ sealed class Contact(val bot: Bot, val id: UInt) {
abstract suspend fun sendMessage(message: MessageChain) abstract suspend fun sendMessage(message: MessageChain)
suspend fun sendMessage(message: Message) { suspend fun sendMessage(message: Message) = sendMessage(message.toChain())
if (message is MessageChain) { suspend fun sendMessage(plain: String) = sendMessage(PlainText(plain))
return sendMessage(message)
}
return sendMessage(message.toChain())
}
suspend fun sendMessage(plain: String) = this.sendMessage(PlainText(plain))
abstract suspend fun sendXMLMessage(message: String) abstract suspend fun sendXMLMessage(message: String)
} }
......
...@@ -70,8 +70,8 @@ interface Message { ...@@ -70,8 +70,8 @@ interface Message {
* ``` * ```
*/ */
fun concat(tail: Message): MessageChain = fun concat(tail: Message): MessageChain =
if (tail is MessageChain) MessageChain(this).also { tail.forEach { child -> it.concat(child) } } if (tail is MessageChain) tail.concat(this)/*MessageChainImpl(this).also { tail.forEach { child -> it.concat(child) } }*/
else MessageChain(this, tail) else MessageChainImpl(this, tail)
infix operator fun plus(another: Message): MessageChain = this.concat(another) infix operator fun plus(another: Message): MessageChain = this.concat(another)
infix operator fun plus(another: String): MessageChain = this.concat(another.toMessage()) infix operator fun plus(another: String): MessageChain = this.concat(another.toMessage())
...@@ -129,23 +129,142 @@ inline class Face(val id: FaceID) : Message { ...@@ -129,23 +129,142 @@ inline class Face(val id: FaceID) : Message {
} }
// ==================================== MessageChain ==================================== // ==================================== MessageChain ====================================
/**
* 构造无初始元素的可修改的 [MessageChain]. 初始大小将会被设定为 8
*/
@Suppress("FunctionName")
fun MessageChain(): MessageChain = MessageChainImpl(ArrayList(8))
/**
* 构造无初始元素的可修改的 [MessageChain]. 初始大小将会被设定为 [initialCapacity]
*/
@Suppress("FunctionName")
fun MessageChain(initialCapacity: Int): MessageChain = MessageChainImpl(ArrayList(initialCapacity))
/**
* 构造 [MessageChain]
* 若仅提供一个参数, 请考虑使用 [Message.toChain] 以优化性能
*/
@Suppress("FunctionName")
fun MessageChain(vararg messages: Message): MessageChain = MessageChainImpl(messages.toMutableList())
/**
* 构造 [MessageChain]
*/
@Suppress("FunctionName")
fun MessageChain(messages: Iterable<Message>): MessageChain = MessageChainImpl(messages.toMutableList())
/**
* 构造单元素的不可修改的 [MessageChain]. 内部类实现为 [SingleMessageChain]
*
* 参数 [delegate] 不能为 [MessageChain] 的实例, 否则将会抛出异常.
* 使用 [Message.toChain] 将帮助提前处理这个问题.
*
* @param delegate 所构造的单元素 [MessageChain] 代表的 [Message]
* @throws IllegalArgumentException 当 [delegate] 为 [MessageChain] 的实例时
* @see Message.toChain 将
*/
@Suppress("FunctionName")
fun SingleMessageChain(delegate: Message): MessageChain {
require(delegate !is MessageChain) { "delegate for SingleMessageChain should not be any instance of MessageChain" }
return SingleMessageChainImpl(delegate)
}
/** /**
* 消息链. 即 MutableList<Message>. * 消息链. 即 MutableList<Message>.
* 它是一个特殊的 [Message], 实现 [MutableList] 接口, 但将所有的接口调用都转到内部维护的另一个 [MutableList], [delegate] * 它的一般实现为 [MessageChainImpl], `null` 实现为 [NullMessageChain]
* *
* 有关 [MessageChain] 的创建和连接: * 有关 [MessageChain] 的创建和连接:
* - 当任意两个不是 [MessageChain] 的 [Message] 相连接后, 将会产生一个 [MessageChain]. * - 当任意两个不是 [MessageChain] 的 [Message] 相连接后, 将会产生一个 [MessageChain].
* - 若两个 [MessageChain] 连接, 后一个将会被添加到第一个内. * - 若两个 [MessageChain] 连接, 后一个将会被合并到第一个内.
* - 若一个 [MessageChain] 与一个其他 [Message] 连接, [Message] 将会被添加入 [MessageChain]. * - 若一个 [MessageChain] 与一个其他 [Message] 连接, [Message] 将会被添加入 [MessageChain].
* - 若一个 [Message] 与一个 [MessageChain] 连接, 将会创建一个新的 [MessageChain], 并顺序添加连接时的参数. * - 若一个 [Message] 与一个 [MessageChain] 连接, [Message] 将会被添加入 [MessageChain].
*/
interface MessageChain : Message, MutableList<Message> {
// region Message override
override val stringValue: String
override operator fun contains(sub: String): Boolean
override fun concat(tail: Message): MessageChain
// endregion
operator fun plusAssign(message: Message) {
this.concat(message)
}
operator fun plusAssign(plain: String) {
this.concat(plain.toMessage())
}
}
/**
* Null 的 [MessageChain].
* 它不包含任何元素, 也没有创建任何 list.
*
* - 所有 get 方法均抛出 [NoSuchElementException]
* - 所有 add 方法均抛出 [UnsupportedOperationException]
* - 其他判断类方法均 false 或 -1
*/ */
inline class MessageChain constructor( object NullMessageChain : MessageChain {
override fun subList(fromIndex: Int, toIndex: Int): MutableList<Message> = unsupported()
override val stringValue: String
get() = ""
override fun contains(sub: String): Boolean = false
override fun contains(element: Message): Boolean = false
override fun concat(tail: Message): MessageChain = MessageChainImpl(tail)
override val size: Int = 0
override fun containsAll(elements: Collection<Message>): Boolean = false
override fun get(index: Int): Message = throw NoSuchElementException()
override fun indexOf(element: Message): Int = -1
override fun isEmpty(): Boolean = true
override fun iterator(): MutableIterator<Message> = object : MutableIterator<Message> {
override fun hasNext(): Boolean = false
override fun next(): Message = throw NoSuchElementException()
override fun remove() = throw NoSuchElementException()
}
override fun lastIndexOf(element: Message): Int = -1
override fun add(element: Message): Boolean = unsupported()
override fun add(index: Int, element: Message) = unsupported()
override fun addAll(index: Int, elements: Collection<Message>): Boolean = unsupported()
override fun addAll(elements: Collection<Message>): Boolean = unsupported()
override fun clear() {}
override fun listIterator(): MutableListIterator<Message> = object : MutableListIterator<Message> {
override fun hasPrevious(): Boolean = false
override fun nextIndex(): Int = -1
override fun previous(): Message = throw NoSuchElementException()
override fun previousIndex(): Int = -1
override fun add(element: Message) = unsupported()
override fun hasNext(): Boolean = false
override fun next(): Message = throw NoSuchElementException()
override fun remove() = throw NoSuchElementException()
override fun set(element: Message) = unsupported()
}
override fun listIterator(index: Int): MutableListIterator<Message> = unsupported()
override fun remove(element: Message): Boolean = false
override fun removeAll(elements: Collection<Message>): Boolean = false
override fun removeAt(index: Int): Message = throw NoSuchElementException()
override fun retainAll(elements: Collection<Message>): Boolean = false
override fun set(index: Int, element: Message): Message = unsupported()
private fun unsupported(): Nothing = throw UnsupportedOperationException()
}
/**
* [MessageChain] 实现
* 它是一个特殊的 [Message], 实现 [MutableList] 接口, 但将所有的接口调用都转到内部维护的另一个 [MutableList].
*/
internal inline class MessageChainImpl constructor(
/** /**
* Elements will not be instances of [MessageChain] * Elements will not be instances of [MessageChain]
*/ */
private val delegate: MutableList<Message> private val delegate: MutableList<Message>
) : Message, MutableList<Message> { ) : Message, MutableList<Message>, MessageChain {
constructor() : this(ArrayList(8)) constructor() : this(ArrayList(8))
constructor(initialCapacity: Int) : this(ArrayList(initialCapacity))
constructor(vararg messages: Message) : this(messages.toMutableList()) constructor(vararg messages: Message) : this(messages.toMutableList())
constructor(messages: Iterable<Message>) : this(messages.toMutableList()) constructor(messages: Iterable<Message>) : this(messages.toMutableList())
...@@ -154,33 +273,20 @@ inline class MessageChain constructor( ...@@ -154,33 +273,20 @@ inline class MessageChain constructor(
override operator fun contains(sub: String): Boolean = delegate.any { it.contains(sub) } override operator fun contains(sub: String): Boolean = delegate.any { it.contains(sub) }
override fun concat(tail: Message): MessageChain { override fun concat(tail: Message): MessageChain {
if (tail is MessageChain) tail.delegate.forEach { child -> this.concat(child) } if (tail is MessageChain) tail.forEach { child -> this.concat(child) }
else this.delegate.add(tail) else this.delegate.add(tail)
return this return this
} }
// endregion
/**
* 获取第一个 [M] 类型的实例
* @throws [NoSuchElementException] 如果找不到该类型的实例
*/
inline fun <reified M : Message> first(): Message = this.first { M::class.isInstance(it) }
/** // endregion
* 获取第一个 [M] 类型的实例 override operator fun plusAssign(message: Message) {
*/
inline fun <reified M : Message> firstOrNull(): Message? = this.firstOrNull { M::class.isInstance(it) }
operator fun plusAssign(message: Message) {
this.concat(message) this.concat(message)
} }
operator fun plusAssign(plain: String) { override operator fun plusAssign(plain: String) {
this.concat(plain.toMessage()) this.concat(plain.toMessage())
} }
// region MutableList override // region MutableList override
override fun containsAll(elements: Collection<Message>): Boolean = delegate.containsAll(elements) override fun containsAll(elements: Collection<Message>): Boolean = delegate.containsAll(elements)
...@@ -205,4 +311,96 @@ inline class MessageChain constructor( ...@@ -205,4 +311,96 @@ inline class MessageChain constructor(
override operator fun contains(element: Message): Boolean = delegate.contains(element) override operator fun contains(element: Message): Boolean = delegate.contains(element)
override val size: Int get() = delegate.size override val size: Int get() = delegate.size
// endregion // endregion
} }
\ No newline at end of file
/**
* 单个成员的不可修改的 [MessageChain].
* 在连接时将会把它当做一个普通 [Message] 看待.
*/
internal inline class SingleMessageChainImpl(
private val delegate: Message
) : Message, MutableList<Message>, MessageChain {
// region Message override
override val stringValue: String get() = this.delegate.stringValue
override operator fun contains(sub: String): Boolean = delegate.contains(sub)
override fun concat(tail: Message): MessageChain {
if (tail is MessageChain) tail.forEach { child -> this.concat(child) }
else MessageChain(delegate, tail)
return this
}
// endregion
// region MutableList override
override fun containsAll(elements: Collection<Message>): Boolean = elements.all { it === delegate }
override operator fun get(index: Int): Message = if (index == 0) delegate else throw NoSuchElementException()
override fun indexOf(element: Message): Int = if (delegate === element) 0 else -1
override fun isEmpty(): Boolean = false
override fun lastIndexOf(element: Message): Int = if (delegate === element) 0 else -1
override fun add(element: Message): Boolean = throw UnsupportedOperationException()
override fun add(index: Int, element: Message) = throw UnsupportedOperationException()
override fun addAll(index: Int, elements: Collection<Message>): Boolean = throw UnsupportedOperationException()
override fun addAll(elements: Collection<Message>): Boolean = throw UnsupportedOperationException()
override fun clear() = throw UnsupportedOperationException()
override fun listIterator(): MutableListIterator<Message> = object : MutableListIterator<Message> {
private var hasNext = true
override fun hasPrevious(): Boolean = false
override fun nextIndex(): Int = if (hasNext) 0 else -1
override fun previous(): Message = throw NoSuchElementException()
override fun previousIndex(): Int = -1
override fun add(element: Message) = throw UnsupportedOperationException()
override fun hasNext(): Boolean = !hasNext
override fun next(): Message =
if (hasNext) {
hasNext = false
this@SingleMessageChainImpl
} else throw NoSuchElementException()
override fun remove() = throw UnsupportedOperationException()
override fun set(element: Message) = throw UnsupportedOperationException()
}
override fun listIterator(index: Int): MutableListIterator<Message> = throw UnsupportedOperationException()
override fun remove(element: Message): Boolean = throw UnsupportedOperationException()
override fun removeAll(elements: Collection<Message>): Boolean = throw UnsupportedOperationException()
override fun removeAt(index: Int): Message = throw UnsupportedOperationException()
override fun retainAll(elements: Collection<Message>): Boolean = throw UnsupportedOperationException()
override fun set(index: Int, element: Message): Message = throw UnsupportedOperationException()
override fun subList(fromIndex: Int, toIndex: Int): MutableList<Message> {
return if (fromIndex == 0) when (toIndex) {
1 -> mutableListOf<Message>(this)
0 -> mutableListOf()
else -> throw UnsupportedOperationException()
}
else throw UnsupportedOperationException()
}
override fun iterator(): MutableIterator<Message> = object : MutableIterator<Message> {
private var hasNext = true
override fun hasNext(): Boolean = !hasNext
override fun next(): Message =
if (hasNext) {
hasNext = false
this@SingleMessageChainImpl
} else throw NoSuchElementException()
override fun remove() = throw UnsupportedOperationException()
}
override operator fun contains(element: Message): Boolean = element === delegate
override val size: Int get() = 1
// endregion
}
/**
* 获取第一个 [M] 类型的实例
*/
inline fun <reified M : Message> MessageChain.firstOrNull(): Message? = this.firstOrNull { M::class.isInstance(it) }
/**
* 获取第一个 [M] 类型的实例
* @throws [NoSuchElementException] 如果找不到该类型的实例
*/
inline fun <reified M : Message> MessageChain.first(): Message = this.first { M::class.isInstance(it) }
\ No newline at end of file
...@@ -7,9 +7,20 @@ package net.mamoe.mirai.message ...@@ -7,9 +7,20 @@ package net.mamoe.mirai.message
fun String.toMessage(): PlainText = PlainText(this) fun String.toMessage(): PlainText = PlainText(this)
/** /**
* 构造 [MessageChain] * 得到包含 [this] 的 [MessageChain].
* 若 [this] 为 [MessageChain] 将直接返回 this
* 否则将调用 [SingleMessageChain] 构造一个唯一成员不可修改的 [SingleMessageChainImpl]
*
* @see SingleMessageChain
* @see SingleMessageChainImpl
*/
fun Message.toChain(): MessageChain = if (this is MessageChain) this else SingleMessageChain(this)
/**
* 以 [this] 为代表 (delegate) 构造 [SingleMessageChain].
* @throws IllegalArgumentException 当 [this] 为 [MessageChain] 的实例时
*/ */
fun Message.toChain(): MessageChain = if (this is MessageChain) this else MessageChain(this) fun Message.singleChain(): MessageChain = SingleMessageChain(this)
/** /**
* 构造 [MessageChain] * 构造 [MessageChain]
......
...@@ -6,6 +6,7 @@ import kotlinx.io.core.ByteReadPacket ...@@ -6,6 +6,7 @@ import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact import kotlinx.io.core.discardExact
import kotlinx.io.core.readUInt import kotlinx.io.core.readUInt
import net.mamoe.mirai.message.MessageChain import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.message.NullMessageChain
import net.mamoe.mirai.message.internal.readMessageChain import net.mamoe.mirai.message.internal.readMessageChain
import net.mamoe.mirai.utils.io.* import net.mamoe.mirai.utils.io.*
import kotlin.properties.Delegates import kotlin.properties.Delegates
...@@ -26,7 +27,7 @@ class ServerGroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventP ...@@ -26,7 +27,7 @@ class ServerGroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventP
* 发送方权限. * 发送方权限.
*/ */
lateinit var senderPermission: SenderPermission lateinit var senderPermission: SenderPermission
var message: MessageChain by Delegates.notNull() var message: MessageChain = NullMessageChain
override fun decode() = with(input) { override fun decode() = with(input) {
discardExact(31) discardExact(31)
......
...@@ -23,39 +23,42 @@ internal object PacketNameFormatter { ...@@ -23,39 +23,42 @@ internal object PacketNameFormatter {
} }
private object IgnoreIdList : List<String> by listOf( private object IgnoreIdList : List<String> by listOf(
"idHex", "idHex",
"id", "id",
"packetId", "packetId",
"sequenceIdInternal", "sequenceIdInternal",
"sequenceId", "sequenceId",
"fixedId", "fixedId",
"idByteArray", "idByteArray",
"encoded", "encoded",
"packet", "packet",
"Companion", "Companion",
"EMPTY_ID_HEX", "EMPTY_ID_HEX",
"input", "input",
"output", "output",
"UninitializedByteReadPacket", "this\$0",
"sessionKey" "\$\$delegatedProperties",
"UninitializedByteReadPacket",
"sessionKey"
) )
internal actual fun Packet.packetToString(): String = PacketNameFormatter.adjustName(this::class.simpleName + "(${this.idHexString})") + this::class.java.allDeclaredFields internal actual fun Packet.packetToString(): String = PacketNameFormatter.adjustName(this::class.simpleName + "(${this.idHexString})") + this::class.java.allDeclaredFields
.filterNot { it.name in IgnoreIdList || /*"delegate" in it.name||*/ "$" in it.name } .filterNot { it.name in IgnoreIdList /*|| "delegate" in it.name|| "$" in it.name */ }
.joinToString(", ", "{", "}") { .joinToString(", ", "{", "}") {
it.isAccessible = true it.isAccessible = true
it.name + "=" + it.get(this).let { value -> it.name.replace("\$delegate", "") + "=" + it.get(this).let { value ->
when (value) { when (value) {
null -> null null -> null
is ByteArray -> value.toUHexString() is ByteArray -> value.toUHexString()
is UByteArray -> value.toUHexString() is UByteArray -> value.toUHexString()
is ByteReadPacket -> "[ByteReadPacket(${value.remaining})]" is ByteReadPacket -> "[ByteReadPacket(${value.remaining})]"
//is ByteReadPacket -> value.copy().readBytes().toUHexString() //is ByteReadPacket -> value.copy().readBytes().toUHexString()
is IoBuffer -> "[IoBuffer(${value.readRemaining})]" is IoBuffer -> "[IoBuffer(${value.readRemaining})]"
else -> value.toString() is Lazy<*> -> "[Lazy]"
} else -> value.toString()
} }
} }
}
private val Class<*>.allDeclaredFields: List<Field> private val Class<*>.allDeclaredFields: List<Field>
get() { get() {
......
...@@ -15,6 +15,7 @@ import net.mamoe.mirai.login ...@@ -15,6 +15,7 @@ import net.mamoe.mirai.login
import net.mamoe.mirai.message.Image import net.mamoe.mirai.message.Image
import net.mamoe.mirai.message.ImageId import net.mamoe.mirai.message.ImageId
import net.mamoe.mirai.message.PlainText import net.mamoe.mirai.message.PlainText
import net.mamoe.mirai.message.firstOrNull
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingRawPacket import net.mamoe.mirai.network.protocol.tim.packet.OutgoingRawPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
import net.mamoe.mirai.network.protocol.tim.packet.uploadImage import net.mamoe.mirai.network.protocol.tim.packet.uploadImage
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment