mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-12 10:40:21 +08:00
[Review] Move Listener.ConcurrencyKind and Listener.EventPriority to top-level
This commit is contained in:
parent
4e2108d841
commit
619dafa1ae
@ -53,9 +53,9 @@ public interface Event {
|
|||||||
*
|
*
|
||||||
* 当事件被 [拦截][Event.intercept] 后, 优先级较低 (靠右) 的监听器将不会被调用.
|
* 当事件被 [拦截][Event.intercept] 后, 优先级较低 (靠右) 的监听器将不会被调用.
|
||||||
*
|
*
|
||||||
* 优先级为 [Listener.EventPriority.MONITOR] 的监听器不应该调用这个函数.
|
* 优先级为 [EventPriority.MONITOR] 的监听器不应该调用这个函数.
|
||||||
*
|
*
|
||||||
* @see Listener.EventPriority 查看优先级相关信息
|
* @see EventPriority 查看优先级相关信息
|
||||||
*/
|
*/
|
||||||
public fun intercept()
|
public fun intercept()
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@ import kotlinx.coroutines.*
|
|||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.event.Listener.ConcurrencyKind.CONCURRENT
|
import net.mamoe.mirai.event.ConcurrencyKind.CONCURRENT
|
||||||
import net.mamoe.mirai.event.Listener.ConcurrencyKind.LOCKED
|
import net.mamoe.mirai.event.ConcurrencyKind.LOCKED
|
||||||
import net.mamoe.mirai.event.events.BotEvent
|
import net.mamoe.mirai.event.events.BotEvent
|
||||||
import net.mamoe.mirai.internal.event.GlobalEventListeners
|
import net.mamoe.mirai.internal.event.GlobalEventListeners
|
||||||
import net.mamoe.mirai.internal.event.Handler
|
import net.mamoe.mirai.internal.event.Handler
|
||||||
@ -80,7 +80,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads internal con
|
|||||||
public fun asChannel(
|
public fun asChannel(
|
||||||
capacity: Int = Channel.RENDEZVOUS,
|
capacity: Int = Channel.RENDEZVOUS,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
concurrency: Listener.ConcurrencyKind = CONCURRENT,
|
concurrency: ConcurrencyKind = CONCURRENT,
|
||||||
priority: EventPriority = EventPriority.NORMAL,
|
priority: EventPriority = EventPriority.NORMAL,
|
||||||
): Channel<out BaseEvent> {
|
): Channel<out BaseEvent> {
|
||||||
val channel = Channel<BaseEvent>(capacity)
|
val channel = Channel<BaseEvent>(capacity)
|
||||||
@ -120,7 +120,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads internal con
|
|||||||
* [filter] 允许挂起协程. **过滤器的挂起将被认为是事件监听器的挂起**.
|
* [filter] 允许挂起协程. **过滤器的挂起将被认为是事件监听器的挂起**.
|
||||||
*
|
*
|
||||||
* 过滤器挂起是否会影响事件处理,
|
* 过滤器挂起是否会影响事件处理,
|
||||||
* 取决于 [subscribe] 时的 [Listener.ConcurrencyKind] 和 [Listener.EventPriority].
|
* 取决于 [subscribe] 时的 [ConcurrencyKind] 和 [EventPriority].
|
||||||
*
|
*
|
||||||
* ## 过滤器异常处理
|
* ## 过滤器异常处理
|
||||||
* 若 [filter] 抛出异常, 将被包装为 [ExceptionInEventChannelFilterException] 并重新抛出.
|
* 若 [filter] 抛出异常, 将被包装为 [ExceptionInEventChannelFilterException] 并重新抛出.
|
||||||
@ -305,11 +305,11 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads internal con
|
|||||||
* ## 并发安全性
|
* ## 并发安全性
|
||||||
* 基于 [concurrency] 参数, 事件监听器可以被允许并行执行.
|
* 基于 [concurrency] 参数, 事件监听器可以被允许并行执行.
|
||||||
*
|
*
|
||||||
* - 若 [concurrency] 为 [Listener.ConcurrencyKind.CONCURRENT], [handler] 可能被并行调用, 需要保证并发安全.
|
* - 若 [concurrency] 为 [ConcurrencyKind.CONCURRENT], [handler] 可能被并行调用, 需要保证并发安全.
|
||||||
* - 若 [concurrency] 为 [Listener.ConcurrencyKind.LOCKED], [handler] 会被 [Mutex] 限制.
|
* - 若 [concurrency] 为 [ConcurrencyKind.LOCKED], [handler] 会被 [Mutex] 限制.
|
||||||
*
|
*
|
||||||
* @param coroutineContext 在 [defaultCoroutineContext] 的基础上, 给事件监听协程的额外的 [CoroutineContext].
|
* @param coroutineContext 在 [defaultCoroutineContext] 的基础上, 给事件监听协程的额外的 [CoroutineContext].
|
||||||
* @param concurrency 并发类型. 查看 [Listener.ConcurrencyKind]
|
* @param concurrency 并发类型. 查看 [ConcurrencyKind]
|
||||||
* @param priority 监听优先级,优先级越高越先执行
|
* @param priority 监听优先级,优先级越高越先执行
|
||||||
* @param handler 事件处理器. 在接收到事件时会调用这个处理器. 其返回值意义参考 [ListeningStatus]. 其异常处理参考上文
|
* @param handler 事件处理器. 在接收到事件时会调用这个处理器. 其返回值意义参考 [ListeningStatus]. 其异常处理参考上文
|
||||||
*
|
*
|
||||||
@ -331,7 +331,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads internal con
|
|||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
public inline fun <reified E : Event> subscribe(
|
public inline fun <reified E : Event> subscribe(
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
concurrency: Listener.ConcurrencyKind = LOCKED,
|
concurrency: ConcurrencyKind = LOCKED,
|
||||||
priority: EventPriority = EventPriority.NORMAL,
|
priority: EventPriority = EventPriority.NORMAL,
|
||||||
noinline handler: suspend E.(E) -> ListeningStatus
|
noinline handler: suspend E.(E) -> ListeningStatus
|
||||||
): Listener<E> = subscribe(E::class, coroutineContext, concurrency, priority, handler)
|
): Listener<E> = subscribe(E::class, coroutineContext, concurrency, priority, handler)
|
||||||
@ -346,7 +346,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads internal con
|
|||||||
public fun <E : Event> subscribe(
|
public fun <E : Event> subscribe(
|
||||||
eventClass: KClass<out E>,
|
eventClass: KClass<out E>,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
concurrency: Listener.ConcurrencyKind = LOCKED,
|
concurrency: ConcurrencyKind = LOCKED,
|
||||||
priority: EventPriority = EventPriority.NORMAL,
|
priority: EventPriority = EventPriority.NORMAL,
|
||||||
handler: suspend E.(E) -> ListeningStatus
|
handler: suspend E.(E) -> ListeningStatus
|
||||||
): Listener<E> = subscribeInternal(
|
): Listener<E> = subscribeInternal(
|
||||||
@ -372,7 +372,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads internal con
|
|||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
public inline fun <reified E : Event> subscribeAlways(
|
public inline fun <reified E : Event> subscribeAlways(
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
concurrency: Listener.ConcurrencyKind = CONCURRENT,
|
concurrency: ConcurrencyKind = CONCURRENT,
|
||||||
priority: EventPriority = EventPriority.NORMAL,
|
priority: EventPriority = EventPriority.NORMAL,
|
||||||
noinline handler: suspend E.(E) -> Unit
|
noinline handler: suspend E.(E) -> Unit
|
||||||
): Listener<E> = subscribeAlways(E::class, coroutineContext, concurrency, priority, handler)
|
): Listener<E> = subscribeAlways(E::class, coroutineContext, concurrency, priority, handler)
|
||||||
@ -386,7 +386,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads internal con
|
|||||||
public fun <E : Event> subscribeAlways(
|
public fun <E : Event> subscribeAlways(
|
||||||
eventClass: KClass<out E>,
|
eventClass: KClass<out E>,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
concurrency: Listener.ConcurrencyKind = CONCURRENT,
|
concurrency: ConcurrencyKind = CONCURRENT,
|
||||||
priority: EventPriority = EventPriority.NORMAL,
|
priority: EventPriority = EventPriority.NORMAL,
|
||||||
handler: suspend E.(E) -> Unit
|
handler: suspend E.(E) -> Unit
|
||||||
): Listener<E> = subscribeInternal(
|
): Listener<E> = subscribeInternal(
|
||||||
@ -465,7 +465,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads internal con
|
|||||||
public fun <E : Event> subscribeAlways(
|
public fun <E : Event> subscribeAlways(
|
||||||
eventClass: Class<out E>,
|
eventClass: Class<out E>,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
concurrency: Listener.ConcurrencyKind = CONCURRENT,
|
concurrency: ConcurrencyKind = CONCURRENT,
|
||||||
priority: EventPriority = EventPriority.NORMAL,
|
priority: EventPriority = EventPriority.NORMAL,
|
||||||
handler: Consumer<E>
|
handler: Consumer<E>
|
||||||
): Listener<E> = subscribeInternal(
|
): Listener<E> = subscribeInternal(
|
||||||
@ -495,7 +495,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads internal con
|
|||||||
public fun <E : Event> subscribe(
|
public fun <E : Event> subscribe(
|
||||||
eventClass: Class<out E>,
|
eventClass: Class<out E>,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
concurrency: Listener.ConcurrencyKind = CONCURRENT,
|
concurrency: ConcurrencyKind = CONCURRENT,
|
||||||
priority: EventPriority = EventPriority.NORMAL,
|
priority: EventPriority = EventPriority.NORMAL,
|
||||||
handler: java.util.function.Function<E, ListeningStatus>
|
handler: java.util.function.Function<E, ListeningStatus>
|
||||||
): Listener<E> = subscribeInternal(
|
): Listener<E> = subscribeInternal(
|
||||||
@ -523,7 +523,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads internal con
|
|||||||
public fun <E : Event> subscribeOnce(
|
public fun <E : Event> subscribeOnce(
|
||||||
eventClass: Class<out E>,
|
eventClass: Class<out E>,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
concurrency: Listener.ConcurrencyKind = CONCURRENT,
|
concurrency: ConcurrencyKind = CONCURRENT,
|
||||||
priority: EventPriority = EventPriority.NORMAL,
|
priority: EventPriority = EventPriority.NORMAL,
|
||||||
handler: Consumer<E>
|
handler: Consumer<E>
|
||||||
): Listener<E> = subscribeInternal(
|
): Listener<E> = subscribeInternal(
|
||||||
@ -565,8 +565,8 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads internal con
|
|||||||
@Suppress("FunctionName")
|
@Suppress("FunctionName")
|
||||||
private fun <E : Event> createListener(
|
private fun <E : Event> createListener(
|
||||||
coroutineContext: CoroutineContext,
|
coroutineContext: CoroutineContext,
|
||||||
concurrencyKind: Listener.ConcurrencyKind,
|
concurrencyKind: ConcurrencyKind,
|
||||||
priority: Listener.EventPriority = EventPriority.NORMAL,
|
priority: EventPriority = EventPriority.NORMAL,
|
||||||
handler: suspend (E) -> ListeningStatus
|
handler: suspend (E) -> ListeningStatus
|
||||||
): Listener<E> {
|
): Listener<E> {
|
||||||
val context = this.defaultCoroutineContext + coroutineContext
|
val context = this.defaultCoroutineContext + coroutineContext
|
||||||
|
@ -34,7 +34,7 @@ import kotlin.internal.LowPriorityInOverloadResolution
|
|||||||
public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>.subscribe(
|
public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>.subscribe(
|
||||||
crossinline handler: suspend E.(E) -> ListeningStatus,
|
crossinline handler: suspend E.(E) -> ListeningStatus,
|
||||||
priority: EventPriority = EventPriority.NORMAL,
|
priority: EventPriority = EventPriority.NORMAL,
|
||||||
concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT,
|
concurrency: ConcurrencyKind = ConcurrencyKind.CONCURRENT,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||||
): Listener<E> = subscribe(E::class, coroutineContext, concurrency, priority) { handler(this) }
|
): Listener<E> = subscribe(E::class, coroutineContext, concurrency, priority) { handler(this) }
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>
|
|||||||
public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>.subscribe(
|
public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>.subscribe(
|
||||||
crossinline handler: suspend (E) -> ListeningStatus,
|
crossinline handler: suspend (E) -> ListeningStatus,
|
||||||
priority: EventPriority = EventPriority.NORMAL,
|
priority: EventPriority = EventPriority.NORMAL,
|
||||||
concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT,
|
concurrency: ConcurrencyKind = ConcurrencyKind.CONCURRENT,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||||
): Listener<E> = subscribe(E::class, coroutineContext, concurrency, priority) { handler(this) }
|
): Listener<E> = subscribe(E::class, coroutineContext, concurrency, priority) { handler(this) }
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>
|
|||||||
public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>.subscribe(
|
public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>.subscribe(
|
||||||
crossinline handler: E.(E) -> ListeningStatus,
|
crossinline handler: E.(E) -> ListeningStatus,
|
||||||
priority: EventPriority = EventPriority.NORMAL,
|
priority: EventPriority = EventPriority.NORMAL,
|
||||||
concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT,
|
concurrency: ConcurrencyKind = ConcurrencyKind.CONCURRENT,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||||
): Listener<E> = subscribe(E::class, coroutineContext, concurrency, priority) { handler(this) }
|
): Listener<E> = subscribe(E::class, coroutineContext, concurrency, priority) { handler(this) }
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>
|
|||||||
public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>.subscribe(
|
public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>.subscribe(
|
||||||
crossinline handler: (E) -> ListeningStatus,
|
crossinline handler: (E) -> ListeningStatus,
|
||||||
priority: EventPriority = EventPriority.NORMAL,
|
priority: EventPriority = EventPriority.NORMAL,
|
||||||
concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT,
|
concurrency: ConcurrencyKind = ConcurrencyKind.CONCURRENT,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||||
): Listener<E> = subscribe(E::class, coroutineContext, concurrency, priority) { handler(this) }
|
): Listener<E> = subscribe(E::class, coroutineContext, concurrency, priority) { handler(this) }
|
||||||
|
|
||||||
@ -118,7 +118,7 @@ public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>
|
|||||||
public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>.subscribeAlways(
|
public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>.subscribeAlways(
|
||||||
crossinline handler: suspend (E) -> Unit,
|
crossinline handler: suspend (E) -> Unit,
|
||||||
priority: EventPriority = EventPriority.NORMAL,
|
priority: EventPriority = EventPriority.NORMAL,
|
||||||
concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT,
|
concurrency: ConcurrencyKind = ConcurrencyKind.CONCURRENT,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||||
): Listener<E> = subscribeAlways(E::class, coroutineContext, concurrency, priority) { handler(this) }
|
): Listener<E> = subscribeAlways(E::class, coroutineContext, concurrency, priority) { handler(this) }
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>
|
|||||||
public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>.subscribeAlways(
|
public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>.subscribeAlways(
|
||||||
crossinline handler: suspend E.(E) -> Unit,
|
crossinline handler: suspend E.(E) -> Unit,
|
||||||
priority: EventPriority = EventPriority.NORMAL,
|
priority: EventPriority = EventPriority.NORMAL,
|
||||||
concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT,
|
concurrency: ConcurrencyKind = ConcurrencyKind.CONCURRENT,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||||
): Listener<E> = subscribeAlways(E::class, coroutineContext, concurrency, priority) { handler(this) }
|
): Listener<E> = subscribeAlways(E::class, coroutineContext, concurrency, priority) { handler(this) }
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>
|
|||||||
public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>.subscribeAlways(
|
public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>.subscribeAlways(
|
||||||
crossinline handler: E.(E) -> Unit,
|
crossinline handler: E.(E) -> Unit,
|
||||||
priority: EventPriority = EventPriority.NORMAL,
|
priority: EventPriority = EventPriority.NORMAL,
|
||||||
concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT,
|
concurrency: ConcurrencyKind = ConcurrencyKind.CONCURRENT,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||||
): Listener<E> = subscribeAlways(E::class, coroutineContext, concurrency, priority) { handler(this) }
|
): Listener<E> = subscribeAlways(E::class, coroutineContext, concurrency, priority) { handler(this) }
|
||||||
|
|
||||||
@ -176,6 +176,6 @@ public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>
|
|||||||
public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>.subscribeAlways(
|
public inline fun <BaseEvent : Event, reified E : Event> EventChannel<BaseEvent>.subscribeAlways(
|
||||||
crossinline handler: (E) -> Unit,
|
crossinline handler: (E) -> Unit,
|
||||||
priority: EventPriority = EventPriority.NORMAL,
|
priority: EventPriority = EventPriority.NORMAL,
|
||||||
concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT,
|
concurrency: ConcurrencyKind = ConcurrencyKind.CONCURRENT,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||||
): Listener<E> = subscribeAlways(E::class, coroutineContext, concurrency, priority) { handler(this) }
|
): Listener<E> = subscribeAlways(E::class, coroutineContext, concurrency, priority) { handler(this) }
|
@ -147,10 +147,10 @@ import kotlin.coroutines.EmptyCoroutineContext
|
|||||||
public annotation class EventHandler(
|
public annotation class EventHandler(
|
||||||
/**
|
/**
|
||||||
* 监听器优先级
|
* 监听器优先级
|
||||||
* @see Listener.EventPriority 查看优先级相关信息
|
* @see EventPriority 查看优先级相关信息
|
||||||
* @see Event.intercept 拦截事件
|
* @see Event.intercept 拦截事件
|
||||||
*/
|
*/
|
||||||
public val priority: Listener.EventPriority = EventPriority.NORMAL,
|
public val priority: EventPriority = EventPriority.NORMAL,
|
||||||
/**
|
/**
|
||||||
* 是否自动忽略被 [取消][CancellableEvent.isCancelled]
|
* 是否自动忽略被 [取消][CancellableEvent.isCancelled]
|
||||||
* @see CancellableEvent
|
* @see CancellableEvent
|
||||||
@ -158,9 +158,9 @@ public annotation class EventHandler(
|
|||||||
public val ignoreCancelled: Boolean = true,
|
public val ignoreCancelled: Boolean = true,
|
||||||
/**
|
/**
|
||||||
* 并发类型
|
* 并发类型
|
||||||
* @see Listener.ConcurrencyKind
|
* @see ConcurrencyKind
|
||||||
*/
|
*/
|
||||||
public val concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT
|
public val concurrency: ConcurrencyKind = ConcurrencyKind.CONCURRENT
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,7 +15,7 @@ package net.mamoe.mirai.event
|
|||||||
|
|
||||||
import kotlinx.coroutines.CompletableJob
|
import kotlinx.coroutines.CompletableJob
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import net.mamoe.mirai.event.Listener.EventPriority.*
|
import net.mamoe.mirai.event.EventPriority.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 订阅者的状态
|
* 订阅者的状态
|
||||||
@ -29,9 +29,9 @@ public enum class ListeningStatus {
|
|||||||
/**
|
/**
|
||||||
* 表示已停止.
|
* 表示已停止.
|
||||||
*
|
*
|
||||||
* - 若监听器使用 [Listener.ConcurrencyKind.LOCKED],
|
* - 若监听器使用 [ConcurrencyKind.LOCKED],
|
||||||
* 在这之后监听器将会被从监听器列表中删除, 因此不再能接收到事件.
|
* 在这之后监听器将会被从监听器列表中删除, 因此不再能接收到事件.
|
||||||
* - 若使用 [Listener.ConcurrencyKind.CONCURRENT],
|
* - 若使用 [ConcurrencyKind.CONCURRENT],
|
||||||
* 在这之后无法保证立即停止监听.
|
* 在这之后无法保证立即停止监听.
|
||||||
*/
|
*/
|
||||||
STOPPED
|
STOPPED
|
||||||
@ -45,9 +45,29 @@ public enum class ListeningStatus {
|
|||||||
*/
|
*/
|
||||||
public interface Listener<in E : Event> : CompletableJob {
|
public interface Listener<in E : Event> : CompletableJob {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 并发类型
|
||||||
|
*/
|
||||||
|
public val concurrencyKind: ConcurrencyKind
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 事件优先级
|
||||||
|
* @see [EventPriority]
|
||||||
|
*/
|
||||||
|
public val priority: EventPriority get() = NORMAL
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 这个方法将会调用 [EventChannel.subscribe] 时提供的参数 `noinline handler: suspend E.(E) -> ListeningStatus`.
|
||||||
|
*
|
||||||
|
* 这个函数不会抛出任何异常, 详见 [EventChannel.subscribe]
|
||||||
|
*/
|
||||||
|
public suspend fun onEvent(event: E): ListeningStatus
|
||||||
|
}
|
||||||
|
|
||||||
public enum class ConcurrencyKind {
|
public enum class ConcurrencyKind {
|
||||||
/**
|
/**
|
||||||
* 并发地同时处理多个事件, 但无法保证 [onEvent] 返回 [ListeningStatus.STOPPED] 后立即停止事件监听.
|
* 并发地同时处理多个事件, 但无法保证 [Listener.onEvent] 返回 [ListeningStatus.STOPPED] 后立即停止事件监听.
|
||||||
*/
|
*/
|
||||||
CONCURRENT,
|
CONCURRENT,
|
||||||
|
|
||||||
@ -57,16 +77,12 @@ public interface Listener<in E : Event> : CompletableJob {
|
|||||||
LOCKED
|
LOCKED
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 并发类型
|
|
||||||
*/
|
|
||||||
public val concurrencyKind: ConcurrencyKind
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 事件优先级.
|
* 事件优先级.
|
||||||
*
|
*
|
||||||
* 在广播时, 事件监听器的调用顺序为 (从左到右):
|
* 在广播时, 事件监听器的调用顺序为 (从左到右):
|
||||||
* `[HIGHEST]` -> `[HIGH]` -> `[NORMAL]` -> `[LOW]` -> `[LOWEST]` -> `[MONITOR]`
|
* [HIGHEST] -> [HIGH] -> [NORMAL] -> [LOW] -> [LOWEST] -> [MONITOR]
|
||||||
*
|
*
|
||||||
* - 使用 [MONITOR] 优先级的监听器将会被**并行**调用.
|
* - 使用 [MONITOR] 优先级的监听器将会被**并行**调用.
|
||||||
* - 使用其他优先级的监听器都将会**按顺序**调用.
|
* - 使用其他优先级的监听器都将会**按顺序**调用.
|
||||||
@ -93,19 +109,3 @@ public interface Listener<in E : Event> : CompletableJob {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 事件优先级
|
|
||||||
* @see [EventPriority]
|
|
||||||
*/
|
|
||||||
public val priority: EventPriority get() = NORMAL
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 这个方法将会调用 [EventChannel.subscribe] 时提供的参数 `noinline handler: suspend E.(E) -> ListeningStatus`.
|
|
||||||
*
|
|
||||||
* 这个函数不会抛出任何异常, 详见 [EventChannel.subscribe]
|
|
||||||
*/
|
|
||||||
public suspend fun onEvent(event: E): ListeningStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
public typealias EventPriority = Listener.EventPriority
|
|
@ -32,7 +32,7 @@ import kotlin.reflect.KClass
|
|||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
public suspend inline fun <reified E : Event> nextEvent(
|
public suspend inline fun <reified E : Event> nextEvent(
|
||||||
timeoutMillis: Long = -1,
|
timeoutMillis: Long = -1,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
crossinline filter: (E) -> Boolean = { true }
|
crossinline filter: (E) -> Boolean = { true }
|
||||||
): E {
|
): E {
|
||||||
require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" }
|
require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" }
|
||||||
@ -56,7 +56,7 @@ public suspend inline fun <reified E : Event> nextEvent(
|
|||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
public suspend inline fun <reified E : Event> nextEventOrNull(
|
public suspend inline fun <reified E : Event> nextEventOrNull(
|
||||||
timeoutMillis: Long,
|
timeoutMillis: Long,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
crossinline filter: (E) -> Boolean = { true }
|
crossinline filter: (E) -> Boolean = { true }
|
||||||
): E? {
|
): E? {
|
||||||
return withTimeoutOrNull(timeoutMillis) {
|
return withTimeoutOrNull(timeoutMillis) {
|
||||||
@ -70,7 +70,7 @@ public suspend inline fun <reified E : Event> nextEventOrNull(
|
|||||||
internal suspend inline fun <E : Event> nextEventImpl(
|
internal suspend inline fun <E : Event> nextEventImpl(
|
||||||
eventClass: KClass<E>,
|
eventClass: KClass<E>,
|
||||||
coroutineScope: CoroutineScope,
|
coroutineScope: CoroutineScope,
|
||||||
priority: Listener.EventPriority,
|
priority: EventPriority,
|
||||||
crossinline filter: (E) -> Boolean
|
crossinline filter: (E) -> Boolean
|
||||||
): E = suspendCancellableCoroutine { cont ->
|
): E = suspendCancellableCoroutine { cont ->
|
||||||
coroutineScope.globalEventChannel().subscribe(eventClass, priority = priority) {
|
coroutineScope.globalEventChannel().subscribe(eventClass, priority = priority) {
|
||||||
@ -90,7 +90,7 @@ internal suspend inline fun <E : BotEvent> nextBotEventImpl(
|
|||||||
bot: Bot,
|
bot: Bot,
|
||||||
eventClass: KClass<E>,
|
eventClass: KClass<E>,
|
||||||
coroutineScope: CoroutineScope,
|
coroutineScope: CoroutineScope,
|
||||||
priority: Listener.EventPriority
|
priority: EventPriority
|
||||||
): E = suspendCancellableCoroutine { cont ->
|
): E = suspendCancellableCoroutine { cont ->
|
||||||
coroutineScope.globalEventChannel().subscribe(eventClass, priority = priority) {
|
coroutineScope.globalEventChannel().subscribe(eventClass, priority = priority) {
|
||||||
try {
|
try {
|
||||||
|
@ -61,7 +61,7 @@ import net.mamoe.mirai.utils.MiraiExperimentalApi
|
|||||||
public suspend inline fun <reified T : MessageEvent> T.whileSelectMessages(
|
public suspend inline fun <reified T : MessageEvent> T.whileSelectMessages(
|
||||||
timeoutMillis: Long = -1,
|
timeoutMillis: Long = -1,
|
||||||
filterContext: Boolean = true,
|
filterContext: Boolean = true,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
@BuilderInference crossinline selectBuilder: @MessageDsl MessageSelectBuilder<T, Boolean>.() -> Unit
|
@BuilderInference crossinline selectBuilder: @MessageDsl MessageSelectBuilder<T, Boolean>.() -> Unit
|
||||||
): Unit = whileSelectMessagesImpl(timeoutMillis, filterContext, priority, selectBuilder)
|
): Unit = whileSelectMessagesImpl(timeoutMillis, filterContext, priority, selectBuilder)
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ public suspend inline fun <reified T : MessageEvent> T.whileSelectMessages(
|
|||||||
public suspend inline fun <reified T : MessageEvent> T.selectMessagesUnit(
|
public suspend inline fun <reified T : MessageEvent> T.selectMessagesUnit(
|
||||||
timeoutMillis: Long = -1,
|
timeoutMillis: Long = -1,
|
||||||
filterContext: Boolean = true,
|
filterContext: Boolean = true,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
@BuilderInference crossinline selectBuilder: @MessageDsl MessageSelectBuilderUnit<T, Unit>.() -> Unit
|
@BuilderInference crossinline selectBuilder: @MessageDsl MessageSelectBuilderUnit<T, Unit>.() -> Unit
|
||||||
): Unit = selectMessagesImpl(timeoutMillis, true, filterContext, priority, selectBuilder)
|
): Unit = selectMessagesImpl(timeoutMillis, true, filterContext, priority, selectBuilder)
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ public suspend inline fun <reified T : MessageEvent> T.selectMessagesUnit(
|
|||||||
public suspend inline fun <reified T : MessageEvent, R> T.selectMessages(
|
public suspend inline fun <reified T : MessageEvent, R> T.selectMessages(
|
||||||
timeoutMillis: Long = -1,
|
timeoutMillis: Long = -1,
|
||||||
filterContext: Boolean = true,
|
filterContext: Boolean = true,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
@BuilderInference
|
@BuilderInference
|
||||||
crossinline selectBuilder: @MessageDsl MessageSelectBuilder<T, R>.() -> Unit
|
crossinline selectBuilder: @MessageDsl MessageSelectBuilder<T, R>.() -> Unit
|
||||||
): R =
|
): R =
|
||||||
@ -436,7 +436,7 @@ internal suspend inline fun <reified T : MessageEvent, R> T.selectMessagesImpl(
|
|||||||
timeoutMillis: Long = -1,
|
timeoutMillis: Long = -1,
|
||||||
isUnit: Boolean,
|
isUnit: Boolean,
|
||||||
filterContext: Boolean = true,
|
filterContext: Boolean = true,
|
||||||
priority: Listener.EventPriority,
|
priority: EventPriority,
|
||||||
@BuilderInference
|
@BuilderInference
|
||||||
crossinline selectBuilder: @MessageDsl MessageSelectBuilderUnit<T, R>.() -> Unit
|
crossinline selectBuilder: @MessageDsl MessageSelectBuilderUnit<T, R>.() -> Unit
|
||||||
): R = withSilentTimeoutOrCoroutineScope(timeoutMillis) {
|
): R = withSilentTimeoutOrCoroutineScope(timeoutMillis) {
|
||||||
@ -486,7 +486,7 @@ internal suspend inline fun <reified T : MessageEvent, R> T.selectMessagesImpl(
|
|||||||
// we don't have any way to reduce duplication yet,
|
// we don't have any way to reduce duplication yet,
|
||||||
// until local functions are supported in inline functions
|
// until local functions are supported in inline functions
|
||||||
@Suppress("DuplicatedCode") val subscribeAlways = globalEventChannel().subscribeAlways<T>(
|
@Suppress("DuplicatedCode") val subscribeAlways = globalEventChannel().subscribeAlways<T>(
|
||||||
concurrency = Listener.ConcurrencyKind.LOCKED,
|
concurrency = ConcurrencyKind.LOCKED,
|
||||||
priority = priority
|
priority = priority
|
||||||
) { event ->
|
) { event ->
|
||||||
if (filterContext && !this.isContextIdenticalWith(this@selectMessagesImpl))
|
if (filterContext && !this.isContextIdenticalWith(this@selectMessagesImpl))
|
||||||
@ -538,7 +538,7 @@ internal suspend inline fun <reified T : MessageEvent, R> T.selectMessagesImpl(
|
|||||||
internal suspend inline fun <reified T : MessageEvent> T.whileSelectMessagesImpl(
|
internal suspend inline fun <reified T : MessageEvent> T.whileSelectMessagesImpl(
|
||||||
timeoutMillis: Long,
|
timeoutMillis: Long,
|
||||||
filterContext: Boolean,
|
filterContext: Boolean,
|
||||||
priority: Listener.EventPriority,
|
priority: EventPriority,
|
||||||
crossinline selectBuilder: @MessageDsl MessageSelectBuilder<T, Boolean>.() -> Unit
|
crossinline selectBuilder: @MessageDsl MessageSelectBuilder<T, Boolean>.() -> Unit
|
||||||
): Unit = withSilentTimeoutOrCoroutineScope(timeoutMillis) {
|
): Unit = withSilentTimeoutOrCoroutineScope(timeoutMillis) {
|
||||||
var deferred: CompletableDeferred<Boolean>? = CompletableDeferred()
|
var deferred: CompletableDeferred<Boolean>? = CompletableDeferred()
|
||||||
@ -568,7 +568,7 @@ internal suspend inline fun <reified T : MessageEvent> T.whileSelectMessagesImpl
|
|||||||
|
|
||||||
// ensure atomic completing
|
// ensure atomic completing
|
||||||
val subscribeAlways = globalEventChannel().subscribeAlways<T>(
|
val subscribeAlways = globalEventChannel().subscribeAlways<T>(
|
||||||
concurrency = Listener.ConcurrencyKind.LOCKED,
|
concurrency = ConcurrencyKind.LOCKED,
|
||||||
priority = priority
|
priority = priority
|
||||||
) { event ->
|
) { event ->
|
||||||
if (filterContext && !this.isContextIdenticalWith(this@whileSelectMessagesImpl))
|
if (filterContext && !this.isContextIdenticalWith(this@whileSelectMessagesImpl))
|
||||||
|
@ -16,7 +16,7 @@ package net.mamoe.mirai.event
|
|||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.contact.OtherClient
|
import net.mamoe.mirai.contact.OtherClient
|
||||||
import net.mamoe.mirai.contact.Stranger
|
import net.mamoe.mirai.contact.Stranger
|
||||||
import net.mamoe.mirai.event.Listener.ConcurrencyKind.CONCURRENT
|
import net.mamoe.mirai.event.ConcurrencyKind.CONCURRENT
|
||||||
import net.mamoe.mirai.event.events.*
|
import net.mamoe.mirai.event.events.*
|
||||||
import net.mamoe.mirai.message.data.content
|
import net.mamoe.mirai.message.data.content
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
@ -75,8 +75,8 @@ public typealias MessageEventSubscribersBuilder = MessageSubscribersBuilder<Mess
|
|||||||
*/
|
*/
|
||||||
public fun <R> EventChannel<*>.subscribeMessages(
|
public fun <R> EventChannel<*>.subscribeMessages(
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
concurrencyKind: Listener.ConcurrencyKind = CONCURRENT,
|
concurrencyKind: ConcurrencyKind = CONCURRENT,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
listeners: MessageEventSubscribersBuilder.() -> R
|
listeners: MessageEventSubscribersBuilder.() -> R
|
||||||
): R {
|
): R {
|
||||||
contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) }
|
contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) }
|
||||||
@ -93,8 +93,8 @@ public typealias GroupMessageSubscribersBuilder = MessageSubscribersBuilder<Grou
|
|||||||
*/
|
*/
|
||||||
public fun <R> EventChannel<*>.subscribeGroupMessages(
|
public fun <R> EventChannel<*>.subscribeGroupMessages(
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
concurrencyKind: Listener.ConcurrencyKind = CONCURRENT,
|
concurrencyKind: ConcurrencyKind = CONCURRENT,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
listeners: GroupMessageSubscribersBuilder.() -> R
|
listeners: GroupMessageSubscribersBuilder.() -> R
|
||||||
): R {
|
): R {
|
||||||
contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) }
|
contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) }
|
||||||
@ -111,8 +111,8 @@ public typealias FriendMessageSubscribersBuilder = MessageSubscribersBuilder<Fri
|
|||||||
*/
|
*/
|
||||||
public fun <R> EventChannel<*>.subscribeFriendMessages(
|
public fun <R> EventChannel<*>.subscribeFriendMessages(
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
concurrencyKind: Listener.ConcurrencyKind = CONCURRENT,
|
concurrencyKind: ConcurrencyKind = CONCURRENT,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
listeners: FriendMessageSubscribersBuilder.() -> R
|
listeners: FriendMessageSubscribersBuilder.() -> R
|
||||||
): R {
|
): R {
|
||||||
contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) }
|
contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) }
|
||||||
@ -129,8 +129,8 @@ public typealias TempMessageSubscribersBuilder = MessageSubscribersBuilder<TempM
|
|||||||
*/
|
*/
|
||||||
public fun <R> EventChannel<*>.subscribeTempMessages(
|
public fun <R> EventChannel<*>.subscribeTempMessages(
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
concurrencyKind: Listener.ConcurrencyKind = CONCURRENT,
|
concurrencyKind: ConcurrencyKind = CONCURRENT,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
listeners: TempMessageSubscribersBuilder.() -> R
|
listeners: TempMessageSubscribersBuilder.() -> R
|
||||||
): R {
|
): R {
|
||||||
contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) }
|
contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) }
|
||||||
@ -148,8 +148,8 @@ public typealias StrangerMessageSubscribersBuilder = MessageSubscribersBuilder<S
|
|||||||
*/
|
*/
|
||||||
public fun <R> EventChannel<*>.subscribeStrangerMessages(
|
public fun <R> EventChannel<*>.subscribeStrangerMessages(
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
concurrencyKind: Listener.ConcurrencyKind = CONCURRENT,
|
concurrencyKind: ConcurrencyKind = CONCURRENT,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
listeners: StrangerMessageSubscribersBuilder.() -> R
|
listeners: StrangerMessageSubscribersBuilder.() -> R
|
||||||
): R {
|
): R {
|
||||||
contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) }
|
contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) }
|
||||||
@ -168,8 +168,8 @@ public typealias OtherClientMessageSubscribersBuilder = MessageSubscribersBuilde
|
|||||||
*/
|
*/
|
||||||
public fun <R> EventChannel<*>.subscribeOtherClientMessages(
|
public fun <R> EventChannel<*>.subscribeOtherClientMessages(
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
concurrencyKind: Listener.ConcurrencyKind = CONCURRENT,
|
concurrencyKind: ConcurrencyKind = CONCURRENT,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
listeners: OtherClientMessageSubscribersBuilder.() -> R
|
listeners: OtherClientMessageSubscribersBuilder.() -> R
|
||||||
): R {
|
): R {
|
||||||
contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) }
|
contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) }
|
||||||
@ -185,8 +185,8 @@ private typealias MessageSubscriberBuilderConstructor<E> = (
|
|||||||
private inline fun <reified E : MessageEvent> EventChannel<*>.createBuilder(
|
private inline fun <reified E : MessageEvent> EventChannel<*>.createBuilder(
|
||||||
constructor: MessageSubscriberBuilderConstructor<E>,
|
constructor: MessageSubscriberBuilderConstructor<E>,
|
||||||
coroutineContext: CoroutineContext,
|
coroutineContext: CoroutineContext,
|
||||||
concurrencyKind: Listener.ConcurrencyKind,
|
concurrencyKind: ConcurrencyKind,
|
||||||
priority: Listener.EventPriority
|
priority: EventPriority
|
||||||
): MessageSubscribersBuilder<E, Listener<E>, Unit, Unit> = constructor(Unit) { filter, listener ->
|
): MessageSubscribersBuilder<E, Listener<E>, Unit, Unit> = constructor(Unit) { filter, listener ->
|
||||||
subscribeAlways(coroutineContext, concurrencyKind, priority) {
|
subscribeAlways(coroutineContext, concurrencyKind, priority) {
|
||||||
val toString = this.message.content
|
val toString = this.message.content
|
||||||
|
@ -34,7 +34,7 @@ import kotlin.reflect.KClass
|
|||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
public suspend inline fun <reified E : Event, R : Any> syncFromEvent(
|
public suspend inline fun <reified E : Event, R : Any> syncFromEvent(
|
||||||
timeoutMillis: Long = -1,
|
timeoutMillis: Long = -1,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
crossinline mapper: suspend E.(E) -> R?
|
crossinline mapper: suspend E.(E) -> R?
|
||||||
): R {
|
): R {
|
||||||
require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" }
|
require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" }
|
||||||
@ -67,7 +67,7 @@ public suspend inline fun <reified E : Event, R : Any> syncFromEvent(
|
|||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
public suspend inline fun <reified E : Event, R : Any> syncFromEventOrNull(
|
public suspend inline fun <reified E : Event, R : Any> syncFromEventOrNull(
|
||||||
timeoutMillis: Long,
|
timeoutMillis: Long,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
crossinline mapper: suspend E.(E) -> R?
|
crossinline mapper: suspend E.(E) -> R?
|
||||||
): R? {
|
): R? {
|
||||||
require(timeoutMillis > 0) { "timeoutMillis must be > 0" }
|
require(timeoutMillis > 0) { "timeoutMillis must be > 0" }
|
||||||
@ -96,7 +96,7 @@ public suspend inline fun <reified E : Event, R : Any> syncFromEventOrNull(
|
|||||||
public inline fun <reified E : Event, R : Any> CoroutineScope.asyncFromEventOrNull(
|
public inline fun <reified E : Event, R : Any> CoroutineScope.asyncFromEventOrNull(
|
||||||
timeoutMillis: Long,
|
timeoutMillis: Long,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
crossinline mapper: suspend E.(E) -> R?
|
crossinline mapper: suspend E.(E) -> R?
|
||||||
): Deferred<R?> {
|
): Deferred<R?> {
|
||||||
require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" }
|
require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" }
|
||||||
@ -125,7 +125,7 @@ public inline fun <reified E : Event, R : Any> CoroutineScope.asyncFromEventOrNu
|
|||||||
public inline fun <reified E : Event, R : Any> CoroutineScope.asyncFromEvent(
|
public inline fun <reified E : Event, R : Any> CoroutineScope.asyncFromEvent(
|
||||||
timeoutMillis: Long = -1,
|
timeoutMillis: Long = -1,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
crossinline mapper: suspend E.(E) -> R?
|
crossinline mapper: suspend E.(E) -> R?
|
||||||
): Deferred<R> {
|
): Deferred<R> {
|
||||||
require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" }
|
require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" }
|
||||||
@ -144,7 +144,7 @@ public inline fun <reified E : Event, R : Any> CoroutineScope.asyncFromEvent(
|
|||||||
internal suspend inline fun <E : Event, R> syncFromEventImpl(
|
internal suspend inline fun <E : Event, R> syncFromEventImpl(
|
||||||
eventClass: KClass<E>,
|
eventClass: KClass<E>,
|
||||||
coroutineScope: CoroutineScope,
|
coroutineScope: CoroutineScope,
|
||||||
priority: Listener.EventPriority,
|
priority: EventPriority,
|
||||||
crossinline mapper: suspend E.(E) -> R?
|
crossinline mapper: suspend E.(E) -> R?
|
||||||
): R = suspendCancellableCoroutine { cont ->
|
): R = suspendCancellableCoroutine { cont ->
|
||||||
coroutineScope.globalEventChannel().subscribe(eventClass, priority = priority) {
|
coroutineScope.globalEventChannel().subscribe(eventClass, priority = priority) {
|
||||||
|
@ -29,14 +29,14 @@ internal class Handler<in E : Event> internal constructor(
|
|||||||
parentJob: Job?,
|
parentJob: Job?,
|
||||||
subscriberContext: CoroutineContext,
|
subscriberContext: CoroutineContext,
|
||||||
@JvmField val handler: suspend (E) -> ListeningStatus,
|
@JvmField val handler: suspend (E) -> ListeningStatus,
|
||||||
override val concurrencyKind: Listener.ConcurrencyKind,
|
override val concurrencyKind: ConcurrencyKind,
|
||||||
override val priority: Listener.EventPriority
|
override val priority: EventPriority
|
||||||
) : Listener<E>, CompletableJob by SupervisorJob(parentJob) { // avoid being cancelled on handling event
|
) : Listener<E>, CompletableJob by SupervisorJob(parentJob) { // avoid being cancelled on handling event
|
||||||
|
|
||||||
private val subscriberContext: CoroutineContext = subscriberContext + this // override Job.
|
private val subscriberContext: CoroutineContext = subscriberContext + this // override Job.
|
||||||
|
|
||||||
val lock: Mutex? = when (concurrencyKind) {
|
val lock: Mutex? = when (concurrencyKind) {
|
||||||
Listener.ConcurrencyKind.LOCKED -> Mutex()
|
ConcurrencyKind.LOCKED -> Mutex()
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,14 +78,14 @@ internal object GlobalEventListeners {
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
val map =
|
val map =
|
||||||
EnumMap<Listener.EventPriority, ConcurrentLinkedQueue<ListenerRegistry>>(Listener.EventPriority::class.java)
|
EnumMap<EventPriority, ConcurrentLinkedQueue<ListenerRegistry>>(EventPriority::class.java)
|
||||||
EventPriority.values().forEach {
|
EventPriority.values().forEach {
|
||||||
map[it] = ConcurrentLinkedQueue()
|
map[it] = ConcurrentLinkedQueue()
|
||||||
}
|
}
|
||||||
ALL_LEVEL_REGISTRIES = map
|
ALL_LEVEL_REGISTRIES = map
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun get(priority: Listener.EventPriority): ConcurrentLinkedQueue<ListenerRegistry> =
|
operator fun get(priority: EventPriority): ConcurrentLinkedQueue<ListenerRegistry> =
|
||||||
ALL_LEVEL_REGISTRIES[priority]!!
|
ALL_LEVEL_REGISTRIES[priority]!!
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ internal inline fun <E, T : Iterable<E>> T.forEach0(block: T.(E) -> Unit) {
|
|||||||
internal suspend inline fun <E : AbstractEvent> callAndRemoveIfRequired(
|
internal suspend inline fun <E : AbstractEvent> callAndRemoveIfRequired(
|
||||||
event: E
|
event: E
|
||||||
) {
|
) {
|
||||||
for (p in Listener.EventPriority.prioritiesExcludedMonitor) {
|
for (p in EventPriority.prioritiesExcludedMonitor) {
|
||||||
GlobalEventListeners[p].forEach0 { registeredRegistry ->
|
GlobalEventListeners[p].forEach0 { registeredRegistry ->
|
||||||
if (event.isIntercepted) {
|
if (event.isIntercepted) {
|
||||||
return
|
return
|
||||||
@ -113,14 +113,14 @@ internal suspend inline fun <E : AbstractEvent> callAndRemoveIfRequired(
|
|||||||
if (!registeredRegistry.type.isInstance(event)) return@forEach0
|
if (!registeredRegistry.type.isInstance(event)) return@forEach0
|
||||||
val listener = registeredRegistry.listener
|
val listener = registeredRegistry.listener
|
||||||
when (listener.concurrencyKind) {
|
when (listener.concurrencyKind) {
|
||||||
Listener.ConcurrencyKind.LOCKED -> {
|
ConcurrencyKind.LOCKED -> {
|
||||||
(listener as Handler).lock!!.withLock {
|
(listener as Handler).lock!!.withLock {
|
||||||
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
||||||
remove(registeredRegistry)
|
remove(registeredRegistry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Listener.ConcurrencyKind.CONCURRENT -> {
|
ConcurrencyKind.CONCURRENT -> {
|
||||||
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
||||||
remove(registeredRegistry)
|
remove(registeredRegistry)
|
||||||
}
|
}
|
||||||
@ -137,14 +137,14 @@ internal suspend inline fun <E : AbstractEvent> callAndRemoveIfRequired(
|
|||||||
val listener = registeredRegistry.listener
|
val listener = registeredRegistry.listener
|
||||||
launch {
|
launch {
|
||||||
when (listener.concurrencyKind) {
|
when (listener.concurrencyKind) {
|
||||||
Listener.ConcurrencyKind.LOCKED -> {
|
ConcurrencyKind.LOCKED -> {
|
||||||
(listener as Handler).lock!!.withLock {
|
(listener as Handler).lock!!.withLock {
|
||||||
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
||||||
remove(registeredRegistry)
|
remove(registeredRegistry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Listener.ConcurrencyKind.CONCURRENT -> {
|
ConcurrencyKind.CONCURRENT -> {
|
||||||
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
||||||
remove(registeredRegistry)
|
remove(registeredRegistry)
|
||||||
}
|
}
|
||||||
|
@ -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 许可证的约束, 可以在以下链接找到该许可证.
|
* 此源代码的使用受 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.
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
@ -16,7 +16,6 @@ package net.mamoe.mirai.message
|
|||||||
import kotlinx.coroutines.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import net.mamoe.mirai.event.EventPriority
|
import net.mamoe.mirai.event.EventPriority
|
||||||
import net.mamoe.mirai.event.Listener
|
|
||||||
import net.mamoe.mirai.event.events.*
|
import net.mamoe.mirai.event.events.*
|
||||||
import net.mamoe.mirai.event.syncFromEvent
|
import net.mamoe.mirai.event.syncFromEvent
|
||||||
import net.mamoe.mirai.event.syncFromEventOrNull
|
import net.mamoe.mirai.event.syncFromEventOrNull
|
||||||
@ -46,7 +45,7 @@ public fun MessageEvent.isContextIdenticalWith(another: MessageEvent): Boolean {
|
|||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
public suspend inline fun <reified P : MessageEvent> P.nextMessage(
|
public suspend inline fun <reified P : MessageEvent> P.nextMessage(
|
||||||
timeoutMillis: Long = -1,
|
timeoutMillis: Long = -1,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
noinline filter: suspend P.(P) -> Boolean = { true }
|
noinline filter: suspend P.(P) -> Boolean = { true }
|
||||||
): MessageChain {
|
): MessageChain {
|
||||||
return syncFromEvent<P, P>(timeoutMillis, priority) {
|
return syncFromEvent<P, P>(timeoutMillis, priority) {
|
||||||
@ -68,7 +67,7 @@ public suspend inline fun <reified P : MessageEvent> P.nextMessage(
|
|||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
public suspend inline fun <reified P : MessageEvent> P.nextMessageOrNull(
|
public suspend inline fun <reified P : MessageEvent> P.nextMessageOrNull(
|
||||||
timeoutMillis: Long,
|
timeoutMillis: Long,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
noinline filter: suspend P.(P) -> Boolean = { true }
|
noinline filter: suspend P.(P) -> Boolean = { true }
|
||||||
): MessageChain? {
|
): MessageChain? {
|
||||||
require(timeoutMillis > 0) { "timeoutMillis must be > 0" }
|
require(timeoutMillis > 0) { "timeoutMillis must be > 0" }
|
||||||
@ -84,7 +83,7 @@ public suspend inline fun <reified P : MessageEvent> P.nextMessageOrNull(
|
|||||||
public inline fun <reified P : MessageEvent> P.nextMessageAsync(
|
public inline fun <reified P : MessageEvent> P.nextMessageAsync(
|
||||||
timeoutMillis: Long = -1,
|
timeoutMillis: Long = -1,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
noinline filter: suspend P.(P) -> Boolean = { true }
|
noinline filter: suspend P.(P) -> Boolean = { true }
|
||||||
): Deferred<MessageChain> {
|
): Deferred<MessageChain> {
|
||||||
return this.bot.async(coroutineContext) {
|
return this.bot.async(coroutineContext) {
|
||||||
@ -101,7 +100,7 @@ public inline fun <reified P : MessageEvent> P.nextMessageAsync(
|
|||||||
public inline fun <reified P : MessageEvent> P.nextMessageOrNullAsync(
|
public inline fun <reified P : MessageEvent> P.nextMessageOrNullAsync(
|
||||||
timeoutMillis: Long,
|
timeoutMillis: Long,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
priority: Listener.EventPriority = EventPriority.MONITOR,
|
priority: EventPriority = EventPriority.MONITOR,
|
||||||
noinline filter: suspend P.(P) -> Boolean = { true }
|
noinline filter: suspend P.(P) -> Boolean = { true }
|
||||||
): Deferred<MessageChain?> {
|
): Deferred<MessageChain?> {
|
||||||
require(timeoutMillis > 0) { "timeoutMillis must be > 0" }
|
require(timeoutMillis > 0) { "timeoutMillis must be > 0" }
|
||||||
|
@ -52,7 +52,7 @@ class EventTests {
|
|||||||
resetEventListeners()
|
resetEventListeners()
|
||||||
var listeners = 0
|
var listeners = 0
|
||||||
val counter = AtomicInteger(0)
|
val counter = AtomicInteger(0)
|
||||||
for (p in Listener.EventPriority.values()) {
|
for (p in EventPriority.values()) {
|
||||||
repeat(2333) {
|
repeat(2333) {
|
||||||
listeners++
|
listeners++
|
||||||
GlobalScope.globalEventChannel().subscribeAlways<ParentEvent> {
|
GlobalScope.globalEventChannel().subscribeAlways<ParentEvent> {
|
||||||
@ -78,7 +78,7 @@ class EventTests {
|
|||||||
val registered = AtomicInteger()
|
val registered = AtomicInteger()
|
||||||
coroutineScope {
|
coroutineScope {
|
||||||
println("Step 0")
|
println("Step 0")
|
||||||
for (priority in Listener.EventPriority.values()) {
|
for (priority in EventPriority.values()) {
|
||||||
launch {
|
launch {
|
||||||
repeat(5000) {
|
repeat(5000) {
|
||||||
registered.getAndIncrement()
|
registered.getAndIncrement()
|
||||||
@ -216,7 +216,7 @@ class EventTests {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
fun resetEventListeners() {
|
fun resetEventListeners() {
|
||||||
for (p in Listener.EventPriority.values()) {
|
for (p in EventPriority.values()) {
|
||||||
GlobalEventListeners[p].clear()
|
GlobalEventListeners[p].clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -278,11 +278,11 @@ class EventTests {
|
|||||||
step.step(1)
|
step.step(1)
|
||||||
ListeningStatus.LISTENING
|
ListeningStatus.LISTENING
|
||||||
}
|
}
|
||||||
subscribe<PriorityTestEvent>(priority = Listener.EventPriority.HIGH) {
|
subscribe<PriorityTestEvent>(priority = EventPriority.HIGH) {
|
||||||
step.step(0)
|
step.step(0)
|
||||||
ListeningStatus.LISTENING
|
ListeningStatus.LISTENING
|
||||||
}
|
}
|
||||||
subscribe<PriorityTestEvent>(priority = Listener.EventPriority.LOW) {
|
subscribe<PriorityTestEvent>(priority = EventPriority.LOW) {
|
||||||
step.step(3)
|
step.step(3)
|
||||||
ListeningStatus.LISTENING
|
ListeningStatus.LISTENING
|
||||||
}
|
}
|
||||||
|
@ -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 许可证的约束, 可以在以下链接找到该许可证.
|
* 此源代码的使用受 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.
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
@ -135,13 +135,13 @@ internal class JvmMethodEventsTest {
|
|||||||
fun getCalled() = called.get()
|
fun getCalled() = called.get()
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@EventHandler(Listener.EventPriority.HIGHEST)
|
@EventHandler(EventPriority.HIGHEST)
|
||||||
private suspend fun TestEvent.`suspend receiver param Unit`(event: TestEvent) {
|
private suspend fun TestEvent.`suspend receiver param Unit`(event: TestEvent) {
|
||||||
intercept()
|
intercept()
|
||||||
called.getAndIncrement()
|
called.getAndIncrement()
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(Listener.EventPriority.MONITOR)
|
@EventHandler(EventPriority.MONITOR)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
private fun TestEvent.`receiver param LS`(event: TestEvent): ListeningStatus {
|
private fun TestEvent.`receiver param LS`(event: TestEvent): ListeningStatus {
|
||||||
called.getAndIncrement()
|
called.getAndIncrement()
|
||||||
|
@ -24,7 +24,7 @@ import net.mamoe.mirai.Bot
|
|||||||
import net.mamoe.mirai.contact.ContactList
|
import net.mamoe.mirai.contact.ContactList
|
||||||
import net.mamoe.mirai.contact.OtherClient
|
import net.mamoe.mirai.contact.OtherClient
|
||||||
import net.mamoe.mirai.event.*
|
import net.mamoe.mirai.event.*
|
||||||
import net.mamoe.mirai.event.Listener.EventPriority.MONITOR
|
import net.mamoe.mirai.event.EventPriority.MONITOR
|
||||||
import net.mamoe.mirai.event.events.BotEvent
|
import net.mamoe.mirai.event.events.BotEvent
|
||||||
import net.mamoe.mirai.event.events.BotOfflineEvent
|
import net.mamoe.mirai.event.events.BotOfflineEvent
|
||||||
import net.mamoe.mirai.event.events.BotReloginEvent
|
import net.mamoe.mirai.event.events.BotReloginEvent
|
||||||
@ -94,7 +94,7 @@ internal abstract class AbstractBot<N : BotNetworkHandler> constructor(
|
|||||||
private val offlineListener: Listener<BotOfflineEvent> =
|
private val offlineListener: Listener<BotOfflineEvent> =
|
||||||
this@AbstractBot.eventChannel.subscribeAlways(
|
this@AbstractBot.eventChannel.subscribeAlways(
|
||||||
priority = MONITOR,
|
priority = MONITOR,
|
||||||
concurrency = Listener.ConcurrencyKind.LOCKED
|
concurrency = ConcurrencyKind.LOCKED
|
||||||
) { event ->
|
) { event ->
|
||||||
if (!event.bot.isActive) {
|
if (!event.bot.isActive) {
|
||||||
// bot closed
|
// bot closed
|
||||||
|
@ -479,7 +479,7 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
@Suppress("RemoveRedundantQualifierName")
|
@Suppress("RemoveRedundantQualifierName")
|
||||||
val listener = bot.eventChannel.subscribeAlways<BotReloginEvent>(priority = Listener.EventPriority.MONITOR) {
|
val listener = bot.eventChannel.subscribeAlways<BotReloginEvent>(priority = EventPriority.MONITOR) {
|
||||||
this@QQAndroidBotNetworkHandler.launch { syncMessageSvc() }
|
this@QQAndroidBotNetworkHandler.launch { syncMessageSvc() }
|
||||||
}
|
}
|
||||||
supervisor.invokeOnCompletion { listener.cancel() }
|
supervisor.invokeOnCompletion { listener.cancel() }
|
||||||
|
Loading…
Reference in New Issue
Block a user