From cdc9fb20a5a31603ac3c45d8f467ef74145886e1 Mon Sep 17 00:00:00 2001 From: ForteScarlet Date: Sat, 9 Mar 2024 23:28:42 +0800 Subject: [PATCH] =?UTF-8?q?pref:=20=E5=BA=9F=E5=BC=83=20`Bot.processor`=20?= =?UTF-8?q?=E5=B9=B6=E9=87=8D=E5=91=BD=E5=90=8D=E4=B8=BA=20`Bot.subscribe`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Writerside/topics/use-stdlib.md | 26 ++--- .../bot/KookBotVerifyInfoConfiguration.kt | 4 +- .../kook/bot/internal/KookBotEvents.kt | 14 ++- .../love/forte/simbot/kook/stdlib/Bot.kt | 97 ++++++++++++++++--- .../simbot/kook/stdlib/BotConfiguration.kt | 29 +++--- .../forte/simbot/kook/stdlib/BotSubscribes.kt | 73 ++++++++++++++ .../simbot/kook/stdlib/internal/BotImpl.kt | 10 +- 7 files changed, 204 insertions(+), 49 deletions(-) create mode 100644 simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/stdlib/BotSubscribes.kt diff --git a/Writerside/topics/use-stdlib.md b/Writerside/topics/use-stdlib.md index 6d06205f..68f4a898 100644 --- a/Writerside/topics/use-stdlib.md +++ b/Writerside/topics/use-stdlib.md @@ -123,9 +123,9 @@ val bot = BotFactory.create(ticket) { } // 注册事件有一些不同但类似的方式 -// 1️⃣ 通过 processor 注册一个普通的事件处理器,此处理器会接收并处理所有类型的事件 -// processor 是最基本的注册方式,也是其他方式的最终汇集点 -bot.processor { raw -> +// 1️⃣ 通过 subscribe 注册一个普通的事件处理器,此处理器会接收并处理所有类型的事件 +// subscribe 是最基本的注册方式,也是其他方式的最终汇集点 +bot.subscribe { raw -> // raw 代表事件的原始JSON字符串 // this: Event<*>, 也就是解析出来的事件结构体 println("event: $this") @@ -133,11 +133,11 @@ bot.processor { raw -> println("raw: $raw") } -// 2️⃣ 通过 processor 注册一个针对具体 Event 事件类型的事件处理器, +// 2️⃣ 通过 subscribe 注册一个针对具体 Event 事件类型的事件处理器, // 它只有在接收到的 Event.extra 与目标类型一致时才会处理。 // 此示例展示处理 KMarkdownEventExtra 也就 KMarkdown 类型的消息事件, // 并在对方发送了包含 'stop' 的文本时终止 bot。 -bot.processor { +bot.subscribe { // raw 代表事件的原始JSON字符串 // this: Event, 也就是解析出来的事件结构体, // 并且 extra 类型为指定的 KMarkdownEventExtra @@ -176,9 +176,9 @@ Bot bot = BotFactory.create(ticket, config -> { // 一些其他的配置... }); -// 通过 processor 注册一个普通的事件处理器, +// 通过 subscribe 注册一个普通的事件处理器, // 此处理器会接收并处理所有类型的事件 -bot.processor(EventProcessors.async((event, raw) -> { +bot.subscribe(EventProcessors.async((event, raw) -> { // raw 代表事件的原始JSON字符串 // event: Event<*>, 也就是解析出来的事件结构体 System.out.println("event: " + event); @@ -189,10 +189,10 @@ bot.processor(EventProcessors.async((event, raw) -> { return CompletableFuture.completedFuture(null); })); -// 通过 processor 注册一个普通的事件处理器, +// 通过 subscribe 注册一个普通的事件处理器, // 此处理器会接收并处理指定的类型 AtMessageCreate 的事件 // 此示例展示处理 AtMessageCreate 也就公域是消息事件,并在对方发送了包含 'stop' 的文本时终止 bot。 -bot.processor(EventProcessors.async(KMarkdownEventExtra.class, (event, raw) -> { +bot.subscribe(EventProcessors.async(KMarkdownEventExtra.class, (event, raw) -> { // raw 代表事件的原始JSON字符串 // event: Event, 也就是解析出来的事件结构体 System.out.println("event kmarkdown: " + event.getExtra().getKmarkdown()); @@ -233,9 +233,9 @@ Bot bot = BotFactory.create(ticket, config -> { // 一些其他的配置... }); -// 通过 processor 注册一个普通的事件处理器, +// 通过 subscribe 注册一个普通的事件处理器, // 此处理器会接收并处理所有类型的事件 -bot.processor(EventProcessors.async((event, raw) -> { +bot.subscribe(EventProcessors.async((event, raw) -> { // raw 代表事件的原始JSON字符串 // event: Event<*>, 也就是解析出来的事件结构体 System.out.println("event: " + event); @@ -243,10 +243,10 @@ bot.processor(EventProcessors.async((event, raw) -> { System.out.println("raw: " + raw); })); -// 通过 processor 注册一个普通的事件处理器, +// 通过 subscribe 注册一个普通的事件处理器, // 此处理器会接收并处理指定的类型 AtMessageCreate 的事件 // 此示例展示处理 AtMessageCreate 也就公域是消息事件,并在对方发送了包含 'stop' 的文本时终止 bot。 - bot.processor(EventProcessors.block(KMarkdownEventExtra.class, (event, raw) -> { + bot.subscribe(EventProcessors.block(KMarkdownEventExtra.class, (event, raw) -> { // raw 代表事件的原始JSON字符串 // event: Event, 也就是解析出来的事件结构体 System.out.println("event kmarkdown: " + event.getExtra().getKmarkdown()); diff --git a/simbot-component-kook-core/src/commonMain/kotlin/love/forte/simbot/component/kook/bot/KookBotVerifyInfoConfiguration.kt b/simbot-component-kook-core/src/commonMain/kotlin/love/forte/simbot/component/kook/bot/KookBotVerifyInfoConfiguration.kt index 3c970ae3..963e33fc 100644 --- a/simbot-component-kook-core/src/commonMain/kotlin/love/forte/simbot/component/kook/bot/KookBotVerifyInfoConfiguration.kt +++ b/simbot-component-kook-core/src/commonMain/kotlin/love/forte/simbot/component/kook/bot/KookBotVerifyInfoConfiguration.kt @@ -27,7 +27,7 @@ import love.forte.simbot.component.kook.KookComponent import love.forte.simbot.component.kook.bot.KookBotVerifyInfoConfiguration.Ticket import love.forte.simbot.kook.TokenType import love.forte.simbot.kook.stdlib.BotConfiguration -import love.forte.simbot.kook.stdlib.ProcessorType +import love.forte.simbot.kook.stdlib.SubscribeSequence /** * `.bot` 配置文件读取的配置信息实体, 用于接收序列化配置信息。 @@ -160,7 +160,7 @@ public data class KookBotVerifyInfoConfiguration( /** - * [ProcessorType.NORMAL] 类型的事件处理器是否在异步中执行。 + * [SubscribeSequence.NORMAL] 类型的事件处理器是否在异步中执行。 * * 更多说明参考 [BotConfiguration.isNormalEventProcessAsync] * diff --git a/simbot-component-kook-core/src/commonMain/kotlin/love/forte/simbot/component/kook/bot/internal/KookBotEvents.kt b/simbot-component-kook-core/src/commonMain/kotlin/love/forte/simbot/component/kook/bot/internal/KookBotEvents.kt index 8c3af61c..c12e3fdd 100644 --- a/simbot-component-kook-core/src/commonMain/kotlin/love/forte/simbot/component/kook/bot/internal/KookBotEvents.kt +++ b/simbot-component-kook-core/src/commonMain/kotlin/love/forte/simbot/component/kook/bot/internal/KookBotEvents.kt @@ -35,7 +35,7 @@ import love.forte.simbot.kook.DiscreetKookApi import love.forte.simbot.kook.api.user.GetUserViewApi import love.forte.simbot.kook.event.* import love.forte.simbot.kook.objects.SimpleUser -import love.forte.simbot.kook.stdlib.ProcessorType +import love.forte.simbot.kook.stdlib.SubscribeSequence import love.forte.simbot.kook.event.Event as KEvent import love.forte.simbot.kook.objects.User as KUser @@ -71,7 +71,7 @@ internal fun KookBotImpl.registerEvent() { val thisBot = this - sourceBot.processor(ProcessorType.PREPARE) { rawEvent -> + sourceBot.subscribe(SubscribeSequence.PREPARE) { rawEvent -> val event = this when (val ex = extra) { @@ -286,7 +286,7 @@ internal fun KookBotImpl.registerEvent() { members.entries.removeAll { (k, _) -> k.guildId == guildId } removedGuild - } ?: return@processor + } ?: return@subscribe pushAndLaunch( KookBotSelfExitedGuildEventImpl( @@ -434,7 +434,11 @@ internal fun KookBotImpl.registerEvent() { } else -> { - logger.warn("No chat channel or category ({}) removed in event {}", ex.body.id, event) + logger.warn( + "No chat channel or category ({}) removed in event {}", + ex.body.id, + event + ) } } } @@ -603,7 +607,7 @@ private fun KookBotImpl.pushUnsupported(event: KEvent, sourceEventJs } -private inline fun KookBotImpl.pushAndLaunch(event: Event): Job { +private fun KookBotImpl.pushAndLaunch(event: Event): Job { return launch { eventProcessor.push(event) .onEachError { er -> diff --git a/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/stdlib/Bot.kt b/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/stdlib/Bot.kt index c70282a0..7e5378e9 100644 --- a/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/stdlib/Bot.kt +++ b/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/stdlib/Bot.kt @@ -1,18 +1,21 @@ /* - * Copyright (c) 2023-2024. ForteScarlet. + * Copyright (c) 2023-2024. ForteScarlet. * - * This file is part of simbot-component-kook. + * This file is part of simbot-component-kook. * - * simbot-component-kook is free software: you can redistribute it and/or modify it under the terms of - * the GNU Lesser General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. + * simbot-component-kook is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * simbot-component-kook is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. + * simbot-component-kook is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License along with simbot-component-kook, - * If not, see . + * You should have received a copy of the GNU Lesser General Public License + * along with simbot-component-kook, + * If not, see . */ package love.forte.simbot.kook.stdlib @@ -97,24 +100,64 @@ public interface Bot : CoroutineScope { * 添加一个事件处理器。 * 所有事件处理器会在每次触发的时候按照添加顺序依次进行处理。 * + * Deprecated: 重命名为了 [subscribe] + * + * @see subscribe * @param processorType 事件处理器类型。默认为 [ProcessorType.NORMAL]。 * @param processor 事件处理器。 */ + @Suppress("DEPRECATION") + @Deprecated("Use `subscribe`", ReplaceWith("subscribe(subscribeSequence = processorType, processor = processor)")) public fun processor( processorType: ProcessorType, processor: EventProcessor - ) + ) { + subscribe( + subscribeSequence = when (processorType) { + ProcessorType.PREPARE -> SubscribeSequence.PREPARE + ProcessorType.NORMAL -> SubscribeSequence.NORMAL + }, + processor = processor + ) + } /** * 添加一个 [ProcessorType.NORMAL] 类型的事件处理器。 * 所有事件处理器会在每次触发的时候按照添加顺序依次进行处理。 * + * Deprecated: 重命名为了 [subscribe] + * + * @see subscribe * @param processor 事件处理器。 */ + @Suppress("DEPRECATION") + @Deprecated("Use `subscribe`", ReplaceWith("subscribe(SubscribeSequence.NORMAL, processor = processor)")) public fun processor(processor: EventProcessor) { processor(ProcessorType.NORMAL, processor) } + /** + * 订阅事件并使用事件处理器 [processor] 进行处理。。 + * 所有事件处理器会在每次触发的时候按照添加顺序依次进行处理。 + * + * @param subscribeSequence 事件订阅的序列类型。默认为 [SubscribeSequence.NORMAL]。 + * @param processor 事件处理器。 + */ + public fun subscribe( + subscribeSequence: SubscribeSequence, + processor: EventProcessor + ) + + /** + * 添加一个 [SubscribeSequence.NORMAL] 类型的事件处理器。 + * 所有事件处理器会在每次触发的时候按照添加顺序依次进行处理。 + * + * @param processor 事件处理器。 + */ + public fun subscribe(processor: EventProcessor) { + subscribe(SubscribeSequence.NORMAL, processor) + } + /** * 查询 bot 作为用户的信息。 * @@ -258,6 +301,8 @@ private data class BotWsTicket(override val clientId: String, override val token * @param EX 事件内容 [Event.extra] 的具体类型。 * */ +@Suppress("DEPRECATION") +@Deprecated("Use `Bot.subscribe(...)`", ReplaceWith("this.subscribe(processor)")) public inline fun Bot.processor(crossinline processor: suspend Event.(raw: String) -> Unit) { processor { raw -> if (extra is EX) { @@ -272,6 +317,8 @@ public inline fun Bot.processor(crossinline processor: * * @param type 事件类型。 */ +@Suppress("DEPRECATION") +@Deprecated("Use `Bot.subscribe(...)`", ReplaceWith("this.subscribe(type, processor)")) public inline fun Bot.processor(type: Event.Type, crossinline processor: suspend Event<*>.(raw: String) -> Unit) { processor { raw -> if (this.type == type) { @@ -282,7 +329,12 @@ public inline fun Bot.processor(type: Event.Type, crossinline processor: suspend /** * [Bot] 中的事件处理器类型。 + * + * Deprecated: 重命名为了 [SubscribeSequence] + * + * @see SubscribeSequence */ +@Deprecated("Use `SubscribeSequence` with `Bot.subscribe`", ReplaceWith("SubscribeSequence")) public enum class ProcessorType { /** * 前置类型。所有前置事件处理器会在每次触发的时候优先于 [普通类型][NORMAL] 的事件处理器进行处理, @@ -302,3 +354,26 @@ public enum class ProcessorType { */ NORMAL; } + +/** + * [Bot] 中订阅事件时的序列类型。 + */ +public enum class SubscribeSequence { + /** + * 前置类型。所有前置事件处理器会在每次触发的时候优先于 [普通类型][NORMAL] 的事件处理器进行处理, + * 并且所有前置处理器**不会**异步执行。 + * + * 前置类型的事件处理器应当尽可能的快速执行完毕。 + */ + PREPARE, + + /** + * 普通类型。所有事件处理器会在每次触发的时候按照添加顺序依次进行处理, + * 但是以事件为单位,整个流程可能是异步的。 + * + * [NORMAL] 最终是否会异步处理会受配置项 [BotConfiguration.isNormalEventProcessAsync] + * 的影响,默认为异步。如果此配置为 `false` 则 [NORMAL] 的实际表现效果将会与 [PREPARE] 类似, + * 只是优先级低于 [PREPARE]。 + */ + NORMAL; +} diff --git a/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/stdlib/BotConfiguration.kt b/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/stdlib/BotConfiguration.kt index a59fde6d..3b14f46f 100644 --- a/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/stdlib/BotConfiguration.kt +++ b/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/stdlib/BotConfiguration.kt @@ -1,18 +1,21 @@ /* - * Copyright (c) 2023-2024. ForteScarlet. + * Copyright (c) 2023-2024. ForteScarlet. * - * This file is part of simbot-component-kook. + * This file is part of simbot-component-kook. * - * simbot-component-kook is free software: you can redistribute it and/or modify it under the terms of - * the GNU Lesser General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. + * simbot-component-kook is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * simbot-component-kook is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. + * simbot-component-kook is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License along with simbot-component-kook, - * If not, see . + * You should have received a copy of the GNU Lesser General Public License + * along with simbot-component-kook, + * If not, see . */ package love.forte.simbot.kook.stdlib @@ -210,10 +213,10 @@ public class BotConfiguration { /** - * [ProcessorType.NORMAL] 类型的事件处理器是否在异步中执行。 + * [SubscribeSequence.NORMAL] 类型的事件处理器是否在异步中执行。 * 默认为 `true`。 - * 当为 `false` 时, [ProcessorType.NORMAL] 的表现效果将会与 - * [ProcessorType.PREPARE] 基本类似。 + * 当为 `false` 时, [SubscribeSequence.NORMAL] 的表现效果将会与 + * [SubscribeSequence.PREPARE] 基本类似。 */ public var isNormalEventProcessAsync: Boolean = true diff --git a/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/stdlib/BotSubscribes.kt b/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/stdlib/BotSubscribes.kt new file mode 100644 index 00000000..97985621 --- /dev/null +++ b/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/stdlib/BotSubscribes.kt @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024. ForteScarlet. + * + * This file is part of simbot-component-kook. + * + * simbot-component-kook is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * simbot-component-kook is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with simbot-component-kook, + * If not, see . + */ + +package love.forte.simbot.kook.stdlib + +import love.forte.simbot.kook.event.Event +import love.forte.simbot.kook.event.EventExtra + + +/** + * 订阅一个具体的 [EventExtra] 类型的事件。 + * + * ```kotlin + * bot.subscribe { raw -> + * // ... + * } + * ``` + * + * @param subscribeSequence 事件处理器的序列类型,默认为 [SubscribeSequence.NORMAL] + * @param EX 事件内容 [Event.extra] 的具体类型。 + */ +public inline fun Bot.subscribe( + subscribeSequence: SubscribeSequence = SubscribeSequence.NORMAL, + crossinline processor: suspend Event.(raw: String) -> Unit +) { + subscribe(subscribeSequence) { raw -> + if (extra is EX) { + @Suppress("UNCHECKED_CAST") + processor.invoke(this as Event, raw) + } + } +} + +/** + * 订阅一个 [Event.type] 目标的事件。 + * + * ```kotlin + * bot.subscribe(type) { raw -> + * // ... + * } + * ``` + * + * @param type 事件类型 + * @param subscribeSequence 事件处理器的序列类型,默认为 [SubscribeSequence.NORMAL] + */ +public inline fun Bot.subscribe( + type: Event.Type, + subscribeSequence: SubscribeSequence = SubscribeSequence.NORMAL, + crossinline processor: suspend Event<*>.(raw: String) -> Unit +) { + subscribe(subscribeSequence) { raw -> + if (this.type == type) { + processor(raw) + } + } +} diff --git a/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/stdlib/internal/BotImpl.kt b/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/stdlib/internal/BotImpl.kt index 16e29492..4b6bc121 100644 --- a/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/stdlib/internal/BotImpl.kt +++ b/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/stdlib/internal/BotImpl.kt @@ -59,12 +59,12 @@ internal class BotImpl( internal val authorization: String = "${ticket.type.prefix} ${ticket.token}" - private val queueMap = ActualEnumMap.create> { + private val queueMap = ActualEnumMap.create> { createConcurrentQueue() } - override fun processor(processorType: ProcessorType, processor: EventProcessor) { - queueMap[processorType].add(processor) + override fun subscribe(subscribeSequence: SubscribeSequence, processor: EventProcessor) { + queueMap[subscribeSequence].add(processor) } private val job = SupervisorJob(configuration.coroutineContext[Job]) @@ -247,8 +247,8 @@ internal class BotImpl( } internal suspend fun processEvent(event: Signal.Event<*>, raw: String) { - val prepareProcessors = queueMap[ProcessorType.PREPARE] - val normalProcessors = queueMap[ProcessorType.NORMAL] + val prepareProcessors = queueMap[SubscribeSequence.PREPARE] + val normalProcessors = queueMap[SubscribeSequence.NORMAL] if (prepareProcessors.size == 0 && normalProcessors.size == 0) { eventLogger.trace("prepare processors and normal processors are both empty, skip.") return