Skip to content

Commit 25c3fbf

Browse files
authored
Merge pull request #855 from simple-robot/basic-listeners-for-jvm
JVM中的EventListener兼容类型增加一个 nonBlock 类型用于简化响应式结果的使用
2 parents e6f0ded + beb3c7b commit 25c3fbf

File tree

4 files changed

+349
-1
lines changed

4 files changed

+349
-1
lines changed

simbot-api/api/simbot-api.api

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,8 @@ public final class love/forte/simbot/event/EventListeners {
12381238
public static synthetic fun block$default (Lkotlin/coroutines/CoroutineContext;Ljava/lang/Class;Llove/forte/simbot/event/TypedJBlockEventListener;ILjava/lang/Object;)Llove/forte/simbot/event/EventListener;
12391239
public static synthetic fun block$default (Lkotlin/coroutines/CoroutineContext;Llove/forte/simbot/event/JBlockEventListener;ILjava/lang/Object;)Llove/forte/simbot/event/EventListener;
12401240
public static final fun handleWith (Llove/forte/simbot/event/EventListener;Llove/forte/simbot/event/EventListenerContext;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
1241+
public static final fun nonBlock (Ljava/lang/Class;Llove/forte/simbot/event/TypedJNonBlockEventListener;)Llove/forte/simbot/event/EventListener;
1242+
public static final fun nonBlock (Llove/forte/simbot/event/JNonBlockEventListener;)Llove/forte/simbot/event/EventListener;
12411243
}
12421244

12431245
public abstract interface class love/forte/simbot/event/EventProcessor {
@@ -1482,6 +1484,16 @@ public final class love/forte/simbot/event/JBlockEventListener$Companion {
14821484
public static synthetic fun toListener$default (Llove/forte/simbot/event/JBlockEventListener$Companion;Lkotlin/coroutines/CoroutineContext;Llove/forte/simbot/event/JBlockEventListener;ILjava/lang/Object;)Llove/forte/simbot/event/EventListener;
14831485
}
14841486

1487+
public abstract interface class love/forte/simbot/event/JNonBlockEventListener {
1488+
public static final field Companion Llove/forte/simbot/event/JNonBlockEventListener$Companion;
1489+
public abstract fun handle (Llove/forte/simbot/event/EventListenerContext;)Llove/forte/simbot/event/EventResult;
1490+
public static fun toListener (Llove/forte/simbot/event/JNonBlockEventListener;)Llove/forte/simbot/event/EventListener;
1491+
}
1492+
1493+
public final class love/forte/simbot/event/JNonBlockEventListener$Companion {
1494+
public final fun toListener (Llove/forte/simbot/event/JNonBlockEventListener;)Llove/forte/simbot/event/EventListener;
1495+
}
1496+
14851497
public abstract interface class love/forte/simbot/event/MemberAuthorAwareMessageEvent : love/forte/simbot/event/ActorAuthorAwareMessageEvent {
14861498
public abstract synthetic fun author (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
14871499
public synthetic fun getAuthor ()Llove/forte/simbot/common/id/IDContainer;
@@ -1729,6 +1741,16 @@ public final class love/forte/simbot/event/TypedJBlockEventListener$Companion {
17291741
public static synthetic fun toListener$default (Llove/forte/simbot/event/TypedJBlockEventListener$Companion;Lkotlin/coroutines/CoroutineContext;Ljava/lang/Class;Llove/forte/simbot/event/TypedJBlockEventListener;ILjava/lang/Object;)Llove/forte/simbot/event/EventListener;
17301742
}
17311743

1744+
public abstract interface class love/forte/simbot/event/TypedJNonBlockEventListener {
1745+
public static final field Companion Llove/forte/simbot/event/TypedJNonBlockEventListener$Companion;
1746+
public abstract fun handle (Llove/forte/simbot/event/EventListenerContext;Llove/forte/simbot/event/Event;)Llove/forte/simbot/event/EventResult;
1747+
public static fun toListener (Ljava/lang/Class;Llove/forte/simbot/event/TypedJNonBlockEventListener;)Llove/forte/simbot/event/EventListener;
1748+
}
1749+
1750+
public final class love/forte/simbot/event/TypedJNonBlockEventListener$Companion {
1751+
public final fun toListener (Ljava/lang/Class;Llove/forte/simbot/event/TypedJNonBlockEventListener;)Llove/forte/simbot/event/EventListener;
1752+
}
1753+
17321754
public abstract class love/forte/simbot/message/AggregatedMessageReceipt : java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker, love/forte/simbot/message/StandardMessageReceipt {
17331755
public fun <init> ()V
17341756
public synthetic fun delete ([Llove/forte/simbot/ability/DeleteOption;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;

simbot-api/src/commonMain/kotlin/love/forte/simbot/event/EventResult.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Project https://github.com/simple-robot/simpler-robot
55
66
*
7-
* This file is part of the Simple Robot Library.
7+
* This file is part of the Simple Robot Library (Alias: simple-robot, simbot, etc.).
88
*
99
* This program is free software: you can redistribute it and/or modify
1010
* it under the terms of the GNU Lesser General Public License as published by
@@ -261,6 +261,8 @@ public sealed class StandardEventResult : EventResult {
261261
*
262262
* 首次结果收集应当由 [EventDispatcher] 推送结果之前即完成,因此 [EventProcessor.push]
263263
* 的结果中不会出现从未收集过结果的 result。
264+
*
265+
* @see Simple
264266
*/
265267
public abstract class CollectableReactivelyResult : StandardEventResult() {
266268

simbot-api/src/jvmMain/kotlin/love/forte/simbot/event/EventListener.jvm.kt

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,14 @@ package love.forte.simbot.event
2929
import kotlinx.coroutines.Dispatchers
3030
import kotlinx.coroutines.future.await
3131
import kotlinx.coroutines.runInterruptible
32+
import love.forte.simbot.annotations.Api4J
3233
import love.forte.simbot.event.EventResult.Companion.invalid
3334
import love.forte.simbot.event.JAsyncEventListener.Companion.toListener
3435
import love.forte.simbot.event.JBlockEventListener.Companion.toListener
36+
import love.forte.simbot.event.JNonBlockEventListener.Companion.toListener
3537
import love.forte.simbot.event.TypedJAsyncEventListener.Companion.toListener
3638
import love.forte.simbot.event.TypedJBlockEventListener.Companion.toListener
39+
import love.forte.simbot.event.TypedJNonBlockEventListener.Companion.toListener
3740
import org.jetbrains.annotations.Blocking
3841
import org.jetbrains.annotations.NonBlocking
3942
import java.util.concurrent.CompletableFuture
@@ -387,6 +390,7 @@ private class TypedJBlockingEventListenerImpl<E : Event>(
387390
/**
388391
* 创建一个基于 [CompletionStage] 的异步事件处理器。
389392
*/
393+
@Api4J
390394
public fun async(function: JAsyncEventListener): EventListener =
391395
toListener(function)
392396

@@ -395,6 +399,7 @@ public fun async(function: JAsyncEventListener): EventListener =
395399
* 只处理 [type] 类型的事件。
396400
* 其他类型的事件会直接返回 [EventResult.invalid]。
397401
*/
402+
@Api4J
398403
public fun <E : Event> async(type: Class<E>, function: TypedJAsyncEventListener<E>): EventListener =
399404
toListener(type, function)
400405

@@ -404,6 +409,7 @@ public fun <E : Event> async(type: Class<E>, function: TypedJAsyncEventListener<
404409
* @param dispatcherContext 阻塞逻辑的调度上下文。默认为 [Dispatchers.IO]。
405410
* 会在 [runInterruptible] 中使用。
406411
*/
412+
@Api4J
407413
@JvmOverloads
408414
public fun block(dispatcherContext: CoroutineContext = Dispatchers.IO, function: JBlockEventListener): EventListener =
409415
toListener(dispatcherContext, function)
@@ -416,6 +422,7 @@ public fun block(dispatcherContext: CoroutineContext = Dispatchers.IO, function:
416422
* @param dispatcherContext 阻塞逻辑的调度上下文。默认为 [Dispatchers.IO]。
417423
* 会在 [runInterruptible] 中使用。
418424
*/
425+
@Api4J
419426
@JvmOverloads
420427
public fun <E : Event> block(
421428
dispatcherContext: CoroutineContext = Dispatchers.IO,
@@ -424,3 +431,223 @@ public fun <E : Event> block(
424431
): EventListener =
425432
toListener(dispatcherContext, type, function)
426433

434+
435+
/**
436+
* 一个事件 [Event] 的非阻塞监听器。也可以称之为事件处理器。
437+
*
438+
* 是针对JVM平台的兼容类型,可以通过 [toListener] 转化为 [EventListener] 类型。
439+
*
440+
* 如果希望针对某个具体的事件类型进行处理,可参考 [TypedJNonBlockEventListener]。
441+
*
442+
* 与 [JBlockEventListener] 不同,[JNonBlockEventListener]
443+
* 不会在执行 [handle] 的时候进行额外的处理(例如使用 [runInterruptible]、[Dispatchers.IO] 等),
444+
* 因此 [JNonBlockEventListener] 更适合用于返回那些**非阻塞**的结果。
445+
*
446+
* [handle] 默认被视为非阻塞的,并将响应式结果 (或其他可收集结果)
447+
* 放在 [StandardEventResult.CollectableReactivelyResult]
448+
* 类型的结果内。
449+
*
450+
* ```java
451+
* EventListeners.nonBlock(
452+
* (context) -> {
453+
* return EventResult.of(
454+
* Mono.just("Hello.");
455+
* );
456+
* }
457+
* );
458+
* ```
459+
*
460+
* @see EventListener
461+
* @see toListener
462+
* @see TypedJNonBlockEventListener
463+
*
464+
* @since 4.1.0
465+
*
466+
* @author ForteScarlet
467+
*/
468+
public fun interface JNonBlockEventListener {
469+
/**
470+
* 通过 [context] 处理事件并得到响应结果。
471+
*
472+
* @throws Exception 任何可能抛出的异常
473+
*/
474+
@Throws(Exception::class)
475+
@NonBlocking
476+
public fun handle(context: EventListenerContext): EventResult
477+
478+
public companion object {
479+
/**
480+
* Converts a [JNonBlockEventListener] to an EventListener.
481+
*
482+
* @param listener The [JNonBlockEventListener] to be converted.
483+
* @return The converted [EventListener].
484+
*/
485+
@JvmStatic
486+
public fun toListener(listener: JNonBlockEventListener): EventListener =
487+
listener.toEventListener()
488+
489+
490+
/**
491+
* 将 [JNonBlockEventListener] 转化为 [EventListener]。
492+
*/
493+
private fun JNonBlockEventListener.toEventListener(): EventListener =
494+
JNonBlockEventListenerImpl(this)
495+
}
496+
}
497+
498+
/**
499+
* 一个事件 [Event] 的非阻塞监听器。也可以称之为事件处理器。
500+
*
501+
* 是针对JVM平台的兼容类型,可以通过 [toListener] 转化为 [EventListener] 类型。
502+
*
503+
* 会针对指定的类型进行事件处理。如果类型不匹配则会返回 [EventResult.invalid]。
504+
*
505+
* 与 [TypedJBlockEventListener] 不同,[TypedJNonBlockEventListener]
506+
* 不会在执行 [handle] 的时候进行额外的处理(例如使用 [runInterruptible]、[Dispatchers.IO] 等),
507+
* 因此 [TypedJNonBlockEventListener] 更适合用于返回那些**非阻塞**的结果。
508+
*
509+
* [handle] 默认被视为非阻塞的,并将响应式结果 (或其他可收集结果)
510+
* 放在 [StandardEventResult.CollectableReactivelyResult]
511+
* 类型的结果内。
512+
*
513+
* ```java
514+
* EventListeners.nonBlock(
515+
* Event.class,
516+
* (context, event) -> {
517+
* return EventResult.of(
518+
* Mono.just("Hello.");
519+
* );
520+
* }
521+
* );
522+
* ```
523+
*
524+
* @see EventListener
525+
* @see toListener
526+
*
527+
* @see StandardEventResult.CollectableReactivelyResult
528+
* @see StandardEventResult.Simple
529+
*
530+
* @since 4.1.0
531+
*
532+
* @author ForteScarlet
533+
*/
534+
public fun interface TypedJNonBlockEventListener<E : Event> {
535+
/**
536+
* 通过 [context] 处理事件并得到响应结果。
537+
*
538+
* @throws Exception 任何可能抛出的异常
539+
*/
540+
@Throws(Exception::class)
541+
@NonBlocking
542+
public fun handle(context: EventListenerContext, event: E): EventResult
543+
544+
public companion object {
545+
/**
546+
* Converts a [TypedJNonBlockEventListener] to an EventListener.
547+
*
548+
* @param listener The [TypedJNonBlockEventListener] to be converted.
549+
* @return The converted [EventListener].
550+
*/
551+
@JvmStatic
552+
public fun <E : Event> toListener(
553+
type: Class<E>,
554+
listener: TypedJNonBlockEventListener<E>
555+
): EventListener = listener.toEventListener(type)
556+
557+
558+
/**
559+
* 将 [TypedJNonBlockEventListener] 转化为 [EventListener]。
560+
*/
561+
private fun <E : Event> TypedJNonBlockEventListener<E>.toEventListener(
562+
type: Class<E>,
563+
): EventListener =
564+
TypedJNonBlockEventListenerImpl(type, this)
565+
}
566+
}
567+
568+
private class JNonBlockEventListenerImpl(
569+
private val jnbListener: JNonBlockEventListener,
570+
) : EventListener {
571+
override suspend fun EventListenerContext.handle(): EventResult {
572+
return jnbListener.handle(this)
573+
}
574+
575+
override fun equals(other: Any?): Boolean {
576+
if (this === other) return true
577+
if (other !is JNonBlockEventListenerImpl) return false
578+
579+
if (jnbListener != other.jnbListener) return false
580+
581+
return true
582+
}
583+
584+
override fun hashCode(): Int {
585+
return jnbListener.hashCode()
586+
}
587+
588+
override fun toString(): String {
589+
return "JNonBlockEventListener(listener=$jnbListener)"
590+
}
591+
}
592+
593+
private class TypedJNonBlockEventListenerImpl<E : Event>(
594+
private val type: Class<E>,
595+
private val listener: TypedJNonBlockEventListener<E>,
596+
) : EventListener {
597+
override suspend fun EventListenerContext.handle(): EventResult {
598+
val event = context.event
599+
if (type.isInstance(event)) {
600+
return this@TypedJNonBlockEventListenerImpl.listener.handle(this, type.cast(event))
601+
}
602+
603+
return invalid()
604+
}
605+
606+
override fun equals(other: Any?): Boolean {
607+
if (this === other) return true
608+
if (other !is TypedJNonBlockEventListenerImpl<*>) return false
609+
610+
if (type != other.type) return false
611+
if (listener != other.listener) return false
612+
613+
return true
614+
}
615+
616+
override fun hashCode(): Int {
617+
var result = type.hashCode()
618+
result = 31 * result + listener.hashCode()
619+
return result
620+
}
621+
622+
override fun toString(): String {
623+
return "TypedJNonBlockEventListener(type=$type, listener=$listener)"
624+
}
625+
}
626+
627+
628+
/**
629+
* 创建一个非阻塞事件处理器。
630+
*
631+
* @since 4.1.0
632+
*
633+
* @see JNonBlockEventListener
634+
*/
635+
@Api4J
636+
public fun nonBlock(function: JNonBlockEventListener): EventListener =
637+
toListener(function)
638+
639+
/**
640+
* 创建一个非阻塞事件处理器,
641+
* 只处理 [type] 类型的事件。
642+
* 其他类型的事件会直接返回 [EventResult.invalid]。
643+
*
644+
* @since 4.1.0
645+
*
646+
* @see TypedJNonBlockEventListener
647+
*/
648+
@Api4J
649+
public fun <E : Event> nonBlock(
650+
type: Class<E>,
651+
function: TypedJNonBlockEventListener<E>
652+
): EventListener =
653+
toListener(type, function)

0 commit comments

Comments
 (0)