From 6bb8231d8e0106e0c3bd2f1c260999051839b78d Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 22 Mar 2020 16:24:58 +0800 Subject: [PATCH] Prohibit unsafe usage --- .../kotlin/net.mamoe.mirai/event/select.kt | 66 ++++++++- .../event/subscribeMessages.kt | 132 ++++++++++-------- 2 files changed, 134 insertions(+), 64 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/select.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/select.kt index 96b0d8f16..405cf55e9 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/select.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/select.kt @@ -11,6 +11,7 @@ package net.mamoe.mirai.event import kotlinx.coroutines.* import net.mamoe.mirai.message.MessagePacket +import net.mamoe.mirai.message.data.Message import net.mamoe.mirai.message.isContextIdenticalWith import net.mamoe.mirai.message.nextMessage import net.mamoe.mirai.utils.MiraiExperimentalAPI @@ -50,7 +51,6 @@ import kotlin.jvm.JvmSynthetic */ @SinceMirai("0.29.0") @Suppress("unused") -@MiraiExperimentalAPI suspend inline fun > T.whileSelectMessages( timeoutMillis: Long = -1, crossinline selectBuilder: @MessageDsl MessageSelectBuilder.() -> Unit @@ -122,7 +122,6 @@ suspend inline fun > T.selectMessagesUnit( * * @see nextMessage 挂起协程并等待下一条消息 */ -@MiraiExperimentalAPI @SinceMirai("0.29.0") @Suppress("unused") // false positive @OptIn(ExperimentalTypeInference::class) @@ -165,10 +164,69 @@ suspend inline fun , R> T.selectMessages( } @SinceMirai("0.29.0") -class MessageSelectBuilder, R> @PublishedApi internal constructor( +open class MessageSelectBuilder, R> @PublishedApi internal constructor( stub: Any?, subscriber: (M.(String) -> Boolean, MessageListener) -> Unit -) : MessageSubscribersBuilder(stub, subscriber) +) : MessageSubscribersBuilder(stub, subscriber) { + /** + * 无任何触发条件. + */ + @MessageDsl + fun default(onEvent: MessageListener): Unit = subscriber({ true }, onEvent) + + @Deprecated("Use `default` instead", level = DeprecationLevel.HIDDEN) + override fun always(onEvent: MessageListener) { + super.always(onEvent) + } + + // 这些函数无法获取返回值. 必须屏蔽. + + @Deprecated("Using `reply` DSL in message selection is prohibited", level = DeprecationLevel.HIDDEN) + override fun String.containsReply(reply: String): Nothing = error("prohibited") + + @Deprecated("Using `reply` DSL in message selection is prohibited", level = DeprecationLevel.HIDDEN) + override fun String.containsReply(replier: suspend M.(String) -> Any?) = error("prohibited") + + @Deprecated("Using `reply` DSL in message selection is prohibited", level = DeprecationLevel.HIDDEN) + override fun Regex.matchingReply(replier: suspend M.(MatchResult) -> Any?) = error("prohibited") + + @Deprecated("Using `reply` DSL in message selection is prohibited", level = DeprecationLevel.HIDDEN) + override fun Regex.findingReply(replier: suspend M.(MatchResult) -> Any?) = error("prohibited") + + @Deprecated("Using `reply` DSL in message selection is prohibited", level = DeprecationLevel.HIDDEN) + override fun String.startsWithReply(replier: suspend M.(String) -> Any?) = error("prohibited") + + @Deprecated("Using `reply` DSL in message selection is prohibited", level = DeprecationLevel.HIDDEN) + override fun String.endsWithReply(replier: suspend M.(String) -> Any?) = error("prohibited") + + @Deprecated("Using `reply` DSL in message selection is prohibited", level = DeprecationLevel.HIDDEN) + override fun String.reply(reply: String) = error("prohibited") + + @Deprecated("Using `reply` DSL in message selection is prohibited", level = DeprecationLevel.HIDDEN) + override fun String.reply(reply: Message) = error("prohibited") + + @Deprecated("Using `reply` DSL in message selection is prohibited", level = DeprecationLevel.HIDDEN) + override fun String.reply(replier: suspend M.(String) -> Any?) = error("prohibited") + + + @Deprecated("Using `reply` DSL in message selection is prohibited", level = DeprecationLevel.HIDDEN) + override fun ListeningFilter.reply(toReply: String) = error("prohibited") + + @Deprecated("Using `reply` DSL in message selection is prohibited", level = DeprecationLevel.HIDDEN) + override fun ListeningFilter.reply(message: Message) = error("prohibited") + + @Deprecated("Using `reply` DSL in message selection is prohibited", level = DeprecationLevel.HIDDEN) + override fun ListeningFilter.reply(replier: suspend M.(String) -> Any?) = error("prohibited") + + @Deprecated("Using `reply` DSL in message selection is prohibited", level = DeprecationLevel.HIDDEN) + override fun ListeningFilter.quoteReply(toReply: String) = error("prohibited") + + @Deprecated("Using `reply` DSL in message selection is prohibited", level = DeprecationLevel.HIDDEN) + override fun ListeningFilter.quoteReply(message: Message) = error("prohibited") + + @Deprecated("Using `reply` DSL in message selection is prohibited", level = DeprecationLevel.HIDDEN) + override fun ListeningFilter.quoteReply(replier: suspend M.(String) -> Any?) = error("prohibited") +} @JvmSynthetic @PublishedApi diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscribeMessages.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscribeMessages.kt index 8cbfe29b9..920d9ef1a 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscribeMessages.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscribeMessages.kt @@ -24,7 +24,6 @@ import net.mamoe.mirai.message.FriendMessage import net.mamoe.mirai.message.GroupMessage import net.mamoe.mirai.message.MessagePacket import net.mamoe.mirai.message.data.Message -import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.SinceMirai import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind @@ -34,6 +33,8 @@ import kotlin.coroutines.EmptyCoroutineContext import kotlin.js.JsName import kotlin.jvm.JvmName +typealias MessagePacketSubscribersBuilder = MessageSubscribersBuilder, Listener>, Unit, Unit> + /** * 订阅来自所有 [Bot] 的所有联系人的消息事件. 联系人可以是任意群或任意好友或临时会话. * @@ -43,14 +44,14 @@ import kotlin.jvm.JvmName fun CoroutineScope.subscribeMessages( coroutineContext: CoroutineContext = EmptyCoroutineContext, concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - listeners: MessageSubscribersBuilder, Listener>, Unit, Unit>.() -> R + listeners: MessagePacketSubscribersBuilder.() -> R ): R { // contract 可帮助 IDE 进行类型推断. 无实际代码作用. contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) } - return MessageSubscribersBuilder, Listener>, Unit, Unit>(Unit) + return MessagePacketSubscribersBuilder(Unit) { filter, messageListener: MessageListener, Unit> -> // subscribeAlways 即注册一个监听器. 这个监听器收到消息后就传递给 [messageListener] // messageListener 即为 DSL 里 `contains(...) { }`, `startsWith(...) { }` 的代码块. @@ -63,6 +64,8 @@ fun CoroutineScope.subscribeMessages( }.run(listeners) } +typealias GroupMessageSubscribersBuilder = MessageSubscribersBuilder, Unit, Unit> + /** * 订阅来自所有 [Bot] 的所有群消息事件 * @@ -72,12 +75,12 @@ fun CoroutineScope.subscribeMessages( fun CoroutineScope.subscribeGroupMessages( coroutineContext: CoroutineContext = EmptyCoroutineContext, concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - listeners: MessageSubscribersBuilder, Unit, Unit>.() -> R + listeners: GroupMessageSubscribersBuilder.() -> R ): R { contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) } - return MessageSubscribersBuilder, Unit, Unit>(Unit) { filter, listener -> + return GroupMessageSubscribersBuilder(Unit) { filter, listener -> subscribeAlways(coroutineContext, concurrencyKind) { val toString = this.message.toString() if (filter(this, toString)) @@ -86,6 +89,8 @@ fun CoroutineScope.subscribeGroupMessages( }.run(listeners) } +typealias FriendMessageSubscribersBuilder = MessageSubscribersBuilder, Unit, Unit> + /** * 订阅来自所有 [Bot] 的所有好友消息事件 * @@ -95,12 +100,12 @@ fun CoroutineScope.subscribeGroupMessages( fun CoroutineScope.subscribeFriendMessages( coroutineContext: CoroutineContext = EmptyCoroutineContext, concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - listeners: MessageSubscribersBuilder, Unit, Unit>.() -> R + listeners: FriendMessageSubscribersBuilder.() -> R ): R { contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) } - return MessageSubscribersBuilder, Unit, Unit>(Unit) { filter, listener -> + return FriendMessageSubscribersBuilder(Unit) { filter, listener -> subscribeAlways(coroutineContext, concurrencyKind) { val toString = this.message.toString() if (filter(this, toString)) @@ -118,12 +123,12 @@ fun CoroutineScope.subscribeFriendMessages( fun Bot.subscribeMessages( coroutineContext: CoroutineContext = EmptyCoroutineContext, concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - listeners: MessageSubscribersBuilder, Listener>, Unit, Unit>.() -> R + listeners: MessagePacketSubscribersBuilder.() -> R ): R { contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) } - return MessageSubscribersBuilder, Listener>, Unit, Unit>(Unit) { filter, listener -> + return MessagePacketSubscribersBuilder(Unit) { filter, listener -> this.subscribeAlways(coroutineContext, concurrencyKind) { val toString = this.message.toString() if (filter(this, toString)) @@ -143,12 +148,12 @@ fun Bot.subscribeMessages( fun Bot.subscribeGroupMessages( coroutineContext: CoroutineContext = EmptyCoroutineContext, concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - listeners: MessageSubscribersBuilder, Unit, Unit>.() -> R + listeners: GroupMessageSubscribersBuilder.() -> R ): R { contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) } - return MessageSubscribersBuilder, Unit, Unit>(Unit) { filter, listener -> + return GroupMessageSubscribersBuilder(Unit) { filter, listener -> this.subscribeAlways(coroutineContext, concurrencyKind) { val toString = this.message.toString() if (filter(this, toString)) @@ -166,12 +171,12 @@ fun Bot.subscribeGroupMessages( fun Bot.subscribeFriendMessages( coroutineContext: CoroutineContext = EmptyCoroutineContext, concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - listeners: MessageSubscribersBuilder, Unit, Unit>.() -> R + listeners: FriendMessageSubscribersBuilder.() -> R ): R { contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) } - return MessageSubscribersBuilder, Unit, Unit>(Unit) { filter, listener -> + return FriendMessageSubscribersBuilder(Unit) { filter, listener -> this.subscribeAlways(coroutineContext, concurrencyKind) { val toString = this.message.toString() if (filter(this, toString)) @@ -245,10 +250,6 @@ inline fun Bot.incoming( typealias MessageListener = @MessageDsl suspend T.(String) -> R -// TODO: 2020/3/21 抽象消息构造器, 以在 select 时不可访问 `reply` 等函数 - -// TODO: 2020/3/21 引入 TypeAlias 或新的类型以缩短类型参数 - /** * 消息订阅构造器 * @@ -269,41 +270,47 @@ open class MessageSubscribersBuilder, out Ret, R : RR, R */ val subscriber: (M.(String) -> Boolean, MessageListener) -> Ret ) { + @Suppress("DEPRECATION") + open fun newListeningFilter(filter: M.(String) -> Boolean): ListeningFilter = ListeningFilter(filter) + /** * 监听的条件 */ - open inner class ListeningFilter( + open inner class ListeningFilter @Deprecated( + "use newListeningFilter instead", + ReplaceWith("newListeningFilter(filter)") + ) constructor( val filter: M.(String) -> Boolean ) { /** * 进行逻辑 `or`. */ infix fun or(another: ListeningFilter): ListeningFilter = - ListeningFilter { filter.invoke(this, it) || another.filter.invoke(this, it) } + newListeningFilter { filter.invoke(this, it) || another.filter.invoke(this, it) } /** * 进行逻辑 `and`. */ infix fun and(another: ListeningFilter): ListeningFilter = - ListeningFilter { filter.invoke(this, it) && another.filter.invoke(this, it) } + newListeningFilter { filter.invoke(this, it) && another.filter.invoke(this, it) } /** * 进行逻辑 `xor`. */ infix fun xor(another: ListeningFilter): ListeningFilter = - ListeningFilter { filter.invoke(this, it) xor another.filter.invoke(this, it) } + newListeningFilter { filter.invoke(this, it) xor another.filter.invoke(this, it) } /** * 进行逻辑 `nand`, 即 `not and`. */ infix fun nand(another: ListeningFilter): ListeningFilter = - ListeningFilter { !filter.invoke(this, it) || !another.filter.invoke(this, it) } + newListeningFilter { !filter.invoke(this, it) || !another.filter.invoke(this, it) } /** * 进行逻辑 `not` */ fun not(): ListeningFilter = - ListeningFilter { !filter.invoke(this, it) } + newListeningFilter { !filter.invoke(this, it) } /** * 启动事件监听. @@ -312,35 +319,41 @@ open class MessageSubscribersBuilder, out Ret, R : RR, R operator fun invoke(onEvent: MessageListener): Ret { return content(filter, onEvent) } + } - infix fun reply(toReply: String): Ret { - return content(filter) { reply(toReply);stub } + @SinceMirai("0.29.0") + open infix fun ListeningFilter.reply(toReply: String): Ret { + return content(filter) { reply(toReply);stub } + } + + @SinceMirai("0.29.0") + open infix fun ListeningFilter.reply(message: Message): Ret { + return content(filter) { reply(message);stub } + } + + @SinceMirai("0.29.0") + open infix fun ListeningFilter.reply(replier: (@MessageDsl suspend M.(String) -> Any?)): Ret { + return content(filter) { + @Suppress("DSL_SCOPE_VIOLATION_WARNING") + executeAndReply(replier) } + } - infix fun reply(message: Message): Ret { - return content(filter) { reply(message);stub } - } + @SinceMirai("0.29.0") + open infix fun ListeningFilter.quoteReply(toReply: String): Ret { + return content(filter) { quoteReply(toReply);stub } + } - infix fun reply(replier: (@MessageDsl suspend M.(String) -> Any?)): Ret { - return content(filter) { - @Suppress("DSL_SCOPE_VIOLATION_WARNING") - executeAndReply(replier) - } - } + @SinceMirai("0.29.0") + open infix fun ListeningFilter.quoteReply(message: Message): Ret { + return content(filter) { quoteReply(message);stub } + } - infix fun quoteReply(toReply: String): Ret { - return content(filter) { quoteReply(toReply);stub } - } - - infix fun quoteReply(message: Message): Ret { - return content(filter) { quoteReply(message);stub } - } - - infix fun quoteReply(replier: (@MessageDsl suspend M.(String) -> Any?)): Ret { - return content(filter) { - @Suppress("DSL_SCOPE_VIOLATION_WARNING") - executeAndQuoteReply(replier) - } + @SinceMirai("0.29.0") + open infix fun ListeningFilter.quoteReply(replier: (@MessageDsl suspend M.(String) -> Any?)): Ret { + return content(filter) { + @Suppress("DSL_SCOPE_VIOLATION_WARNING") + executeAndQuoteReply(replier) } } @@ -350,7 +363,7 @@ open class MessageSubscribersBuilder, out Ret, R : RR, R * 无任何触发条件. */ @MessageDsl - fun always(onEvent: MessageListener): Ret = subscriber({ true }, onEvent) + open fun always(onEvent: MessageListener): Ret = subscriber({ true }, onEvent) /** * 如果消息内容 `==` [equals] @@ -372,7 +385,6 @@ open class MessageSubscribersBuilder, out Ret, R : RR, R /** * 如果消息内容 `==` [equals] */ - @MiraiExperimentalAPI @MessageDsl @JvmName("case1") @JsName("case1") @@ -603,7 +615,7 @@ open class MessageSubscribersBuilder, out Ret, R : RR, R * 如果是好友发来的消息 */ @MessageDsl - fun sentByFriend(): ListeningFilter = ListeningFilter { this is FriendMessage } + fun sentByFriend(): ListeningFilter = newListeningFilter { this is FriendMessage } /** * 如果是管理员或群主发的消息 @@ -682,7 +694,7 @@ open class MessageSubscribersBuilder, out Ret, R : RR, R */ @MessageDsl fun content(filter: M.(String) -> Boolean): ListeningFilter = - ListeningFilter(filter) + newListeningFilter(filter) /** * 如果 [filter] 返回 `true` 就执行 `onEvent` @@ -741,7 +753,7 @@ open class MessageSubscribersBuilder, out Ret, R : RR, R * 若消息内容包含 [this] 则回复 [reply] */ @MessageDsl - infix fun String.containsReply(reply: String): Ret = + open infix fun String.containsReply(reply: String): Ret = content({ this@containsReply in it }, { reply(reply); stub }) /** @@ -752,7 +764,7 @@ open class MessageSubscribersBuilder, out Ret, R : RR, R * @param replier 若返回 [Message] 则直接发送; 若返回 [Unit] 则不回复; 其他情况则 [Any.toString] 后回复 */ @MessageDsl - infix fun String.containsReply(replier: @MessageDsl suspend M.(String) -> Any?): Ret = + open infix fun String.containsReply(replier: @MessageDsl suspend M.(String) -> Any?): Ret = content({ this@containsReply in it }, { @Suppress("DSL_SCOPE_VIOLATION_WARNING") this.executeAndReply(replier) @@ -766,7 +778,7 @@ open class MessageSubscribersBuilder, out Ret, R : RR, R * @param replier 若返回 [Message] 则直接发送; 若返回 [Unit] 则不回复; 其他情况则 [Any.toString] 后回复 */ @MessageDsl - infix fun Regex.matchingReply(replier: @MessageDsl suspend M.(MatchResult) -> Any?): Ret = + open infix fun Regex.matchingReply(replier: @MessageDsl suspend M.(MatchResult) -> Any?): Ret = always { val find = this@matchingReply.matchEntire(it) ?: return@always stub @Suppress("DSL_SCOPE_VIOLATION_WARNING") @@ -783,7 +795,7 @@ open class MessageSubscribersBuilder, out Ret, R : RR, R * @param replier 若返回 [Message] 则直接发送; 若返回 [Unit] 则不回复; 其他情况则 [Any.toString] 后回复 */ @MessageDsl - infix fun Regex.findingReply(replier: @MessageDsl suspend M.(MatchResult) -> Any?): Ret = + open infix fun Regex.findingReply(replier: @MessageDsl suspend M.(MatchResult) -> Any?): Ret = always { val find = this@findingReply.find(it) ?: return@always stub @Suppress("DSL_SCOPE_VIOLATION_WARNING") @@ -806,7 +818,7 @@ open class MessageSubscribersBuilder, out Ret, R : RR, R * @param replier 若返回 [Message] 则直接发送; 若返回 [Unit] 则不回复; 其他类型则 [Any.toString] 后回复 */ @MessageDsl - infix fun String.startsWithReply(replier: @MessageDsl suspend M.(String) -> Any?): Ret { + open infix fun String.startsWithReply(replier: @MessageDsl suspend M.(String) -> Any?): Ret { val toCheck = this.trimStart() return content({ it.trim().startsWith(toCheck) }, { @Suppress("DSL_SCOPE_VIOLATION_WARNING") @@ -830,7 +842,7 @@ open class MessageSubscribersBuilder, out Ret, R : RR, R * @param replier 若返回 [Message] 则直接发送; 若返回 [Unit] 则不回复; 其他情况则 [Any.toString] 后回复 */ @MessageDsl - infix fun String.endsWithReply(replier: @MessageDsl suspend M.(String) -> Any?): Ret { + open infix fun String.endsWithReply(replier: @MessageDsl suspend M.(String) -> Any?): Ret { val toCheck = this.trimEnd() return content({ it.trim().endsWith(toCheck) }, { @Suppress("DSL_SCOPE_VIOLATION_WARNING") @@ -841,19 +853,19 @@ open class MessageSubscribersBuilder, out Ret, R : RR, R } @MessageDsl - infix fun String.reply(reply: String): Ret { + open infix fun String.reply(reply: String): Ret { val toCheck = this.trim() return content({ it.trim() == toCheck }, { reply(reply);stub }) } @MessageDsl - infix fun String.reply(reply: Message): Ret { + open infix fun String.reply(reply: Message): Ret { val toCheck = this.trim() return content({ it.trim() == toCheck }, { reply(reply);stub }) } @MessageDsl - infix fun String.reply(replier: @MessageDsl suspend M.(String) -> Any?): Ret { + open infix fun String.reply(replier: @MessageDsl suspend M.(String) -> Any?): Ret { val toCheck = this.trim() return content({ it.trim() == toCheck }, { @Suppress("DSL_SCOPE_VIOLATION_WARNING")