Bläddra i källkod

Add EventChannel.filter accepting non-suspend Predicates for Java users

Him188 5 år sedan
förälder
incheckning
b30e098068

+ 1 - 0
binary-compatibility-validator/api/binary-compatibility-validator.api

@@ -1516,6 +1516,7 @@ public class net/mamoe/mirai/event/EventChannel {
 	public final fun context ([Lkotlin/coroutines/CoroutineContext;)Lnet/mamoe/mirai/event/EventChannel;
 	public final fun exceptionHandler (Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/event/EventChannel;
 	public final fun exceptionHandler (Lkotlinx/coroutines/CoroutineExceptionHandler;)Lnet/mamoe/mirai/event/EventChannel;
+	public final fun filter (Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/event/EventChannel;
 	public final synthetic fun filter (Lkotlin/jvm/functions/Function2;)Lnet/mamoe/mirai/event/EventChannel;
 	public final fun filterIsInstance (Ljava/lang/Class;)Lnet/mamoe/mirai/event/EventChannel;
 	public final fun filterIsInstance (Lkotlin/reflect/KClass;)Lnet/mamoe/mirai/event/EventChannel;

+ 42 - 0
mirai-core-api/src/commonMain/kotlin/event/EventChannel.kt

@@ -148,6 +148,48 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads internal con
         }
     }
 
+    /**
+     * [EventChannel.filter] 的 Java 版本.
+     *
+     * 添加一个过滤器. 过滤器将在收到任何事件之后, 传递给通过 [EventChannel.subscribe] 注册的监听器之前调用.
+     *
+     * 若 [filter] 返回 `true`, 该事件将会被传给监听器. 否则将会被忽略, **监听器继续监听**.
+     *
+     * ## 线性顺序
+     * 多个 [filter] 的处理是线性且有顺序的. 若一个 [filter] 已经返回了 `false` (代表忽略这个事件), 则会立即忽略, 而不会传递给后续过滤器.
+     *
+     * 示例:
+     * ```
+     * GlobalEventChannel // GlobalEventChannel 会收到全局所有事件, 事件类型是 Event
+     *     .filterIsInstance(BotEvent.class) // 过滤, 只接受 BotEvent
+     *     .filter(event ->
+     *         // 此时的 event 一定是 BotEvent
+     *         event.bot.id == 123456 // 再过滤 event 的 bot.id
+     *     )
+     *     .subscribeAlways(event -> {
+     *         // 现在 event 是 BotEvent, 且 bot.id == 123456
+     *     })
+     * ```
+     *
+     * ## 过滤器阻塞
+     * [filter] 允许阻塞线程. **过滤器的阻塞将被认为是事件监听器的阻塞**.
+     *
+     * 过滤器阻塞是否会影响事件处理,
+     * 取决于 [subscribe] 时的 [ConcurrencyKind] 和 [EventPriority].
+     *
+     * ## 过滤器异常处理
+     * 若 [filter] 抛出异常, 将被包装为 [ExceptionInEventChannelFilterException] 并重新抛出.
+     *
+     * @see filterIsInstance 过滤指定类型的事件
+     *
+     * @since 2.2
+     */
+    @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
+    @kotlin.internal.LowPriorityInOverloadResolution
+    public fun filter(filter: (event: BaseEvent) -> Boolean): EventChannel<BaseEvent> {
+        return filter { runInterruptible { filter(it) } }
+    }
+
     /**
      * 过滤事件的类型. 返回一个只包含 [E] 类型事件的 [EventChannel]
      * @see filter 获取更多信息

+ 32 - 0
mirai-core-api/src/jvmTest/kotlin/event/EventChannelJavaTest.java

@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019-2021 Mamoe Technologies and contributors.
+ *
+ *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ *  https://github.com/mamoe/mirai/blob/master/LICENSE
+ */
+
+package event;
+
+import net.mamoe.mirai.event.Event;
+import net.mamoe.mirai.event.GlobalEventChannel;
+import net.mamoe.mirai.event.events.GroupMessageEvent;
+import net.mamoe.mirai.event.events.MessageEvent;
+
+/**
+ * 仅测试可以使用, 不会被编译运行
+ */
+public class EventChannelJavaTest {
+
+    public static void main(String[] args) {
+        GlobalEventChannel.INSTANCE
+                .filter(event -> {
+                    return event.toString() == "test";
+                })
+                .filterIsInstance(MessageEvent.class)
+                .subscribeAlways(GroupMessageEvent.class, groupMessageEvent -> {
+
+                });
+    }
+}

+ 11 - 1
mirai-core-api/src/jvmTest/kotlin/event/EventChannelTest.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2020 Mamoe Technologies and contributors.
+ * Copyright 2019-2021 Mamoe Technologies and contributors.
  *
  *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -16,15 +16,25 @@ import net.mamoe.mirai.event.events.MessageEvent
 import org.junit.jupiter.api.Test
 
 internal class EventChannelTest {
+    suspend fun suspendCall() {
+
+    }
+
     @Suppress("UNUSED_VARIABLE")
     @Test
     fun testVariance() {
         var global: EventChannel<Event> = GlobalEventChannel
         var a: EventChannel<MessageEvent> = global.filterIsInstance<MessageEvent>()
+
+        val filterLambda: (ev: MessageEvent) -> Boolean = { true }
+
+        // Kotlin can't resolve to the non-suspend one
         a.filter {
             // it: Event
+            suspendCall() // would be allowed in Kotlin
             it.isIntercepted
         }
+
         val messageEventChannel = a.filterIsInstance<MessageEvent>()
         // group.asChannel<GroupMessageEvent>()