Commit 9924d37e authored by Him188's avatar Him188

Misc improvements

parent 20af1fc3
...@@ -15,6 +15,7 @@ import kotlin.test.Test ...@@ -15,6 +15,7 @@ import kotlin.test.Test
import kotlin.test.assertFalse import kotlin.test.assertFalse
import kotlin.test.assertTrue import kotlin.test.assertTrue
/*
internal class AtomicResizeCacheListTest { internal class AtomicResizeCacheListTest {
@Test @Test
...@@ -38,4 +39,4 @@ internal class AtomicResizeCacheListTest { ...@@ -38,4 +39,4 @@ internal class AtomicResizeCacheListTest {
assertTrue { list.ensureNoDuplication(1) } assertTrue { list.ensureNoDuplication(1) }
} }
} }
} }*/
\ No newline at end of file \ No newline at end of file
...@@ -13,10 +13,12 @@ package net.mamoe.mirai.event ...@@ -13,10 +13,12 @@ package net.mamoe.mirai.event
import kotlinx.atomicfu.atomic import kotlinx.atomicfu.atomic
import net.mamoe.mirai.event.internal.broadcastInternal import net.mamoe.mirai.event.internal.broadcastInternal
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.PlannedRemoval import net.mamoe.mirai.utils.PlannedRemoval
import net.mamoe.mirai.utils.SinceMirai import net.mamoe.mirai.utils.SinceMirai
import kotlin.jvm.JvmSynthetic import kotlin.jvm.JvmSynthetic
import kotlin.jvm.Volatile
/** /**
* 可被监听的类, 可以是任何 class 或 object. * 可被监听的类, 可以是任何 class 或 object.
...@@ -34,6 +36,20 @@ import kotlin.jvm.JvmSynthetic ...@@ -34,6 +36,20 @@ import kotlin.jvm.JvmSynthetic
* @see [subscribe] 监听事件 * @see [subscribe] 监听事件
*/ */
interface Event { interface Event {
/**
* 事件是否已被拦截.
*
* 所有事件都可以被拦截, 拦截后低优先级的监听器将不会处理到这个事件.
*/
@SinceMirai("1.0.0")
val isIntercepted: Boolean
/**
* 拦截这个事件
*/
@SinceMirai("1.0.0")
fun intercept()
@Deprecated( @Deprecated(
""" """
...@@ -47,6 +63,8 @@ interface Event { ...@@ -47,6 +63,8 @@ interface Event {
/** /**
* 所有实现了 [Event] 接口的类都应该继承的父类. * 所有实现了 [Event] 接口的类都应该继承的父类.
*
* 在使用事件时应使用类型 [Event]. 在实现自定义事件时应继承 [AbstractEvent].
*/ */
@SinceMirai("1.0.0") @SinceMirai("1.0.0")
abstract class AbstractEvent : Event { abstract class AbstractEvent : Event {
...@@ -56,40 +74,20 @@ abstract class AbstractEvent : Event { ...@@ -56,40 +74,20 @@ abstract class AbstractEvent : Event {
final override val DoNotImplementThisClassButExtendAbstractEvent: Nothing final override val DoNotImplementThisClassButExtendAbstractEvent: Nothing
get() = throw Error("Shouldn't be reached") get() = throw Error("Shouldn't be reached")
@Volatile
private var _intercepted = false private var _intercepted = false
private val _cancelled = atomic(false) private val _cancelled = atomic(false)
/** // 实现 Event
* 事件是否已被拦截. override val isIntercepted: Boolean get() = _intercepted
*
* 所有事件都可以被拦截, 拦截后低优先级的监听器将不会处理到这个事件.
*/
@SinceMirai("1.0.0")
val isIntercepted: Boolean
get() = _intercepted
/**
* 拦截这个事件.
* 重复拦截时不会抛出异常.
*/
@SinceMirai("1.0.0") @SinceMirai("1.0.0")
fun intercept() { override fun intercept() {
_intercepted = true _intercepted = true
} }
// 实现 CancellableEvent
/**
* 事件是否已取消.
*
* 事件需实现 [CancellableEvent] 接口才可以被取消,
* 否则此属性固定返回 false.
*/
val isCancelled: Boolean get() = _cancelled.value val isCancelled: Boolean get() = _cancelled.value
/**
* 取消这个事件.
* 重复取消时不会抛出异常.
*/
fun cancel() { fun cancel() {
check(this is CancellableEvent) { check(this is CancellableEvent) {
"Event $this is not cancellable" "Event $this is not cancellable"
...@@ -103,12 +101,18 @@ abstract class AbstractEvent : Event { ...@@ -103,12 +101,18 @@ abstract class AbstractEvent : Event {
*/ */
interface CancellableEvent : Event { interface CancellableEvent : Event {
/** /**
* 事件是否已取消. * 事件是否已被取消.
*
* 事件需实现 [CancellableEvent] 接口才可以被取消,
* 否则此属性固定返回 false.
*/ */
val isCancelled: Boolean val isCancelled: Boolean
/** /**
* 取消这个事件. * 取消这个事件.
* 事件需实现 [CancellableEvent] 接口才可以被取消
*
* @throws IllegalStateException 当事件未实现接口 [CancellableEvent] 时抛出
*/ */
fun cancel() fun cancel()
} }
...@@ -128,6 +132,7 @@ suspend fun <E : Event> E.broadcast(): E = apply { ...@@ -128,6 +132,7 @@ suspend fun <E : Event> E.broadcast(): E = apply {
* 设置为 `true` 以关闭事件. * 设置为 `true` 以关闭事件.
* 所有的 `subscribe` 都能正常添加到监听器列表, 但所有的广播都会直接返回. * 所有的 `subscribe` 都能正常添加到监听器列表, 但所有的广播都会直接返回.
*/ */
@MiraiExperimentalAPI
var EventDisabled = false var EventDisabled = false
/** /**
......
...@@ -14,14 +14,17 @@ import kotlinx.coroutines.* ...@@ -14,14 +14,17 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import net.mamoe.mirai.event.* import net.mamoe.mirai.event.*
import net.mamoe.mirai.utils.* import net.mamoe.mirai.event.events.BotEvent
import net.mamoe.mirai.utils.LockFreeLinkedList
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.MiraiLogger
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext import kotlin.coroutines.coroutineContext
import kotlin.jvm.JvmField import kotlin.jvm.JvmField
import kotlin.reflect.KClass import kotlin.reflect.KClass
@PublishedApi
internal fun <L : Listener<E>, E : Event> KClass<out E>.subscribeInternal(listener: L): L { internal fun <L : Listener<E>, E : Event> KClass<out E>.subscribeInternal(listener: L): L {
with(GlobalEventListeners[listener.priority]) { with(GlobalEventListeners[listener.priority]) {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
...@@ -37,7 +40,6 @@ internal fun <L : Listener<E>, E : Event> KClass<out E>.subscribeInternal(listen ...@@ -37,7 +40,6 @@ internal fun <L : Listener<E>, E : Event> KClass<out E>.subscribeInternal(listen
} }
@PublishedApi
@Suppress("FunctionName") @Suppress("FunctionName")
internal fun <E : Event> CoroutineScope.Handler( internal fun <E : Event> CoroutineScope.Handler(
coroutineContext: CoroutineContext, coroutineContext: CoroutineContext,
...@@ -53,9 +55,7 @@ internal fun <E : Event> CoroutineScope.Handler( ...@@ -53,9 +55,7 @@ internal fun <E : Event> CoroutineScope.Handler(
/** /**
* 事件处理器. * 事件处理器.
*/ */
@PublishedApi internal class Handler<in E : Event> internal constructor(
internal class Handler<in E : Event>
@PublishedApi internal constructor(
parentJob: Job?, parentJob: Job?,
subscriberContext: CoroutineContext, subscriberContext: CoroutineContext,
@JvmField val handler: suspend (E) -> ListeningStatus, @JvmField val handler: suspend (E) -> ListeningStatus,
...@@ -65,8 +65,6 @@ internal class Handler<in E : Event> ...@@ -65,8 +65,6 @@ internal class Handler<in E : Event>
private val subscriberContext: CoroutineContext = subscriberContext + this // override Job. private val subscriberContext: CoroutineContext = subscriberContext + this // override Job.
@MiraiInternalAPI
val lock: Mutex? = when (concurrencyKind) { val lock: Mutex? = when (concurrencyKind) {
Listener.ConcurrencyKind.LOCKED -> Mutex() Listener.ConcurrencyKind.LOCKED -> Mutex()
else -> null else -> null
...@@ -84,7 +82,8 @@ internal class Handler<in E : Event> ...@@ -84,7 +82,8 @@ internal class Handler<in E : Event>
?: coroutineContext[CoroutineExceptionHandler]?.handleException(subscriberContext, e) ?: coroutineContext[CoroutineExceptionHandler]?.handleException(subscriberContext, e)
?: kotlin.run { ?: kotlin.run {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
MiraiLogger.warning( (if (event is BotEvent) event.bot.logger else MiraiLogger)
.warning(
"""Event processing: An exception occurred but no CoroutineExceptionHandler found, """Event processing: An exception occurred but no CoroutineExceptionHandler found,
either in coroutineContext from Handler job, or in subscriberContext""".trimIndent(), e either in coroutineContext from Handler job, or in subscriberContext""".trimIndent(), e
) )
...@@ -102,6 +101,7 @@ internal class ListenerNode( ...@@ -102,6 +101,7 @@ internal class ListenerNode(
val listener: Listener<Event>, val listener: Listener<Event>,
val owner: KClass<out Event> val owner: KClass<out Event>
) )
internal expect object GlobalEventListeners { internal expect object GlobalEventListeners {
operator fun get(priority: Listener.EventPriority): LockFreeLinkedList<ListenerNode> operator fun get(priority: Listener.EventPriority): LockFreeLinkedList<ListenerNode>
} }
...@@ -116,20 +116,21 @@ internal expect class MiraiAtomicBoolean(initial: Boolean) { ...@@ -116,20 +116,21 @@ internal expect class MiraiAtomicBoolean(initial: Boolean) {
// inline: NO extra Continuation // inline: NO extra Continuation
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
internal suspend inline fun Event.broadcastInternal() = coroutineScope { internal suspend inline fun Event.broadcastInternal() {
if (EventDisabled) return@coroutineScope @OptIn(MiraiExperimentalAPI::class)
if (EventDisabled) return
callAndRemoveIfRequired(this@broadcastInternal as? AbstractEvent ?: error("Events must extends AbstractEvent")) callAndRemoveIfRequired(this@broadcastInternal as? AbstractEvent ?: error("Events must extends AbstractEvent"))
} }
@Suppress("DuplicatedCode")
@OptIn(MiraiInternalAPI::class) @OptIn(MiraiInternalAPI::class)
private suspend fun <E : AbstractEvent> callAndRemoveIfRequired( internal suspend fun <E : AbstractEvent> callAndRemoveIfRequired(
event: E event: E
) { ) {
coroutineScope { for (p in Listener.EventPriority.valuesExceptMonitor) {
for (p in Listener.EventPriority.values()) {
GlobalEventListeners[p].forEachNode { eventNode -> GlobalEventListeners[p].forEachNode { eventNode ->
if (event.isIntercepted) { if (event.isIntercepted) {
return@coroutineScope return
} }
val node = eventNode.nodeValue val node = eventNode.nodeValue
if (!node.owner.isInstance(event)) return@forEachNode if (!node.owner.isInstance(event)) return@forEachNode
...@@ -137,30 +138,39 @@ private suspend fun <E : AbstractEvent> callAndRemoveIfRequired( ...@@ -137,30 +138,39 @@ private suspend fun <E : AbstractEvent> callAndRemoveIfRequired(
when (listener.concurrencyKind) { when (listener.concurrencyKind) {
Listener.ConcurrencyKind.LOCKED -> { Listener.ConcurrencyKind.LOCKED -> {
(listener as Handler).lock!!.withLock { (listener as Handler).lock!!.withLock {
kotlin.runCatching { if (listener.onEvent(event) == ListeningStatus.STOPPED) {
when (listener.onEvent(event)) {
ListeningStatus.STOPPED -> {
removeNode(eventNode) removeNode(eventNode)
} }
else -> {
} }
} }
}.onFailure { Listener.ConcurrencyKind.CONCURRENT -> {
// TODO("Exception catching") if (listener.onEvent(event) == ListeningStatus.STOPPED) {
removeNode(eventNode)
} }
} }
} }
Listener.ConcurrencyKind.CONCURRENT -> { }
kotlin.runCatching { }
when (listener.onEvent(event)) { coroutineScope {
ListeningStatus.STOPPED -> { GlobalEventListeners[Listener.EventPriority.MONITOR].forEachNode { eventNode ->
if (event.isIntercepted) {
return@coroutineScope
}
val node = eventNode.nodeValue
if (!node.owner.isInstance(event)) return@forEachNode
val listener = node.listener
launch {
when (listener.concurrencyKind) {
Listener.ConcurrencyKind.LOCKED -> {
(listener as Handler).lock!!.withLock {
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
removeNode(eventNode) removeNode(eventNode)
} }
else -> {
} }
} }
}.onFailure { Listener.ConcurrencyKind.CONCURRENT -> {
// TODO("Exception catching") if (listener.onEvent(event) == ListeningStatus.STOPPED) {
removeNode(eventNode)
} }
} }
} }
......
...@@ -7,22 +7,28 @@ ...@@ -7,22 +7,28 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE * https://github.com/mamoe/mirai/blob/master/LICENSE
*/ */
@file:Suppress("unused")
package net.mamoe.mirai.event package net.mamoe.mirai.event
import kotlinx.coroutines.CompletableJob import kotlinx.coroutines.CompletableJob
import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.Job
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.EventPriority.*
import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.event.events.BotEvent
import net.mamoe.mirai.event.internal.Handler import net.mamoe.mirai.event.internal.Handler
import net.mamoe.mirai.event.internal.subscribeInternal import net.mamoe.mirai.event.internal.subscribeInternal
import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.PlannedRemoval
import net.mamoe.mirai.utils.SinceMirai import net.mamoe.mirai.utils.SinceMirai
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.EmptyCoroutineContext
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
import kotlin.jvm.JvmStatic
import kotlin.jvm.JvmSynthetic import kotlin.jvm.JvmSynthetic
import kotlin.reflect.KClass import kotlin.reflect.KClass
...@@ -40,7 +46,12 @@ enum class ListeningStatus { ...@@ -40,7 +46,12 @@ enum class ListeningStatus {
LISTENING, LISTENING,
/** /**
* 表示已停止 * 表示已停止.
*
* - 若监听器使用 [Listener.ConcurrencyKind.LOCKED],
* 在这之后监听器将会被从监听器列表中删除, 因此不再能接收到事件.
* - 若使用 [Listener.ConcurrencyKind.CONCURRENT],
* 在这之后无法保证立即停止监听.
*/ */
STOPPED STOPPED
} }
...@@ -70,15 +81,45 @@ interface Listener<in E : Event> : CompletableJob { ...@@ -70,15 +81,45 @@ interface Listener<in E : Event> : CompletableJob {
*/ */
val concurrencyKind: ConcurrencyKind val concurrencyKind: ConcurrencyKind
/**
* 事件优先级.
*
* 在广播时, 事件监听器的调用顺序为 (从左到右):
* `[HIGHEST]` -> `[HIGH]` -> `[NORMAL]` -> `[LOW]` -> `[LOWEST]` -> `[MONITOR]`
*
* - 使用 [MONITOR] 优先级的监听器将会被**并行**调用.
* - 使用其他优先级的监听器都将会**按顺序**调用.
* 因此一个监听器的挂起可以阻塞事件处理过程而导致低优先级的监听器较晚处理.
*/
@SinceMirai("1.0.0")
enum class EventPriority { enum class EventPriority {
MONITOR, HIGHEST, HIGH, NORMAL, LOW, LOWEST
HIGHEST, HIGH, NORMAL, LOW, LOWEST,
/**
* 最低的优先级.
*
* 只监听事件而不拦截事件的监听器应使用此监听器.
*/
MONITOR;
companion object {
@JvmStatic
internal val valuesExceptMonitor: Array<EventPriority> = arrayOf(HIGHEST, HIGH, NORMAL, LOW, LOWEST)
}
} }
val priority: EventPriority get() = EventPriority.NORMAL /**
* 事件优先级
* @see [EventPriority]
*/
val priority: EventPriority get() = NORMAL
/**
* 这个方法将会调用 [subscribe] 时提供的参数 `noinline handler: suspend E.(E) -> ListeningStatus`.
* 并捕捉其异常.
*/
suspend fun onEvent(event: E): ListeningStatus suspend fun onEvent(event: E): ListeningStatus
} }
// region 顶层方法 创建当前 coroutineContext 下的子 Job // region 顶层方法 创建当前 coroutineContext 下的子 Job
...@@ -87,50 +128,59 @@ interface Listener<in E : Event> : CompletableJob { ...@@ -87,50 +128,59 @@ interface Listener<in E : Event> : CompletableJob {
* 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. * 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件.
* 每当 [事件广播][Event.broadcast] 时, [handler] 都会被执行. * 每当 [事件广播][Event.broadcast] 时, [handler] 都会被执行.
* *
* 当 [handler] 返回 [ListeningStatus.STOPPED] 时停止监听.
* 或 [Listener.complete] 后结束.
*
* 这个函数返回 [Listener], 它是一个 [CompletableJob]. 请注意它除非被 [Listener.complete] 或 [Listener.cancel], 则不会完成.
* 例:
* ```kotlin
* runBlocking { // this: CoroutineScope
* subscribe<Event> { /* 一些处理 */ } // 返回 Listener, 即 CompletableJob
* }
* foo()
* ```
* `runBlocking` 不会结束, 也就是下一行 `foo()` 不会被执行. 直到监听时创建的 `Listener` 被停止.
* *
* ### 创建监听
* *
* #### 单个 [Bot] 的事件监听
* 要创建一个仅在某个机器人在线时的监听, 请在 [Bot] 下调用本函数 (因为 [Bot] 也实现 [CoroutineScope]). * 要创建一个仅在某个机器人在线时的监听, 请在 [Bot] 下调用本函数 (因为 [Bot] 也实现 [CoroutineScope]).
* 这种方式创建的监听会自动筛选 [Bot]. * 这种方式创建的监听会自动筛选 [Bot].
* ```kotlin * ```
* bot1.subscribe<BotEvent> { /* 只会处理来自 bot1 的事件 */ } * bot1.subscribe<BotEvent> { /* 只会处理来自 bot1 的事件 */ }
* ``` * ```
* *
* * #### 全局范围监听
* 要创建一个全局都存在的监听(不推荐), 即守护协程, 请在 [GlobalScope] 调用本函数: * 要创建一个全局都存在的监听(不推荐), 请使用除 [Bot] 外的任意 [协程作用域][CoroutineScope] 调用本函数:
* ```kotlin * ```
* GlobalScope.subscribe<Event> { /* 会收到来自全部 Bot 的事件和与 Bot 不相关的事件 */ } * GlobalScope.subscribe<Event> { /* 会收到来自全部 Bot 的事件和与 Bot 不相关的事件 */ }
* ``` * ```
* *
* *
* ### 异常处理
* 事件处理时的 [CoroutineContext] 为调用本函数时的 [receiver][this] [CoroutineScope.coroutineContext]. * 事件处理时的 [CoroutineContext] 为调用本函数时的 [receiver][this] [CoroutineScope.coroutineContext].
* 因此: * 因此:
* - 事件处理时抛出的异常将会在 [this] [CoroutineExceptionHandler] 中处理 * - 当参数 [handler] 处理抛出异常时, 将会按如下顺序寻找 [CoroutineExceptionHandler] 处理异常:
* [this] 没有 [CoroutineExceptionHandler], 则在事件广播方的 [CoroutineExceptionHandler] 处理 * 1. 参数 [coroutineContext]
* 若均找不到, 则会触发 logger warning. * 2. 接收者 [this] [CoroutineScope.coroutineContext]
* 3. [Event.broadcast] 调用者的 [coroutineContext]
* 4. 若事件为 [BotEvent], 则从 [BotEvent.bot] 获取到 [Bot], 进而在 [Bot.coroutineContext] 中寻找
* 5. 若以上四个步骤均无法获取 [CoroutineExceptionHandler], 则使用 [MiraiLogger.Companion] 通过日志记录. 但这种情况理论上不应发生.
* - 事件处理时抛出异常不会停止监听器. * - 事件处理时抛出异常不会停止监听器.
* - 建议在事件处理中 ( [handler] ) 处理异常, * - 建议在事件处理中 ( [handler] ) 处理异常,
* 或在 [this] [CoroutineScope.coroutineContext] 中添加 [CoroutineExceptionHandler]. * 或在参数 [coroutineContext] 中添加 [CoroutineExceptionHandler].
*
*
* ### 停止监听
* [handler] 返回 [ListeningStatus.STOPPED] 时停止监听.
* [Listener.complete] 后结束.
*
* 这个函数返回 [Listener], 它是一个 [CompletableJob]. 它会成为 [CoroutineScope] 的一个 [子任务][Job]
* :
* ```
* runBlocking { // this: CoroutineScope
* subscribe<Event> { /* 一些处理 */ } // 返回 Listener, 即 CompletableJob
* }
* foo()
* ```
* `runBlocking` 不会结束, 也就是下一行 `foo()` 不会被执行. 直到监听时创建的 `Listener` 被停止.
* *
* *
* **注意:** 事件处理是 `suspend` , 请规范处理 JVM 阻塞方法.
* *
* @param coroutineContext 给事件监听协程的额外的 [CoroutineContext]. * @param coroutineContext 给事件监听协程的额外的 [CoroutineContext].
* @param concurrency 并发类型. 查看 [Listener.ConcurrencyKind] * @param concurrency 并发类型. 查看 [Listener.ConcurrencyKind]
* @param priority 监听优先级,优先级越高越先执行 * @param priority 监听优先级,优先级越高越先执行
* @param handler 事件处理器. 在接收到事件时会调用这个处理器. 其返回值意义参考 [ListeningStatus]. 其异常处理参考上文
* *
* @see syncFromEvent 监听一个事件, 并尝试从这个事件中获取一个值. * @see syncFromEvent 挂起当前协程, 监听一个事件, 并尝试从这个事件中**同步**一个值
* @see asyncFromEvent 异步监听一个事件, 并尝试从这个事件中获取一个值. * @see asyncFromEvent 异步监听一个事件, 并尝试从这个事件中获取一个值.
* *
* @see selectMessages `when` 的语法 '选择' 即将到来的一条消息. * @see selectMessages `when` 的语法 '选择' 即将到来的一条消息.
...@@ -142,15 +192,18 @@ interface Listener<in E : Event> : CompletableJob { ...@@ -142,15 +192,18 @@ interface Listener<in E : Event> : CompletableJob {
* @see subscribeMessages 监听消息 DSL * @see subscribeMessages 监听消息 DSL
* @see subscribeGroupMessages 监听群消息 DSL * @see subscribeGroupMessages 监听群消息 DSL
* @see subscribeFriendMessages 监听好友消息 DSL * @see subscribeFriendMessages 监听好友消息 DSL
* @see subscribeTempMessages 监听临时会话消息 DSL
*/ */
inline fun <reified E : Event> CoroutineScope.subscribe( inline fun <reified E : Event> CoroutineScope.subscribe(
coroutineContext: CoroutineContext = EmptyCoroutineContext, coroutineContext: CoroutineContext = EmptyCoroutineContext,
concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED, concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED,
priority: Listener.EventPriority = Listener.EventPriority.NORMAL, priority: Listener.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)
/** /**
* 与 [subscribe] 的区别是接受 [eventClass] 参数, 而不使用 `reified` 泛型
*
* @see CoroutineScope.subscribe * @see CoroutineScope.subscribe
*/ */
@SinceMirai("0.38.0") @SinceMirai("0.38.0")
...@@ -158,7 +211,7 @@ fun <E : Event> CoroutineScope.subscribe( ...@@ -158,7 +211,7 @@ fun <E : Event> CoroutineScope.subscribe(
eventClass: KClass<E>, eventClass: KClass<E>,
coroutineContext: CoroutineContext = EmptyCoroutineContext, coroutineContext: CoroutineContext = EmptyCoroutineContext,
concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED, concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED,
priority: Listener.EventPriority = Listener.EventPriority.NORMAL, priority: Listener.EventPriority = NORMAL,
handler: suspend E.(E) -> ListeningStatus handler: suspend E.(E) -> ListeningStatus
): Listener<E> = eventClass.subscribeInternal(Handler(coroutineContext, concurrency, priority) { it.handler(it); }) ): Listener<E> = eventClass.subscribeInternal(Handler(coroutineContext, concurrency, priority) { it.handler(it); })
...@@ -167,7 +220,7 @@ fun <E : Event> CoroutineScope.subscribe( ...@@ -167,7 +220,7 @@ fun <E : Event> CoroutineScope.subscribe(
* 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行. * 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行.
* *
* 可在任意时候通过 [Listener.complete] 来主动停止监听. * 可在任意时候通过 [Listener.complete] 来主动停止监听.
* [Bot] 被关闭后事件监听会被 [取消][Listener.cancel]. * [CoroutineScope] 被关闭后事件监听会被 [取消][Listener.cancel].
* *
* @param coroutineContext 给事件监听协程的额外的 [CoroutineContext] * @param coroutineContext 给事件监听协程的额外的 [CoroutineContext]
* @param priority 处理优先级, 优先级高的先执行 * @param priority 处理优先级, 优先级高的先执行
...@@ -177,7 +230,7 @@ fun <E : Event> CoroutineScope.subscribe( ...@@ -177,7 +230,7 @@ fun <E : Event> CoroutineScope.subscribe(
inline fun <reified E : Event> CoroutineScope.subscribeAlways( inline fun <reified E : Event> CoroutineScope.subscribeAlways(
coroutineContext: CoroutineContext = EmptyCoroutineContext, coroutineContext: CoroutineContext = EmptyCoroutineContext,
concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED, concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED,
priority: Listener.EventPriority = Listener.EventPriority.NORMAL, priority: Listener.EventPriority = NORMAL,
noinline listener: suspend E.(E) -> Unit noinline listener: suspend E.(E) -> Unit
): Listener<E> = subscribeAlways(E::class, coroutineContext, concurrency, priority, listener) ): Listener<E> = subscribeAlways(E::class, coroutineContext, concurrency, priority, listener)
...@@ -190,7 +243,7 @@ fun <E : Event> CoroutineScope.subscribeAlways( ...@@ -190,7 +243,7 @@ fun <E : Event> CoroutineScope.subscribeAlways(
eventClass: KClass<E>, eventClass: KClass<E>,
coroutineContext: CoroutineContext = EmptyCoroutineContext, coroutineContext: CoroutineContext = EmptyCoroutineContext,
concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED, concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED,
priority: Listener.EventPriority = Listener.EventPriority.NORMAL, priority: Listener.EventPriority = NORMAL,
listener: suspend E.(E) -> Unit listener: suspend E.(E) -> Unit
): Listener<E> = eventClass.subscribeInternal( ): Listener<E> = eventClass.subscribeInternal(
Handler(coroutineContext, concurrency, priority) { it.listener(it); ListeningStatus.LISTENING } Handler(coroutineContext, concurrency, priority) { it.listener(it); ListeningStatus.LISTENING }
...@@ -201,7 +254,7 @@ fun <E : Event> CoroutineScope.subscribeAlways( ...@@ -201,7 +254,7 @@ fun <E : Event> CoroutineScope.subscribeAlways(
* 仅在第一次 [事件广播][Event.broadcast] 时, [listener] 会被执行. * 仅在第一次 [事件广播][Event.broadcast] 时, [listener] 会被执行.
* *
* 可在任意时候通过 [Listener.complete] 来主动停止监听. * 可在任意时候通过 [Listener.complete] 来主动停止监听.
* [Bot] 被关闭后事件监听会被 [取消][Listener.cancel]. * [CoroutineScope] 被关闭后事件监听会被 [取消][Listener.cancel].
* *
* @param coroutineContext 给事件监听协程的额外的 [CoroutineContext] * @param coroutineContext 给事件监听协程的额外的 [CoroutineContext]
* @param priority 处理优先级, 优先级高的先执行 * @param priority 处理优先级, 优先级高的先执行
...@@ -211,7 +264,7 @@ fun <E : Event> CoroutineScope.subscribeAlways( ...@@ -211,7 +264,7 @@ fun <E : Event> CoroutineScope.subscribeAlways(
@JvmSynthetic @JvmSynthetic
inline fun <reified E : Event> CoroutineScope.subscribeOnce( inline fun <reified E : Event> CoroutineScope.subscribeOnce(
coroutineContext: CoroutineContext = EmptyCoroutineContext, coroutineContext: CoroutineContext = EmptyCoroutineContext,
priority: Listener.EventPriority = Listener.EventPriority.NORMAL, priority: Listener.EventPriority = NORMAL,
noinline listener: suspend E.(E) -> Unit noinline listener: suspend E.(E) -> Unit
): Listener<E> = subscribeOnce(E::class, coroutineContext, priority, listener) ): Listener<E> = subscribeOnce(E::class, coroutineContext, priority, listener)
...@@ -222,7 +275,7 @@ inline fun <reified E : Event> CoroutineScope.subscribeOnce( ...@@ -222,7 +275,7 @@ inline fun <reified E : Event> CoroutineScope.subscribeOnce(
fun <E : Event> CoroutineScope.subscribeOnce( fun <E : Event> CoroutineScope.subscribeOnce(
eventClass: KClass<E>, eventClass: KClass<E>,
coroutineContext: CoroutineContext = EmptyCoroutineContext, coroutineContext: CoroutineContext = EmptyCoroutineContext,
priority: Listener.EventPriority = Listener.EventPriority.NORMAL, priority: Listener.EventPriority = NORMAL,
listener: suspend E.(E) -> Unit listener: suspend E.(E) -> Unit
): Listener<E> = eventClass.subscribeInternal( ): Listener<E> = eventClass.subscribeInternal(
Handler(coroutineContext, Listener.ConcurrencyKind.LOCKED, priority) { it.listener(it); ListeningStatus.STOPPED } Handler(coroutineContext, Listener.ConcurrencyKind.LOCKED, priority) { it.listener(it); ListeningStatus.STOPPED }
...@@ -234,17 +287,10 @@ fun <E : Event> CoroutineScope.subscribeOnce( ...@@ -234,17 +287,10 @@ fun <E : Event> CoroutineScope.subscribeOnce(
/** /**
* 在 [Bot] 的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. * **注意:** 与 [CoroutineScope.subscribe] 不同的是,
* 每当 [事件广播][Event.broadcast] 时, [handler] 都会被执行, * [Bot.subscribe] 会筛选事件来源 [Bot], 只监听来自 [this] 的事件.
* 当 [handler] 返回 [ListeningStatus.STOPPED] 时停止监听
* *
* 可在任意时候通过 [Listener.complete] 来主动停止监听. * @see CoroutineScope.subscribe 获取更多说明
* [Bot] 被关闭后事件监听会被 [取消][Listener.cancel].
*
* @param coroutineContext 给事件监听协程的额外的 [CoroutineContext]
* @param priority 事件优先级, 优先级高的先处理
*
* @see subscribe 获取更多说明
*/ */
@JvmSynthetic @JvmSynthetic
@JvmName("subscribeAlwaysForBot") @JvmName("subscribeAlwaysForBot")
...@@ -252,11 +298,14 @@ fun <E : Event> CoroutineScope.subscribeOnce( ...@@ -252,11 +298,14 @@ fun <E : Event> CoroutineScope.subscribeOnce(
inline fun <reified E : BotEvent> Bot.subscribe( inline fun <reified E : BotEvent> Bot.subscribe(
coroutineContext: CoroutineContext = EmptyCoroutineContext, coroutineContext: CoroutineContext = EmptyCoroutineContext,
concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED, concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED,
priority: Listener.EventPriority = Listener.EventPriority.NORMAL, priority: Listener.EventPriority = NORMAL,
noinline handler: suspend E.(E) -> ListeningStatus noinline handler: suspend E.(E) -> ListeningStatus
): Listener<E> = this.subscribe(E::class, coroutineContext, concurrency, priority, handler) ): Listener<E> = this.subscribe(E::class, coroutineContext, concurrency, priority, handler)
/** /**
* **注意:** 与 [CoroutineScope.subscribe] 不同的是,
* [Bot.subscribe] 会筛选事件来源 [Bot], 只监听来自 [this] 的事件.
*
* @see Bot.subscribe * @see Bot.subscribe
*/ */
@SinceMirai("0.38.0") @SinceMirai("0.38.0")
...@@ -264,7 +313,7 @@ fun <E : BotEvent> Bot.subscribe( ...@@ -264,7 +313,7 @@ fun <E : BotEvent> Bot.subscribe(
eventClass: KClass<E>, eventClass: KClass<E>,
coroutineContext: CoroutineContext = EmptyCoroutineContext, coroutineContext: CoroutineContext = EmptyCoroutineContext,
concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED, concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED,
priority: Listener.EventPriority = Listener.EventPriority.NORMAL, priority: Listener.EventPriority = NORMAL,
handler: suspend E.(E) -> ListeningStatus handler: suspend E.(E) -> ListeningStatus
): Listener<E> = eventClass.subscribeInternal( ): Listener<E> = eventClass.subscribeInternal(
Handler( Handler(
...@@ -275,16 +324,10 @@ fun <E : BotEvent> Bot.subscribe( ...@@ -275,16 +324,10 @@ fun <E : BotEvent> Bot.subscribe(
) )
/** /**
* 在 [Bot] 的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. * **注意:** 与 [CoroutineScope.subscribe] 不同的是,
* 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行. * [Bot.subscribe] 会筛选事件来源 [Bot], 只监听来自 [this] 的事件.
* *
* 可在任意时候通过 [Listener.complete] 来主动停止监听. * @see CoroutineScope.subscribeAlways 获取更多说明
* [Bot] 被关闭后事件监听会被 [取消][Listener.cancel].
*
* @param coroutineContext 给事件监听协程的额外的 [CoroutineContext]
* @param priority 事件优先级, 优先级高的先处理
*
* @see subscribe 获取更多说明
*/ */
@JvmSynthetic @JvmSynthetic
@JvmName("subscribeAlwaysForBot1") @JvmName("subscribeAlwaysForBot1")
...@@ -292,11 +335,14 @@ fun <E : BotEvent> Bot.subscribe( ...@@ -292,11 +335,14 @@ fun <E : BotEvent> Bot.subscribe(
inline fun <reified E : BotEvent> Bot.subscribeAlways( inline fun <reified E : BotEvent> Bot.subscribeAlways(
coroutineContext: CoroutineContext = EmptyCoroutineContext, coroutineContext: CoroutineContext = EmptyCoroutineContext,
concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT,
priority: Listener.EventPriority = Listener.EventPriority.NORMAL, priority: Listener.EventPriority = NORMAL,
noinline listener: suspend E.(E) -> Unit noinline listener: suspend E.(E) -> Unit
): Listener<E> = subscribeAlways(E::class, coroutineContext, concurrency, priority, listener) ): Listener<E> = subscribeAlways(E::class, coroutineContext, concurrency, priority, listener)
/** /**
* **注意:** 与 [CoroutineScope.subscribe] 不同的是,
* [Bot.subscribe] 会筛选事件来源 [Bot], 只监听来自 [this] 的事件.
*
* @see Bot.subscribeAlways * @see Bot.subscribeAlways
*/ */
@SinceMirai("0.38.0") @SinceMirai("0.38.0")
...@@ -304,40 +350,37 @@ fun <E : BotEvent> Bot.subscribeAlways( ...@@ -304,40 +350,37 @@ fun <E : BotEvent> Bot.subscribeAlways(
eventClass: KClass<E>, eventClass: KClass<E>,
coroutineContext: CoroutineContext = EmptyCoroutineContext, coroutineContext: CoroutineContext = EmptyCoroutineContext,
concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT,
priority: Listener.EventPriority = Listener.EventPriority.NORMAL, priority: Listener.EventPriority = NORMAL,
listener: suspend E.(E) -> Unit listener: suspend E.(E) -> Unit
): Listener<E> = eventClass.subscribeInternal( ): Listener<E> = eventClass.subscribeInternal(
Handler(coroutineContext, concurrency, priority) { if (it.bot === this) it.listener(it); ListeningStatus.LISTENING } Handler(coroutineContext, concurrency, priority) { if (it.bot === this) it.listener(it); ListeningStatus.LISTENING }
) )
/** /**
* 在 [Bot] 的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. * **注意:** 与 [CoroutineScope.subscribe] 不同的是,
* 仅在第一次 [事件广播][Event.broadcast] 时, [listener] 会被执行. * [Bot.subscribe] 会筛选事件来源 [Bot], 只监听来自 [this] 的事件.
*
* 可在任意时候通过 [Listener.complete] 来主动停止监听.
* [Bot] 被关闭后事件监听会被 [取消][Listener.cancel].
* *
* @param coroutineContext 给事件监听协程的额外的 [CoroutineContext] * @see subscribeOnce 获取更多说明
* @param priority 事件优先级, 高的先处理
*
* @see subscribe 获取更多说明
*/ */
@JvmSynthetic @JvmSynthetic
@JvmName("subscribeOnceForBot2") @JvmName("subscribeOnceForBot2")
inline fun <reified E : BotEvent> Bot.subscribeOnce( inline fun <reified E : BotEvent> Bot.subscribeOnce(
coroutineContext: CoroutineContext = EmptyCoroutineContext, coroutineContext: CoroutineContext = EmptyCoroutineContext,
priority: Listener.EventPriority = Listener.EventPriority.NORMAL, priority: Listener.EventPriority = NORMAL,
noinline listener: suspend E.(E) -> Unit noinline listener: suspend E.(E) -> Unit
): Listener<E> = subscribeOnce(E::class, coroutineContext, priority, listener) ): Listener<E> = subscribeOnce(E::class, coroutineContext, priority, listener)
/** /**
* **注意:** 与 [CoroutineScope.subscribe] 不同的是,
* [Bot.subscribe] 会筛选事件来源 [Bot], 只监听来自 [this] 的事件.
*
* @see Bot.subscribeOnce * @see Bot.subscribeOnce
*/ */
@SinceMirai("0.38.0") @SinceMirai("0.38.0")
fun <E : BotEvent> Bot.subscribeOnce( fun <E : BotEvent> Bot.subscribeOnce(
eventClass: KClass<E>, eventClass: KClass<E>,
coroutineContext: CoroutineContext = EmptyCoroutineContext, coroutineContext: CoroutineContext = EmptyCoroutineContext,
priority: Listener.EventPriority = Listener.EventPriority.NORMAL, priority: Listener.EventPriority = NORMAL,
listener: suspend E.(E) -> Unit listener: suspend E.(E) -> Unit
): Listener<E> = ): Listener<E> =
eventClass.subscribeInternal(Handler(coroutineContext, Listener.ConcurrencyKind.LOCKED, priority) { eventClass.subscribeInternal(Handler(coroutineContext, Listener.ConcurrencyKind.LOCKED, priority) {
...@@ -351,6 +394,7 @@ fun <E : BotEvent> Bot.subscribeOnce( ...@@ -351,6 +394,7 @@ fun <E : BotEvent> Bot.subscribeOnce(
// region 为了兼容旧版本的方法 // region 为了兼容旧版本的方法
@PlannedRemoval("1.2.0")
@JvmName("subscribe") @JvmName("subscribe")
@JvmSynthetic @JvmSynthetic
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
...@@ -362,9 +406,11 @@ inline fun <reified E : Event> CoroutineScope.subscribeDeprecated( ...@@ -362,9 +406,11 @@ inline fun <reified E : Event> CoroutineScope.subscribeDeprecated(
): Listener<E> = subscribe( ): Listener<E> = subscribe(
coroutineContext = coroutineContext, coroutineContext = coroutineContext,
concurrency = concurrency, concurrency = concurrency,
priority = MONITOR,
handler = handler handler = handler
) )
@PlannedRemoval("1.2.0")
@JvmName("subscribe") @JvmName("subscribe")
@JvmSynthetic @JvmSynthetic
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
...@@ -378,9 +424,11 @@ fun <E : Event> CoroutineScope.subscribeDeprecated( ...@@ -378,9 +424,11 @@ fun <E : Event> CoroutineScope.subscribeDeprecated(
eventClass = eventClass, eventClass = eventClass,
coroutineContext = coroutineContext, coroutineContext = coroutineContext,
concurrency = concurrency, concurrency = concurrency,
priority = MONITOR,
handler = handler handler = handler
) )
@PlannedRemoval("1.2.0")
@JvmName("subscribeAlways") @JvmName("subscribeAlways")
@JvmSynthetic @JvmSynthetic
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
...@@ -392,9 +440,11 @@ inline fun <reified E : Event> CoroutineScope.subscribeAlwaysDeprecated( ...@@ -392,9 +440,11 @@ inline fun <reified E : Event> CoroutineScope.subscribeAlwaysDeprecated(
): Listener<E> = subscribeAlways( ): Listener<E> = subscribeAlways(
coroutineContext = coroutineContext, coroutineContext = coroutineContext,
concurrency = concurrency, concurrency = concurrency,
priority = MONITOR,
listener = listener listener = listener
) )
@PlannedRemoval("1.2.0")
@JvmName("subscribeAlways") @JvmName("subscribeAlways")
@JvmSynthetic @JvmSynthetic
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
...@@ -408,9 +458,11 @@ fun <E : Event> CoroutineScope.subscribeAlwaysDeprecated( ...@@ -408,9 +458,11 @@ fun <E : Event> CoroutineScope.subscribeAlwaysDeprecated(
eventClass = eventClass, eventClass = eventClass,
coroutineContext = coroutineContext, coroutineContext = coroutineContext,
concurrency = concurrency, concurrency = concurrency,
priority = MONITOR,
listener = listener listener = listener
) )
@PlannedRemoval("1.2.0")
@JvmName("subscribeOnce") @JvmName("subscribeOnce")
@JvmSynthetic @JvmSynthetic
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
...@@ -418,8 +470,13 @@ fun <E : Event> CoroutineScope.subscribeAlwaysDeprecated( ...@@ -418,8 +470,13 @@ fun <E : Event> CoroutineScope.subscribeAlwaysDeprecated(
inline fun <reified E : Event> CoroutineScope.subscribeOnceDeprecated( inline fun <reified E : Event> CoroutineScope.subscribeOnceDeprecated(
coroutineContext: CoroutineContext = EmptyCoroutineContext, coroutineContext: CoroutineContext = EmptyCoroutineContext,
noinline listener: suspend E.(E) -> Unit noinline listener: suspend E.(E) -> Unit
): Listener<E> = subscribeOnce(coroutineContext = coroutineContext, listener = listener) ): Listener<E> = subscribeOnce(
coroutineContext = coroutineContext,
priority = MONITOR,
listener = listener
)
@PlannedRemoval("1.2.0")
@JvmName("subscribeOnce") @JvmName("subscribeOnce")
@JvmSynthetic @JvmSynthetic
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
...@@ -431,9 +488,11 @@ fun <E : Event> CoroutineScope.subscribeOnceDeprecated( ...@@ -431,9 +488,11 @@ fun <E : Event> CoroutineScope.subscribeOnceDeprecated(
): Listener<E> = subscribeOnce( ): Listener<E> = subscribeOnce(
eventClass = eventClass, eventClass = eventClass,
coroutineContext = coroutineContext, coroutineContext = coroutineContext,
priority = MONITOR,
listener = listener listener = listener
) )
@PlannedRemoval("1.2.0")
@JvmSynthetic @JvmSynthetic
@JvmName("subscribeAlwaysForBot") @JvmName("subscribeAlwaysForBot")
@OptIn(MiraiInternalAPI::class) @OptIn(MiraiInternalAPI::class)
...@@ -446,9 +505,11 @@ inline fun <reified E : BotEvent> Bot.subscribeDeprecated( ...@@ -446,9 +505,11 @@ inline fun <reified E : BotEvent> Bot.subscribeDeprecated(
): Listener<E> = this.subscribe( ): Listener<E> = this.subscribe(
coroutineContext = coroutineContext, coroutineContext = coroutineContext,
concurrency = concurrency, concurrency = concurrency,
priority = MONITOR,
handler = handler handler = handler
) )
@PlannedRemoval("1.2.0")
@JvmSynthetic @JvmSynthetic
@JvmName("subscribe") @JvmName("subscribe")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
...@@ -462,9 +523,11 @@ fun <E : BotEvent> Bot.subscribeDeprecated( ...@@ -462,9 +523,11 @@ fun <E : BotEvent> Bot.subscribeDeprecated(
eventClass = eventClass, eventClass = eventClass,
coroutineContext = coroutineContext, coroutineContext = coroutineContext,
concurrency = concurrency, concurrency = concurrency,
priority = MONITOR,
handler = handler handler = handler
) )
@PlannedRemoval("1.2.0")
@JvmSynthetic @JvmSynthetic
@JvmName("subscribeAlwaysForBot1") @JvmName("subscribeAlwaysForBot1")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
...@@ -477,9 +540,11 @@ inline fun <reified E : BotEvent> Bot.subscribeAlwaysDeprecated( ...@@ -477,9 +540,11 @@ inline fun <reified E : BotEvent> Bot.subscribeAlwaysDeprecated(
): Listener<E> = subscribeAlways( ): Listener<E> = subscribeAlways(
coroutineContext = coroutineContext, coroutineContext = coroutineContext,
concurrency = concurrency, concurrency = concurrency,
priority = MONITOR,
listener = listener listener = listener
) )
@PlannedRemoval("1.2.0")
@JvmSynthetic @JvmSynthetic
@JvmName("subscribeAlways") @JvmName("subscribeAlways")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
...@@ -493,9 +558,11 @@ fun <E : BotEvent> Bot.subscribeAlwaysDeprecated( ...@@ -493,9 +558,11 @@ fun <E : BotEvent> Bot.subscribeAlwaysDeprecated(
eventClass = eventClass, eventClass = eventClass,
coroutineContext = coroutineContext, coroutineContext = coroutineContext,
concurrency = concurrency, concurrency = concurrency,
priority = MONITOR,
listener = listener listener = listener
) )
@PlannedRemoval("1.2.0")
@JvmSynthetic @JvmSynthetic
@JvmName("subscribeOnceForBot2") @JvmName("subscribeOnceForBot2")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
...@@ -505,9 +572,11 @@ inline fun <reified E : BotEvent> Bot.subscribeOnceDeprecated( ...@@ -505,9 +572,11 @@ inline fun <reified E : BotEvent> Bot.subscribeOnceDeprecated(
noinline listener: suspend E.(E) -> Unit noinline listener: suspend E.(E) -> Unit
): Listener<E> = subscribeOnce( ): Listener<E> = subscribeOnce(
coroutineContext = coroutineContext, coroutineContext = coroutineContext,
priority = MONITOR,
listener = listener listener = listener
) )
@PlannedRemoval("1.2.0")
@JvmSynthetic @JvmSynthetic
@JvmName("subscribeOnce") @JvmName("subscribeOnce")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
...@@ -519,6 +588,7 @@ fun <E : BotEvent> Bot.subscribeOnceDeprecated( ...@@ -519,6 +588,7 @@ fun <E : BotEvent> Bot.subscribeOnceDeprecated(
): Listener<E> = subscribeOnce( ): Listener<E> = subscribeOnce(
eventClass = eventClass, eventClass = eventClass,
coroutineContext = coroutineContext, coroutineContext = coroutineContext,
priority = MONITOR,
listener = listener listener = listener
) )
// endregion // endregion
\ No newline at end of file
...@@ -9,8 +9,6 @@ ...@@ -9,8 +9,6 @@
package net.mamoe.mirai.event package net.mamoe.mirai.event
import kotlinx.atomicfu.AtomicInt
import kotlinx.atomicfu.atomic
import kotlinx.coroutines.* import kotlinx.coroutines.*
import net.mamoe.mirai.event.internal.GlobalEventListeners import net.mamoe.mirai.event.internal.GlobalEventListeners
import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.MiraiInternalAPI
...@@ -18,7 +16,6 @@ import net.mamoe.mirai.utils.StepUtil ...@@ -18,7 +16,6 @@ import net.mamoe.mirai.utils.StepUtil
import net.mamoe.mirai.utils.internal.runBlocking import net.mamoe.mirai.utils.internal.runBlocking
import java.util.concurrent.Executor import java.util.concurrent.Executor
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import kotlin.concurrent.thread
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertTrue import kotlin.test.assertTrue
...@@ -67,7 +64,6 @@ class EventTests { ...@@ -67,7 +64,6 @@ class EventTests {
} }
kotlinx.coroutines.runBlocking { kotlinx.coroutines.runBlocking {
ParentEvent().broadcast() ParentEvent().broadcast()
delay(5000L) // ?
} }
val called = counter.get() val called = counter.get()
println("Registered $listeners listeners and $called called") println("Registered $listeners listeners and $called called")
...@@ -109,37 +105,39 @@ class EventTests { ...@@ -109,37 +105,39 @@ class EventTests {
} }
@Test @Test
fun `test concurrent listening 2`() { fun `test concurrent listening 2`() = runBlocking {
resetEventListeners() resetEventListeners()
val registered = AtomicInteger() val registered = AtomicInteger()
val called = AtomicInteger() val called = AtomicInteger()
val threads = mutableListOf<Thread>()
val supervisor = CoroutineScope(SupervisorJob())
coroutineScope {
repeat(50) { repeat(50) {
threads.add(thread { launch {
repeat(444) { repeat(444) {
registered.getAndIncrement() registered.getAndIncrement()
GlobalScope.launch {
subscribeAlways<ParentEvent> { supervisor.subscribeAlways<ParentEvent> {
called.getAndIncrement() called.getAndIncrement()
} }
} }
} }
})
} }
Thread.sleep(5000L)// Wait all thread started.
threads.forEach {
it.join() // Wait all finished
} }
println("All listeners registered") println("All listeners registered")
val postCount = 3 val postCount = 3
kotlinx.coroutines.runBlocking { coroutineScope {
repeat(postCount) { repeat(postCount) {
ParentEvent().broadcast() launch { ParentEvent().broadcast() }
} }
delay(5000L)
} }
val calledCount = called.get() val calledCount = called.get()
val shouldCalled = registered.get() * postCount val shouldCalled = registered.get() * postCount
println("Should call $shouldCalled times and $called called") println("Should call $shouldCalled times and $called called")
if (shouldCalled != calledCount) { if (shouldCalled != calledCount) {
throw IllegalStateException("?") throw IllegalStateException("?")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment