From 33409f3a822068e1ee219042d6bd1674a4ab08bc Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 4 Dec 2019 12:53:30 +0800 Subject: [PATCH] Add docs and more useful functions --- .../event/MessageSubscribers.kt | 126 +++++++++++++++--- .../java/demo/subscribe/SubscribeSamples.kt | 2 +- 2 files changed, 106 insertions(+), 22 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt index 58b5e155d..478466622 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt @@ -3,6 +3,9 @@ package net.mamoe.mirai.event import net.mamoe.mirai.Bot +import net.mamoe.mirai.contact.isAdministrator +import net.mamoe.mirai.contact.isOperator +import net.mamoe.mirai.contact.isOwner import net.mamoe.mirai.message.Message import net.mamoe.mirai.message.any import net.mamoe.mirai.network.protocol.tim.packet.event.FriendMessage @@ -18,12 +21,12 @@ import kotlin.jvm.JvmName */ @UseExperimental(ExperimentalContracts::class) @MessageDsl -suspend inline fun subscribeMessages(crossinline listeners: suspend MessageSubscribersBuilder>.() -> Unit) { +suspend inline fun subscribeMessages(crossinline listeners: suspend MessageSubscribersBuilder>.() -> Unit) { contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) } - MessageSubscribersBuilder> { listener -> - subscribeAlways> { + MessageSubscribersBuilder> { listener -> + subscribeAlways> { listener(it) } }.apply { listeners() } @@ -66,12 +69,12 @@ suspend inline fun subscribeFriendMessages(crossinline listeners: suspend Messag */ @UseExperimental(ExperimentalContracts::class) @MessageDsl -suspend inline fun Bot.subscribeMessages(crossinline listeners: suspend MessageSubscribersBuilder>.() -> Unit) { +suspend inline fun Bot.subscribeMessages(crossinline listeners: suspend MessageSubscribersBuilder>.() -> Unit) { contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) } - MessageSubscribersBuilder> { listener -> - this.subscribeAlways> { + MessageSubscribersBuilder> { listener -> + this.subscribeAlways> { listener(it) } }.apply { listeners() } @@ -111,11 +114,11 @@ suspend inline fun Bot.subscribeFriendMessages(crossinline listeners: suspend Me private typealias AnyReplier = @MessageDsl suspend T.(String) -> Any? -private suspend inline operator fun > (@MessageDsl suspend T.(String) -> Unit).invoke(t: T) = +private suspend inline operator fun > (@MessageDsl suspend T.(String) -> Unit).invoke(t: T) = this.invoke(t, t.message.stringValue) @JvmName("invoke1") //Avoid Platform declaration clash -private suspend inline operator fun > AnyReplier.invoke(t: T): Any? = +private suspend inline operator fun > AnyReplier.invoke(t: T): Any? = this.invoke(t, t.message.stringValue) /** @@ -127,7 +130,7 @@ private suspend inline operator fun > AnyReplier.invoke( // TODO: 2019/11/29 应定义为 inline, 但这会导致一个 JVM run-time VerifyError. 等待 kotlin 修复 bug @Suppress("unused") @MessageDsl -class MessageSubscribersBuilder>( +class MessageSubscribersBuilder>( inline val subscriber: suspend (@MessageDsl suspend T.(String) -> Unit) -> Unit ) { /** @@ -194,6 +197,27 @@ class MessageSubscribersBuilder>( @MessageDsl suspend inline fun sentBy(qqId: Long, noinline onEvent: @MessageDsl suspend T.(String) -> Unit) = sentBy(qqId.toUInt(), onEvent) + /** + * 如果是管理员或群主发的消息, 就执行 [onEvent] + */ + @MessageDsl + suspend inline fun sentByOperator(noinline onEvent: @MessageDsl suspend T.(String) -> Unit) = + content({ this is GroupMessage && sender.permission.isOperator() }, onEvent) + + /** + * 如果是管理员发的消息, 就执行 [onEvent] + */ + @MessageDsl + suspend inline fun sentByAdministrator(noinline onEvent: @MessageDsl suspend T.(String) -> Unit) = + content({ this is GroupMessage && sender.permission.isAdministrator() }, onEvent) + + /** + * 如果是群主发的消息, 就执行 [onEvent] + */ + @MessageDsl + suspend inline fun sentByOwner(noinline onEvent: @MessageDsl suspend T.(String) -> Unit) = + content({ this is GroupMessage && sender.permission.isOwner() }, onEvent) + /** * 如果是来自这个群的消息, 就执行 [onEvent] */ @@ -221,21 +245,74 @@ class MessageSubscribersBuilder>( suspend inline fun content(noinline filter: T.(String) -> Boolean, noinline onEvent: @MessageDsl suspend T.(String) -> Unit) = subscriber { if (this.filter(message.stringValue)) onEvent(this) } + /** + * 若消息内容包含 [this] 则回复 [reply] + */ @MessageDsl - suspend inline infix fun String.containsReply(replier: String) = - content({ this@containsReply in it }) { this@content.reply(replier) } + suspend inline infix fun String.containsReply(reply: String) = + content({ this@containsReply in it }) { this@content.reply(reply) } + /** + * 若消息内容包含 [this] 则执行 [replier] 并将其返回值回复给发信对象. + * + * [replier] 的 `it` 将会是消息内容 string. + * + * @param replier 若返回 [Message] 则直接发送; 若返回 [Unit] 则不回复; 其他情况则 [Any.toString] 后回复 + */ @MessageDsl suspend inline infix fun String.containsReply(noinline replier: AnyReplier) = - content({ this@containsReply in it }) { replier(this) } + content({ this@containsReply in it }) { + @Suppress("DSL_SCOPE_VIOLATION_WARNING") // false negative warning + executeAndReply(replier) + } + /** + * 不考虑空格, 若消息内容以 [this] 开始则执行 [replier] 并将其返回值回复给发信对象. + * + * [replier] 的 `it` 将会是去掉用来判断的前缀并删除前后空格后的字符串. + * 如当消息为 "kick 123456 " 时 + * ```kotlin + * "kick" startsWithReply { + * println(it) // it 为 "123456" + * } + * ``` + * + * @param replier 若返回 [Message] 则直接发送; 若返回 [Unit] 则不回复; 其他类型则 [Any.toString] 后回复 + */ @MessageDsl - suspend inline infix fun String.startsWithReply(noinline replier: AnyReplier) = - content({ it.startsWith(this@startsWithReply) }) { replier(this) } + suspend inline infix fun String.startsWithReply(noinline replier: AnyReplier) { + val toCheck = this.trimStart() + content({ it.trimStart().startsWith(toCheck) }) { + @Suppress("DSL_SCOPE_VIOLATION_WARNING") // false negative warning + executeAndReply { + replier(it.removePrefix(toCheck).trim()) + } + } + } + /** + * 不考虑空格, 若消息内容以 [this] 结尾则执行 [replier] 并将其返回值回复给发信对象. + * + * [replier] 的 `it` 将会是去掉用来判断的后缀并删除前后空格后的字符串. + * 如当消息为 " 123456 test" 时 + * ```kotlin + * "test" endswithReply { + * println(it) // it 为 "123456" + * } + * ``` + * + * @param replier 若返回 [Message] 则直接发送; 若返回 [Unit] 则不回复; 其他情况则 [Any.toString] 后回复 + */ @MessageDsl - suspend inline infix fun String.endswithReply(noinline replier: AnyReplier) = - content({ it.endsWith(this@endswithReply) }) { replier(this) } + suspend inline infix fun String.endswithReply(noinline replier: AnyReplier) { + val toCheck = this.trimEnd() + content({ it.endsWith(this@endswithReply) }) { + @Suppress("DSL_SCOPE_VIOLATION_WARNING") // false negative warning + executeAndReply { + replier(it.removeSuffix(toCheck).trim()) + } + } + } @MessageDsl suspend inline infix fun String.reply(reply: String) = case(this) { @@ -243,17 +320,23 @@ class MessageSubscribersBuilder>( } @MessageDsl - suspend inline infix fun String.reply(noinline reply: AnyReplier) = case(this) { - when (val message = reply(this)) { - is Message -> reply(message) + suspend inline infix fun String.reply(noinline replier: AnyReplier) = case(this) { + @Suppress("DSL_SCOPE_VIOLATION_WARNING") // false negative warning + executeAndReply(replier) + } + + @PublishedApi + @Suppress("NOTHING_TO_INLINE") + internal suspend inline fun T.executeAndReply(noinline replier: AnyReplier) { + when (val message = replier(this)) { + is Message -> this.reply(message) is Unit -> { } - else -> reply(message.toString()) + else -> this.reply(message.toString()) } } - /* 易产生迷惑感 suspend inline fun replyCase(equals: String, trim: Boolean = true, noinline replier: MessageReplier) = case(equals, trim) { reply(replier(this)) } suspend inline fun replyContains(value: String, noinline replier: MessageReplier) = content({ value in it }) { replier(this) } @@ -265,6 +348,7 @@ class MessageSubscribersBuilder>( /** * DSL 标记. 将能让 IDE 阻止一些错误的方法调用. */ +@Retention(AnnotationRetention.SOURCE) @Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS, AnnotationTarget.TYPE) @DslMarker internal annotation class MessageDsl \ No newline at end of file diff --git a/mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt b/mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt index 431e3f048..df6142978 100644 --- a/mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt +++ b/mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt @@ -118,7 +118,7 @@ suspend fun Bot.messageDSL() { // 如果是这个 QQ 号发送的消息(可以是好友消息也可以是群消息) - sentBy(1040400290) { + sentBy(123456789) { }