Add Java friendly functional event subscribers to EventChannel

This commit is contained in:
Him188 2020-12-27 14:47:09 +08:00
parent 96c7b51094
commit 7df0c96004
2 changed files with 156 additions and 10 deletions

View File

@ -14,6 +14,7 @@ package net.mamoe.mirai.event
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import net.mamoe.mirai.Bot
import net.mamoe.mirai.JavaFriendlyAPI
import net.mamoe.mirai.event.Listener.ConcurrencyKind.CONCURRENT
import net.mamoe.mirai.event.Listener.ConcurrencyKind.LOCKED
import net.mamoe.mirai.event.events.BotEvent
@ -22,8 +23,10 @@ import net.mamoe.mirai.event.internal.Handler
import net.mamoe.mirai.event.internal.ListenerRegistry
import net.mamoe.mirai.utils.MiraiExperimentalApi
import net.mamoe.mirai.utils.MiraiLogger
import java.util.function.Consumer
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.suspendCoroutine
import kotlin.internal.LowPriorityInOverloadResolution
import kotlin.reflect.KClass
@ -156,6 +159,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads constructor(
*
* @see filterIsInstance 过滤指定类型的事件
*/
@JvmSynthetic
public fun filter(filter: suspend (event: @UnsafeVariance BaseEvent) -> Boolean): EventChannel<BaseEvent> {
return object : EventChannel<BaseEvent>(baseEventClass, defaultCoroutineContext) {
private inline val innerThis get() = this
@ -180,6 +184,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads constructor(
* 过滤事件的类型. 返回一个只包含 [E] 类型事件的 [EventChannel]
* @see filter 获取更多信息
*/
@JvmSynthetic
public inline fun <reified E : Event> filterIsInstance(): EventChannel<E> =
filterIsInstance(E::class)
@ -293,8 +298,8 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads constructor(
* ```
* val scope = CoroutineScope(SupervisorJob())
*
* scope.subscribeAlways<MemberJoinEvent> { /* ... */ }
* scope.subscribeAlways<MemberMuteEvent> { /* ... */ }
* eventChannel.subscribeAlways<MemberJoinEvent> { /* ... */ }
* eventChannel.subscribeAlways<MemberMuteEvent> { /* ... */ }
*
* scope.cancel() // 停止上文两个监听
* ```
@ -350,6 +355,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads constructor(
* @see subscribeFriendMessages 监听好友消息 DSL
* @see subscribeTempMessages 监听临时会话消息 DSL
*/
@JvmSynthetic
public inline fun <reified E : Event> subscribe(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
concurrency: Listener.ConcurrencyKind = LOCKED,
@ -363,6 +369,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads constructor(
* @return 监听器实例. 此监听器已经注册到指定事件上, 在事件广播时将会调用 [handler]
* @see subscribe
*/
@JvmSynthetic
public fun <E : Event> subscribe(
eventClass: KClass<out E>,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
@ -389,6 +396,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads constructor(
*
* @see subscribe 获取更多说明
*/
@JvmSynthetic
public inline fun <reified E : Event> subscribeAlways(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
concurrency: Listener.ConcurrencyKind = CONCURRENT,
@ -401,6 +409,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads constructor(
* @see subscribe
* @see subscribeAlways
*/
@JvmSynthetic
public fun <E : Event> subscribeAlways(
eventClass: KClass<out E>,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
@ -457,7 +466,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads constructor(
* return ListeningStatus.LISTENING
* }
*
* scope.subscribe(::onMessage)
* eventChannel.subscribe(::onMessage)
* ```
* @see subscribe
*/
@ -479,7 +488,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads constructor(
* return ListeningStatus.LISTENING
* }
*
* scope.subscribe(GroupMessageEvent::onMessage)
* eventChannel.subscribe(GroupMessageEvent::onMessage)
* ```
* @see subscribe
*/
@ -501,7 +510,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads constructor(
* return ListeningStatus.LISTENING
* }
*
* scope.subscribe(::onMessage)
* eventChannel.subscribe(::onMessage)
* ```
* @see subscribe
*/
@ -523,7 +532,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads constructor(
* return ListeningStatus.LISTENING
* }
*
* scope.subscribe(GroupMessageEvent::onMessage)
* eventChannel.subscribe(GroupMessageEvent::onMessage)
* ```
* @see subscribe
*/
@ -549,7 +558,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads constructor(
* fun onMessage(event: GroupMessageEvent) {
*
* }
* scope.subscribeAlways(::onMessage)
* eventChannel.subscribeAlways(::onMessage)
* ```
* @see subscribeAlways
*/
@ -569,7 +578,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads constructor(
* fun GroupMessageEvent.onMessage(event: GroupMessageEvent) {
*
* }
* scope.subscribeAlways(GroupMessageEvent::onMessage)
* eventChannel.subscribeAlways(GroupMessageEvent::onMessage)
* ```
* @see subscribeAlways
*/
@ -589,7 +598,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads constructor(
* suspend fun onMessage(event: GroupMessageEvent) {
*
* }
* scope.subscribeAlways(::onMessage)
* eventChannel.subscribeAlways(::onMessage)
* ```
* @see subscribeAlways
*/
@ -609,7 +618,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads constructor(
* suspend fun GroupMessageEvent.onMessage(event: GroupMessageEvent) {
*
* }
* scope.subscribeAlways(GroupMessageEvent::onMessage)
* eventChannel.subscribeAlways(GroupMessageEvent::onMessage)
* ```
* @see subscribeAlways
*/
@ -625,11 +634,106 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads constructor(
// endregion
// region Java API
/**
* Java API. 查看 [subscribeAlways] 获取更多信息.
*
* ```java
* eventChannel.subscribeAlways(GroupMessageEvent.class, (event) -> { });
* ```
*
* @see subscribe
* @see subscribeAlways
*/
@JavaFriendlyAPI
@JvmOverloads
@LowPriorityInOverloadResolution
public fun <E : Event> subscribeAlways(
eventClass: Class<out E>,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
concurrency: Listener.ConcurrencyKind = CONCURRENT,
priority: EventPriority = EventPriority.NORMAL,
handler: Consumer<E>
): Listener<E> = subscribeInternal(
eventClass.kotlin,
createListener(coroutineContext, concurrency, priority) { event ->
val context = currentCoroutineContext()
suspendCoroutine<Unit> { cont ->
Dispatchers.IO.dispatch(context) { cont.resumeWith(kotlin.runCatching { handler.accept(event) }) }
}
ListeningStatus.LISTENING
}
)
/**
* Java API. 查看 [subscribe] 获取更多信息.
*
* ```java
* eventChannel.subscribe(GroupMessageEvent.class, (event) -> {
* return ListeningStatus.LISTENING;
* });
* ```
*
* @see subscribe
*/
@JavaFriendlyAPI
@JvmOverloads
@LowPriorityInOverloadResolution
public fun <E : Event> subscribe(
eventClass: Class<out E>,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
concurrency: Listener.ConcurrencyKind = CONCURRENT,
priority: EventPriority = EventPriority.NORMAL,
handler: java.util.function.Function<E, ListeningStatus>
): Listener<E> = subscribeInternal(
eventClass.kotlin,
createListener(coroutineContext, concurrency, priority) { event ->
val context = currentCoroutineContext()
suspendCoroutine { cont ->
Dispatchers.IO.dispatch(context) { cont.resumeWith(kotlin.runCatching { handler.apply(event) }) }
}
}
)
/**
* Java API. 查看 [subscribeOnce] 获取更多信息.
*
* ```java
* eventChannel.subscribeOnce(GroupMessageEvent.class, (event) -> { });
* ```
*
* @see subscribe
* @see subscribeOnce
*/
@JavaFriendlyAPI
@JvmOverloads
@LowPriorityInOverloadResolution
public fun <E : Event> subscribeOnce(
eventClass: Class<out E>,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
concurrency: Listener.ConcurrencyKind = CONCURRENT,
priority: EventPriority = EventPriority.NORMAL,
handler: Consumer<E>
): Listener<E> = subscribeInternal(
eventClass.kotlin,
createListener(coroutineContext, concurrency, priority) { event ->
val context = currentCoroutineContext()
suspendCoroutine<Unit> { cont ->
Dispatchers.IO.dispatch(context) { cont.resumeWith(kotlin.runCatching { handler.accept(event) }) }
}
ListeningStatus.STOPPED
}
)
// endregion
// region impl
/**
* 由子类实现可以为 handler 包装一个过滤器等. 每个 handler 都会经过此函数处理.
*/
@MiraiExperimentalApi
protected open fun <E : Event> (suspend (E) -> ListeningStatus).intercepted(): (suspend (E) -> ListeningStatus) {
return this
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2019-2020 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
*/
import net.mamoe.mirai.Bot;
import net.mamoe.mirai.BotFactory;
import net.mamoe.mirai.event.ListeningStatus;
import net.mamoe.mirai.event.events.GroupMessageEvent;
import net.mamoe.mirai.event.events.MessageEvent;
import net.mamoe.mirai.utils.BotConfiguration;
/**
* 仅用来测试调用不会被单元测试运行
*/
public class JavaApiTests {
public static void main(String[] args) {
Bot bot = BotFactory.INSTANCE.newBot(11, "", configuration -> {
configuration.fileBasedDeviceInfo();
configuration.setProtocol(BotConfiguration.MiraiProtocol.ANDROID_PHONE);
});
bot.login();
bot.getAsFriend().sendMessage("test"); // blocking bridge
bot.getOtherClients().getOrFail(1).getBot();
bot.getEventChannel().subscribe(MessageEvent.class, event -> {
return ListeningStatus.LISTENING;
});
bot.getEventChannel().subscribeAlways(GroupMessageEvent.class, event -> {
Bot b = event.getBot();
});
}
}