diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt index f9f73d813..4af5e3b1b 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt @@ -391,6 +391,7 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo init { val listener = bot.subscribeAlways<BotReloginEvent>(priority = MONITOR) { + if (bot != this.bot) return@subscribeAlways this@QQAndroidBotNetworkHandler.launch { syncMessageSvc() } } supervisor.invokeOnCompletion { listener.cancel() } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt index a8e8fcc84..a18ebb458 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt @@ -92,6 +92,9 @@ abstract class BotImpl<N : BotNetworkHandler> constructor( @Suppress("unused") private val offlineListener: Listener<BotOfflineEvent> = this@BotImpl.subscribeAlways(concurrency = Listener.ConcurrencyKind.LOCKED) { event -> + if (event.bot != this.bot) { + return@subscribeAlways + } if (network.areYouOk() && event !is BotOfflineEvent.Force) { // avoid concurrent re-login tasks return@subscribeAlways @@ -108,8 +111,10 @@ abstract class BotImpl<N : BotNetworkHandler> constructor( val time = measureTime { tailrec suspend fun reconnect() { - retryCatching<Unit>(configuration.reconnectionRetryTimes, - except = LoginFailedException::class) { tryCount, _ -> + retryCatching<Unit>( + configuration.reconnectionRetryTimes, + except = LoginFailedException::class + ) { tryCount, _ -> if (tryCount != 0) { delay(configuration.reconnectPeriodMillis) } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt index be181ddae..841a63762 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt @@ -15,7 +15,6 @@ import kotlinx.atomicfu.atomic import net.mamoe.mirai.event.internal.broadcastInternal import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.MiraiInternalAPI -import net.mamoe.mirai.utils.PlannedRemoval import net.mamoe.mirai.utils.SinceMirai import kotlin.jvm.JvmSynthetic import kotlin.jvm.Volatile @@ -161,11 +160,3 @@ interface BroadcastControllable : Event { get() = true } - -@PlannedRemoval("1.1.0") -@Deprecated( - "use AbstractEvent and implement CancellableEvent", - level = DeprecationLevel.ERROR, - replaceWith = ReplaceWith("AbstractEvent", "net.mamoe.mirai.event.AbstractEvent") -) -abstract class AbstractCancellableEvent : AbstractEvent(), CancellableEvent diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribersBuilder.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribersBuilder.kt index fadf9d1d2..80677c728 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribersBuilder.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribersBuilder.kt @@ -418,7 +418,6 @@ open class MessageSubscribersBuilder<M : MessageEvent, out Ret, R : RR, RR>( //// DEPRECATED AND INTERNAL //// ///////////////////////////////// - @PublishedApi @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE", "UNCHECKED_CAST") // false positive internal suspend inline fun executeAndReply(m: M, replier: suspend M.(String) -> Any?): RR { when (val message = replier(m, m.message.contentToString())) { @@ -429,7 +428,6 @@ open class MessageSubscribersBuilder<M : MessageEvent, out Ret, R : RR, RR>( return stub } - @PublishedApi @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE", "UNCHECKED_CAST") // false positive internal suspend inline fun executeAndQuoteReply(m: M, replier: suspend M.(String) -> Any?): RR { when (val message = replier(m, m.message.contentToString())) { diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/deprecated.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/deprecated.kt new file mode 100644 index 000000000..93a9352a8 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/deprecated.kt @@ -0,0 +1,258 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +@file:JvmMultifileClass +@file:JvmName("SubscribeMessagesKt") +@file:Suppress( + "EXPERIMENTAL_API_USAGE", + "MemberVisibilityCanBePrivate", + "unused", + "INVISIBLE_MEMBER", + "INVISIBLE_REFERENCE" +) + +package net.mamoe.mirai.event + +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.channels.ReceiveChannel +import net.mamoe.mirai.Bot +import net.mamoe.mirai.event.events.BotEvent +import net.mamoe.mirai.utils.PlannedRemoval +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName + + +// +// +//// +//// 此文件存放所有 `net.mamoe.mirai.event.subscribeMessages` 已弃用的函数. +//// +// +// +// +// +// +// +// + +@PlannedRemoval("1.1.0") +@Deprecated( + "use AbstractEvent and implement CancellableEvent", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith("AbstractEvent", "net.mamoe.mirai.event.AbstractEvent") +) +abstract class AbstractCancellableEvent : AbstractEvent(), CancellableEvent + + +@PlannedRemoval("1.3.0") +@Suppress("DeprecatedCallableAddReplaceWith") +@Deprecated( + "Deprecated for better Coroutine life cycle management. Please filter bot instance on your own.", + level = DeprecationLevel.HIDDEN +) +@kotlin.internal.LowPriorityInOverloadResolution +@OptIn(ExperimentalContracts::class) +fun <R> Bot.subscribeMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + priority: Listener.EventPriority = Listener.EventPriority.MONITOR, + listeners: MessagePacketSubscribersBuilder.() -> R +): R { + contract { + callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) + } + return MessagePacketSubscribersBuilder(Unit) { filter, listener -> + this.subscribeAlways(coroutineContext, concurrencyKind, priority) { + val toString = this.message.contentToString() + if (filter(this, toString)) + listener(this, toString) + } + }.run(listeners) +} + +@PlannedRemoval("1.3.0") +@kotlin.internal.LowPriorityInOverloadResolution +@Suppress("DeprecatedCallableAddReplaceWith") +@Deprecated( + "Deprecated for better Coroutine life cycle management. Please filter bot instance on your own.", + level = DeprecationLevel.HIDDEN +) +@OptIn(ExperimentalContracts::class) +fun <R> Bot.subscribeGroupMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + priority: Listener.EventPriority = Listener.EventPriority.MONITOR, + listeners: GroupMessageSubscribersBuilder.() -> R +): R { + contract { + callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) + } + return GroupMessageSubscribersBuilder(Unit) { filter, listener -> + this.subscribeAlways(coroutineContext, concurrencyKind, priority) { + val toString = this.message.contentToString() + if (filter(this, toString)) + listener(this, toString) + } + }.run(listeners) +} + +@kotlin.internal.LowPriorityInOverloadResolution +@PlannedRemoval("1.3.0") +@Suppress("DeprecatedCallableAddReplaceWith") +@Deprecated( + "Deprecated for better Coroutine life cycle management. Please filter bot instance on your own.", + level = DeprecationLevel.HIDDEN +) +@OptIn(ExperimentalContracts::class) +fun <R> Bot.subscribeFriendMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + priority: Listener.EventPriority = Listener.EventPriority.MONITOR, + listeners: FriendMessageSubscribersBuilder.() -> R +): R { + contract { + callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) + } + return FriendMessageSubscribersBuilder(Unit) { filter, listener -> + this.subscribeAlways(coroutineContext, concurrencyKind, priority) { + val toString = this.message.contentToString() + if (filter(this, toString)) + listener(this, toString) + } + }.run(listeners) +} + + +@kotlin.internal.LowPriorityInOverloadResolution +@PlannedRemoval("1.3.0") +@Suppress("DeprecatedCallableAddReplaceWith") +@Deprecated( + "Deprecated for better Coroutine life cycle management. Please filter bot instance on your own.", + level = DeprecationLevel.HIDDEN +) +@OptIn(ExperimentalContracts::class) +fun <R> Bot.subscribeTempMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + priority: Listener.EventPriority = Listener.EventPriority.MONITOR, + listeners: TempMessageSubscribersBuilder.() -> R +): R { + contract { + callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) + } + return TempMessageSubscribersBuilder(Unit) { filter, listener -> + this.subscribeAlways(coroutineContext, concurrencyKind, priority) { + val toString = this.message.contentToString() + if (filter(this, toString)) + listener(this, toString) + } + }.run(listeners) +} + +@kotlin.internal.LowPriorityInOverloadResolution +@PlannedRemoval("1.3.0") +@Suppress("DeprecatedCallableAddReplaceWith") +@Deprecated( + "Deprecated for better Coroutine life cycle management. Please filter bot instance on your own.", + level = DeprecationLevel.HIDDEN +) +inline fun <reified E : BotEvent> Bot.incoming( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + priority: Listener.EventPriority = Listener.EventPriority.MONITOR, + capacity: Int = Channel.UNLIMITED +): ReceiveChannel<E> { + return Channel<E>(capacity).apply { + val listener = this@incoming.subscribeAlways<E>(coroutineContext, concurrencyKind, priority) { + send(this) + } + this.invokeOnClose { + listener.cancel(CancellationException("ReceiveChannel closed", it)) + } + } +} + +@kotlin.internal.LowPriorityInOverloadResolution +@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) +@PlannedRemoval("1.2.0") +fun <R> CoroutineScope.subscribeMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + listeners: MessagePacketSubscribersBuilder.() -> R +): R = this.subscribeMessages(coroutineContext, concurrencyKind, Listener.EventPriority.MONITOR, listeners) + +@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) +@kotlin.internal.LowPriorityInOverloadResolution +@PlannedRemoval("1.2.0") +fun <R> CoroutineScope.subscribeGroupMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + listeners: GroupMessageSubscribersBuilder.() -> R +): R = this.subscribeGroupMessages(coroutineContext, concurrencyKind, Listener.EventPriority.MONITOR, listeners) + +@kotlin.internal.LowPriorityInOverloadResolution +@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) +@PlannedRemoval("1.2.0") +fun <R> CoroutineScope.subscribeFriendMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + listeners: FriendMessageSubscribersBuilder.() -> R +): R = this.subscribeFriendMessages(coroutineContext, concurrencyKind, Listener.EventPriority.MONITOR, listeners) + +@kotlin.internal.LowPriorityInOverloadResolution +@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) +@PlannedRemoval("1.2.0") +fun <R> CoroutineScope.subscribeTempMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + listeners: TempMessageSubscribersBuilder.() -> R +): R = this.subscribeTempMessages(coroutineContext, concurrencyKind, Listener.EventPriority.MONITOR, listeners) + +@kotlin.internal.LowPriorityInOverloadResolution +@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) +@PlannedRemoval("1.2.0") +fun <R> Bot.subscribeMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + listeners: MessagePacketSubscribersBuilder.() -> R +): R = this.subscribeMessages(coroutineContext, concurrencyKind, Listener.EventPriority.MONITOR, listeners) + +@kotlin.internal.LowPriorityInOverloadResolution +@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) +@PlannedRemoval("1.2.0") +fun <R> Bot.subscribeGroupMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + listeners: GroupMessageSubscribersBuilder.() -> R +): R = this.subscribeGroupMessages(coroutineContext, concurrencyKind, Listener.EventPriority.MONITOR, listeners) + +@kotlin.internal.LowPriorityInOverloadResolution +@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) +@PlannedRemoval("1.2.0") +fun <R> Bot.subscribeFriendMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + listeners: FriendMessageSubscribersBuilder.() -> R +): R = this.subscribeFriendMessages(coroutineContext, concurrencyKind, Listener.EventPriority.MONITOR, listeners) + +@kotlin.internal.LowPriorityInOverloadResolution +@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) +@PlannedRemoval("1.2.0") +fun <R> Bot.subscribeTempMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + listeners: TempMessageSubscribersBuilder.() -> R +): R = this.subscribeTempMessages(coroutineContext, concurrencyKind, Listener.EventPriority.MONITOR, listeners) \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/linear.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/linear.kt index ae988b6ba..58e052194 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/linear.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/linear.kt @@ -27,6 +27,8 @@ import kotlin.reflect.KClass * @see subscribe 普通地监听一个事件 * @see nextEvent 挂起当前协程, 并获取下一个事件实例 * + * @see syncFromEventOrNull 本函数的在超时后返回 `null` 的版本 + * * @throws TimeoutCancellationException 在超时后抛出. * @throws Throwable 当 [mapper] 抛出任何异常时, 本函数会抛出该异常 */ diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/nextEvent.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/nextEvent.kt index c4e7b0325..fd4228b6d 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/nextEvent.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/nextEvent.kt @@ -7,13 +7,14 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -@file:Suppress("unused") +@file:Suppress("unused", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") package net.mamoe.mirai.event import kotlinx.coroutines.* import net.mamoe.mirai.Bot import net.mamoe.mirai.event.events.BotEvent +import net.mamoe.mirai.utils.PlannedRemoval import kotlin.coroutines.resume import kotlin.jvm.JvmSynthetic import kotlin.reflect.KClass @@ -61,18 +62,20 @@ suspend inline fun <reified E : Event> nextEventOrNull( } } +// +// +// 以下为已弃用的函数 +// +// +// -/** - * 挂起当前协程, 直到监听到事件 [E] 的广播, 返回这个事件实例. - * 将筛选 [BotEvent.bot] 与 [this] 相等的事件. - * - * @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制. - * - * @see subscribe 普通地监听一个事件 - * @see syncFromEvent 挂起当前协程, 并尝试从事件中同步一个值 - * - * @throws TimeoutCancellationException 在超时后抛出. - */ + +@PlannedRemoval("1.3.0") +@Suppress("DeprecatedCallableAddReplaceWith") +@Deprecated( + "Deprecated for better Coroutine life cycle management. Please filter bot instance on your own.", + level = DeprecationLevel.HIDDEN +) @JvmSynthetic suspend inline fun <reified E : BotEvent> Bot.nextEvent( timeoutMillis: Long = -1, @@ -84,27 +87,6 @@ suspend inline fun <reified E : BotEvent> Bot.nextEvent( } } -/** - * 挂起当前协程, 直到监听到事件 [E] 的广播, 返回这个事件实例. - * 将筛选 [BotEvent.bot] 与 [this] 相等的事件. - * - * @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制. - * - * @see subscribe 普通地监听一个事件 - * @see syncFromEvent 挂起当前协程, 并尝试从事件中同步一个值 - * - * @return 事件实例, 在超时后返回 `null` - */ -@JvmSynthetic -suspend inline fun <reified E : BotEvent> Bot.nextEventOrNull( - timeoutMillis: Long, - priority: Listener.EventPriority = Listener.EventPriority.MONITOR -): E? { - return withTimeoutOrNull(timeoutMillis) { - nextBotEventImpl(this@nextEventOrNull, E::class, this, priority) - } -} - @JvmSynthetic @PublishedApi internal suspend inline fun <E : Event> nextEventImpl( diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscribeMessages.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscribeMessages.kt index 787171910..011d05b6c 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscribeMessages.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscribeMessages.kt @@ -7,6 +7,8 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ +@file:JvmMultifileClass +@file:JvmName("SubscribeMessagesKt") @file:Suppress("EXPERIMENTAL_API_USAGE", "MemberVisibilityCanBePrivate", "unused") package net.mamoe.mirai.event @@ -16,23 +18,25 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.ReceiveChannel import net.mamoe.mirai.Bot -import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.message.FriendMessageEvent import net.mamoe.mirai.message.GroupMessageEvent import net.mamoe.mirai.message.MessageEvent import net.mamoe.mirai.message.TempMessageEvent -import net.mamoe.mirai.utils.PlannedRemoval import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName typealias MessagePacketSubscribersBuilder = MessageSubscribersBuilder<MessageEvent, Listener<MessageEvent>, Unit, Unit> /** * 订阅来自所有 [Bot] 的所有联系人的消息事件. 联系人可以是任意群或任意好友或临时会话. * + * @see subscribe 事件监听基础 + * * @see CoroutineScope.incoming 打开一个指定事件的接收通道 */ @OptIn(ExperimentalContracts::class) @@ -65,6 +69,8 @@ typealias GroupMessageSubscribersBuilder = MessageSubscribersBuilder<GroupMessag /** * 订阅来自所有 [Bot] 的所有群消息事件 * + * @see subscribe 事件监听基础 + * * @see CoroutineScope.incoming 打开一个指定事件的接收通道 */ @OptIn(ExperimentalContracts::class) @@ -91,6 +97,8 @@ typealias FriendMessageSubscribersBuilder = MessageSubscribersBuilder<FriendMess /** * 订阅来自所有 [Bot] 的所有好友消息事件 * + * @see subscribe 事件监听基础 + * * @see CoroutineScope.incoming 打开一个指定事件的接收通道 */ @OptIn(ExperimentalContracts::class) @@ -117,6 +125,8 @@ typealias TempMessageSubscribersBuilder = MessageSubscribersBuilder<TempMessageE /** * 订阅来自所有 [Bot] 的所有临时会话消息事件 * + * @see subscribe 事件监听基础 + * * @see CoroutineScope.incoming 打开一个指定事件的接收通道 */ @OptIn(ExperimentalContracts::class) @@ -138,104 +148,6 @@ fun <R> CoroutineScope.subscribeTempMessages( }.run(listeners) } -/** - * 订阅来自这个 [Bot] 的所有联系人的消息事件. 联系人可以是任意群或任意好友或临时会话. - * - * @see CoroutineScope.incoming 打开一个指定事件的接收通道 - */ -@OptIn(ExperimentalContracts::class) -fun <R> Bot.subscribeMessages( - coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - priority: Listener.EventPriority = Listener.EventPriority.MONITOR, - listeners: MessagePacketSubscribersBuilder.() -> R -): R { - contract { - callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) - } - return MessagePacketSubscribersBuilder(Unit) { filter, listener -> - this.subscribeAlways(coroutineContext, concurrencyKind, priority) { - val toString = this.message.contentToString() - if (filter(this, toString)) - listener(this, toString) - } - }.run(listeners) -} - -/** - * 订阅来自这个 [Bot] 的所有群消息事件 - * - * @param coroutineContext 给事件监听协程的额外的 [CoroutineContext] - * - * @see CoroutineScope.incoming 打开一个指定事件的接收通道 - */ -@OptIn(ExperimentalContracts::class) -fun <R> Bot.subscribeGroupMessages( - coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - priority: Listener.EventPriority = Listener.EventPriority.MONITOR, - listeners: GroupMessageSubscribersBuilder.() -> R -): R { - contract { - callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) - } - return GroupMessageSubscribersBuilder(Unit) { filter, listener -> - this.subscribeAlways(coroutineContext, concurrencyKind, priority) { - val toString = this.message.contentToString() - if (filter(this, toString)) - listener(this, toString) - } - }.run(listeners) -} - -/** - * 订阅来自这个 [Bot] 的所有好友消息事件. - * - * @see CoroutineScope.incoming 打开一个指定事件的接收通道 - */ -@OptIn(ExperimentalContracts::class) -fun <R> Bot.subscribeFriendMessages( - coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - priority: Listener.EventPriority = Listener.EventPriority.MONITOR, - listeners: FriendMessageSubscribersBuilder.() -> R -): R { - contract { - callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) - } - return FriendMessageSubscribersBuilder(Unit) { filter, listener -> - this.subscribeAlways(coroutineContext, concurrencyKind, priority) { - val toString = this.message.contentToString() - if (filter(this, toString)) - listener(this, toString) - } - }.run(listeners) -} - - -/** - * 订阅来自这个 [Bot] 的所有临时会话消息事件. - * - * @see CoroutineScope.incoming 打开一个指定事件的接收通道 - */ -@OptIn(ExperimentalContracts::class) -fun <R> Bot.subscribeTempMessages( - coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - priority: Listener.EventPriority = Listener.EventPriority.MONITOR, - listeners: TempMessageSubscribersBuilder.() -> R -): R { - contract { - callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) - } - return TempMessageSubscribersBuilder(Unit) { filter, listener -> - this.subscribeAlways(coroutineContext, concurrencyKind, priority) { - val toString = this.message.contentToString() - if (filter(this, toString)) - listener(this, toString) - } - }.run(listeners) -} /** * 打开一个指定事件的接收通道 @@ -245,6 +157,8 @@ fun <R> Bot.subscribeTempMessages( * @see capacity 默认无限大小. 详见 [Channel.Factory] 中的常量 [Channel.UNLIMITED], [Channel.CONFLATED], [Channel.RENDEZVOUS]. * 请谨慎使用 [Channel.RENDEZVOUS]: 在 [Channel] 未被 [接收][Channel.receive] 时他将会阻塞事件处理 * + * @see subscribe 事件监听基础 + * * @see subscribeFriendMessages * @see subscribeMessages * @see subscribeGroupMessages @@ -265,96 +179,3 @@ inline fun <reified E : Event> CoroutineScope.incoming( } } - -/** - * 打开一个来自指定 [Bot] 的指定事件的接收通道 - * - * @param capacity 同 [Channel] 的参数, 参见 [Channel.Factory] 中的常量. - * - * @see capacity 默认无限大小. 详见 [Channel.Factory] 中的常量 [Channel.UNLIMITED], [Channel.CONFLATED], [Channel.RENDEZVOUS]. - * 请谨慎使用 [Channel.RENDEZVOUS]: 在 [Channel] 未被 [接收][Channel.receive] 时他将会阻塞事件处理 - * - * @see subscribeFriendMessages - * @see subscribeMessages - * @see subscribeGroupMessages - */ -inline fun <reified E : BotEvent> Bot.incoming( - coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - priority: Listener.EventPriority = Listener.EventPriority.MONITOR, - capacity: Int = Channel.UNLIMITED -): ReceiveChannel<E> { - return Channel<E>(capacity).apply { - val listener = this@incoming.subscribeAlways<E>(coroutineContext, concurrencyKind, priority) { - send(this) - } - this.invokeOnClose { - listener.cancel(CancellationException("ReceiveChannel closed", it)) - } - } -} - - -@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) -@PlannedRemoval("1.2.0") -fun <R> CoroutineScope.subscribeMessages( - coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - listeners: MessagePacketSubscribersBuilder.() -> R -): R = this.subscribeMessages(coroutineContext, concurrencyKind, Listener.EventPriority.MONITOR, listeners) - -@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) -@PlannedRemoval("1.2.0") -fun <R> CoroutineScope.subscribeGroupMessages( - coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - listeners: GroupMessageSubscribersBuilder.() -> R -): R = this.subscribeGroupMessages(coroutineContext, concurrencyKind, Listener.EventPriority.MONITOR, listeners) - -@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) -@PlannedRemoval("1.2.0") -fun <R> CoroutineScope.subscribeFriendMessages( - coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - listeners: FriendMessageSubscribersBuilder.() -> R -): R = this.subscribeFriendMessages(coroutineContext, concurrencyKind, Listener.EventPriority.MONITOR, listeners) - -@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) -@PlannedRemoval("1.2.0") -fun <R> CoroutineScope.subscribeTempMessages( - coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - listeners: TempMessageSubscribersBuilder.() -> R -): R = this.subscribeTempMessages(coroutineContext, concurrencyKind, Listener.EventPriority.MONITOR, listeners) - -@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) -@PlannedRemoval("1.2.0") -fun <R> Bot.subscribeMessages( - coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - listeners: MessagePacketSubscribersBuilder.() -> R -): R = this.subscribeMessages(coroutineContext, concurrencyKind, Listener.EventPriority.MONITOR, listeners) - -@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) -@PlannedRemoval("1.2.0") -fun <R> Bot.subscribeGroupMessages( - coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - listeners: GroupMessageSubscribersBuilder.() -> R -): R = this.subscribeGroupMessages(coroutineContext, concurrencyKind, Listener.EventPriority.MONITOR, listeners) - -@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) -@PlannedRemoval("1.2.0") -fun <R> Bot.subscribeFriendMessages( - coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - listeners: FriendMessageSubscribersBuilder.() -> R -): R = this.subscribeFriendMessages(coroutineContext, concurrencyKind, Listener.EventPriority.MONITOR, listeners) - -@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) -@PlannedRemoval("1.2.0") -fun <R> Bot.subscribeTempMessages( - coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrencyKind: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, - listeners: TempMessageSubscribersBuilder.() -> R -): R = this.subscribeTempMessages(coroutineContext, concurrencyKind, Listener.EventPriority.MONITOR, listeners) \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscriber.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscriber.kt index 63648afd3..b114ac263 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscriber.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscriber.kt @@ -7,7 +7,7 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -@file:Suppress("unused") +@file:Suppress("unused", "DEPRECATION", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") package net.mamoe.mirai.event @@ -17,6 +17,8 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.sync.Mutex import net.mamoe.mirai.Bot +import net.mamoe.mirai.event.Listener.ConcurrencyKind.CONCURRENT +import net.mamoe.mirai.event.Listener.ConcurrencyKind.LOCKED import net.mamoe.mirai.event.Listener.EventPriority.* import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.event.internal.Handler @@ -117,7 +119,8 @@ interface Listener<in E : Event> : CompletableJob { /** * 这个方法将会调用 [subscribe] 时提供的参数 `noinline handler: suspend E.(E) -> ListeningStatus`. - * 并捕捉其异常. + * + * 这个函数不会抛出任何异常, 详见 [subscribe] 中 `` */ suspend fun onEvent(event: E): ListeningStatus } @@ -125,64 +128,72 @@ interface Listener<in E : Event> : CompletableJob { // region 顶层方法 创建当前 coroutineContext 下的子 Job /** - * 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. + * 在指定的 [协程作用域][CoroutineScope] 下创建一个事件监听器, 监听所有 [E] 及其子类事件. + * * 每当 [事件广播][Event.broadcast] 时, [handler] 都会被执行. * * * ### 创建监听 - * - * #### 单个 [Bot] 的事件监听 - * 要创建一个仅在某个机器人在线时的监听, 请在 [Bot] 下调用本函数 (因为 [Bot] 也实现 [CoroutineScope]). - * 这种方式创建的监听会自动筛选 [Bot]. + * 调用本函数: * ``` - * bot1.subscribe<BotEvent> { /* 只会处理来自 bot1 的事件 */ } + * coroutineScope.subscribe<Event> { /* 会收到来自全部 Bot 的事件和与 Bot 不相关的事件 */ } * ``` * - * #### 全局范围监听 - * 要创建一个全局都存在的监听(不推荐), 请使用除 [Bot] 外的任意 [协程作用域][CoroutineScope] 调用本函数: + * ### 生命周期 + * + * #### 通过协程作用域管理监听器 + * 本函数将会创建一个 [Job], 成为 [this] 中的子任务. 可创建一个 [CoroutineScope] 来管理所有的监听器: * ``` - * GlobalScope.subscribe<Event> { /* 会收到来自全部 Bot 的事件和与 Bot 不相关的事件 */ } + * val scope = CoroutineScope(SupervisorJob()) + * + * scope.subscribeAlways<MemberJoinEvent> { /* ... */ } + * scope.subscribeAlways<MemberMuteEvent> { /* ... */ } + * + * scope.cancel() // 停止上文两个监听 * ``` * + * **注意**, 这个函数返回 [Listener], 它是一个 [CompletableJob]. 它会成为 [CoroutineScope] 的一个 [子任务][Job] + * ``` + * runBlocking { // this: CoroutineScope + * subscribe<Event> { /* 一些处理 */ } // 返回 Listener, 即 CompletableJob + * } + * // runBlocking 不会完结, 直到监听时创建的 `Listener` 被停止. + * // 它可能通过 Listener.cancel() 停止, 也可能自行返回 ListeningStatus.Stopped 停止. + * ``` + * + * #### 在监听器内部停止后续监听 + * 当 [listener] 返回 [ListeningStatus.STOPPED] 时停止监听. + * 或 [Listener.complete] 后结束. + * + * ### 子类监听 + * 监听父类事件, 也会同时监听其子类. 因此监听 [Event] 即可监听所有类型的事件. * * ### 异常处理 * 事件处理时的 [CoroutineContext] 为调用本函数时的 [receiver][this] 的 [CoroutineScope.coroutineContext]. * 因此: - * - 当参数 [handler] 处理抛出异常时, 将会按如下顺序寻找 [CoroutineExceptionHandler] 处理异常: + * - 当参数 [listener] 处理抛出异常时, 将会按如下顺序寻找 [CoroutineExceptionHandler] 处理异常: * 1. 参数 [coroutineContext] * 2. 接收者 [this] 的 [CoroutineScope.coroutineContext] * 3. [Event.broadcast] 调用者的 [coroutineContext] * 4. 若事件为 [BotEvent], 则从 [BotEvent.bot] 获取到 [Bot], 进而在 [Bot.coroutineContext] 中寻找 * 5. 若以上四个步骤均无法获取 [CoroutineExceptionHandler], 则使用 [MiraiLogger.Companion] 通过日志记录. 但这种情况理论上不应发生. * - 事件处理时抛出异常不会停止监听器. - * - 建议在事件处理中 (即 [handler] 里) 处理异常, + * - 建议在事件处理中 (即 [listener] 里) 处理异常, * 或在参数 [coroutineContext] 中添加 [CoroutineExceptionHandler]. * * - * ### 停止监听 - * 当 [handler] 返回 [ListeningStatus.STOPPED] 时停止监听. - * 或 [Listener.complete] 后结束. - * - * 这个函数返回 [Listener], 它是一个 [CompletableJob]. 它会成为 [CoroutineScope] 的一个 [子任务][Job] - * 例: - * ``` - * runBlocking { // this: CoroutineScope - * subscribe<Event> { /* 一些处理 */ } // 返回 Listener, 即 CompletableJob - * } - * foo() - * ``` - * `runBlocking` 不会结束, 也就是下一行 `foo()` 不会被执行. 直到监听时创建的 `Listener` 被停止. - * - * - * * @param coroutineContext 给事件监听协程的额外的 [CoroutineContext]. * @param concurrency 并发类型. 查看 [Listener.ConcurrencyKind] * @param priority 监听优先级,优先级越高越先执行 - * @param handler 事件处理器. 在接收到事件时会调用这个处理器. 其返回值意义参考 [ListeningStatus]. 其异常处理参考上文 + * @param listener 事件处理器. 在接收到事件时会调用这个处理器. 其返回值意义参考 [ListeningStatus]. 其异常处理参考上文 + * + * @return 监听器实例. 此监听器已经注册到指定事件上, 在事件广播时将会调用 [listener] * * @see syncFromEvent 挂起当前协程, 监听一个事件, 并尝试从这个事件中**同步**一个值 * @see asyncFromEvent 异步监听一个事件, 并尝试从这个事件中获取一个值. * + * @see nextEvent 挂起当前协程, 直到监听到事件 [E] 的广播, 返回这个事件实例. + * * @see selectMessages 以 `when` 的语法 '选择' 即将到来的一条消息. * @see whileSelectMessages 以 `when` 的语法 '选择' 即将到来的所有消息, 直到不满足筛选结果. * @@ -196,23 +207,25 @@ interface Listener<in E : Event> : CompletableJob { */ inline fun <reified E : Event> CoroutineScope.subscribe( coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED, + concurrency: Listener.ConcurrencyKind = LOCKED, priority: Listener.EventPriority = NORMAL, - noinline handler: suspend E.(E) -> ListeningStatus -): Listener<E> = subscribe(E::class, coroutineContext, concurrency, priority, handler) + noinline listener: suspend E.(E) -> ListeningStatus +): Listener<E> = subscribe(E::class, coroutineContext, concurrency, priority, listener) /** * 与 [subscribe] 的区别是接受 [eventClass] 参数, 而不使用 `reified` 泛型 * * @see CoroutineScope.subscribe + * + * @return 监听器实例. 此监听器已经注册到指定事件上, 在事件广播时将会调用 [listener] */ fun <E : Event> CoroutineScope.subscribe( eventClass: KClass<E>, coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED, + concurrency: Listener.ConcurrencyKind = LOCKED, priority: Listener.EventPriority = NORMAL, - handler: suspend E.(E) -> ListeningStatus -): Listener<E> = eventClass.subscribeInternal(Handler(coroutineContext, concurrency, priority) { it.handler(it); }) + listener: suspend E.(E) -> ListeningStatus +): Listener<E> = eventClass.subscribeInternal(Handler(coroutineContext, concurrency, priority) { it.listener(it); }) /** * 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. @@ -221,26 +234,30 @@ fun <E : Event> CoroutineScope.subscribe( * 可在任意时候通过 [Listener.complete] 来主动停止监听. * [CoroutineScope] 被关闭后事件监听会被 [取消][Listener.cancel]. * + * @param concurrency 并发类型默认为 [CONCURRENT] * @param coroutineContext 给事件监听协程的额外的 [CoroutineContext] * @param priority 处理优先级, 优先级高的先执行 * + * @return 监听器实例. 此监听器已经注册到指定事件上, 在事件广播时将会调用 [listener] + * * @see CoroutineScope.subscribe 获取更多说明 */ inline fun <reified E : Event> CoroutineScope.subscribeAlways( coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + concurrency: Listener.ConcurrencyKind = CONCURRENT, priority: Listener.EventPriority = NORMAL, noinline listener: suspend E.(E) -> Unit ): Listener<E> = subscribeAlways(E::class, coroutineContext, concurrency, priority, listener) /** + * @see CoroutineScope.subscribe * @see CoroutineScope.subscribeAlways */ fun <E : Event> CoroutineScope.subscribeAlways( eventClass: KClass<E>, coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + concurrency: Listener.ConcurrencyKind = CONCURRENT, priority: Listener.EventPriority = NORMAL, listener: suspend E.(E) -> Unit ): Listener<E> = eventClass.subscribeInternal( @@ -275,11 +292,11 @@ fun <E : Event> CoroutineScope.subscribeOnce( priority: Listener.EventPriority = NORMAL, listener: suspend E.(E) -> Unit ): Listener<E> = eventClass.subscribeInternal( - Handler(coroutineContext, Listener.ConcurrencyKind.LOCKED, priority) { it.listener(it); ListeningStatus.STOPPED } + Handler(coroutineContext, LOCKED, priority) { it.listener(it); ListeningStatus.STOPPED } ) // -// 以下为带筛选 Bot 的监听 +// 以下为带筛选 Bot 的监听 (已启用) // @@ -289,12 +306,19 @@ fun <E : Event> CoroutineScope.subscribeOnce( * * @see CoroutineScope.subscribe 获取更多说明 */ +@PlannedRemoval("1.3.0") +@Suppress("DeprecatedCallableAddReplaceWith", "DEPRECATION") @JvmSynthetic @JvmName("subscribeAlwaysForBot") @OptIn(MiraiInternalAPI::class) +@kotlin.internal.LowPriorityInOverloadResolution +@Deprecated( + "Deprecated for better Coroutine life cycle management. Please filter bot instance on your own.", + level = DeprecationLevel.HIDDEN +) inline fun <reified E : BotEvent> Bot.subscribe( coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED, + concurrency: Listener.ConcurrencyKind = LOCKED, priority: Listener.EventPriority = NORMAL, noinline handler: suspend E.(E) -> ListeningStatus ): Listener<E> = this.subscribe(E::class, coroutineContext, concurrency, priority, handler) @@ -305,10 +329,17 @@ inline fun <reified E : BotEvent> Bot.subscribe( * * @see Bot.subscribe */ +@PlannedRemoval("1.3.0") +@Suppress("DeprecatedCallableAddReplaceWith") +@kotlin.internal.LowPriorityInOverloadResolution +@Deprecated( + "Deprecated for better Coroutine life cycle management. Please filter bot instance on your own.", + level = DeprecationLevel.HIDDEN +) fun <E : BotEvent> Bot.subscribe( eventClass: KClass<E>, coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED, + concurrency: Listener.ConcurrencyKind = LOCKED, priority: Listener.EventPriority = NORMAL, handler: suspend E.(E) -> ListeningStatus ): Listener<E> = eventClass.subscribeInternal( @@ -325,12 +356,19 @@ fun <E : BotEvent> Bot.subscribe( * * @see CoroutineScope.subscribeAlways 获取更多说明 */ +@PlannedRemoval("1.3.0") +@Suppress("DeprecatedCallableAddReplaceWith") @JvmSynthetic @JvmName("subscribeAlwaysForBot1") +@kotlin.internal.LowPriorityInOverloadResolution @OptIn(MiraiInternalAPI::class) +@Deprecated( + "Deprecated for better Coroutine life cycle management. Please filter bot instance on your own.", + level = DeprecationLevel.HIDDEN +) inline fun <reified E : BotEvent> Bot.subscribeAlways( coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + concurrency: Listener.ConcurrencyKind = CONCURRENT, priority: Listener.EventPriority = NORMAL, noinline listener: suspend E.(E) -> Unit ): Listener<E> = subscribeAlways(E::class, coroutineContext, concurrency, priority, listener) @@ -341,10 +379,16 @@ inline fun <reified E : BotEvent> Bot.subscribeAlways( * * @see Bot.subscribeAlways */ +@PlannedRemoval("1.3.0") +@kotlin.internal.LowPriorityInOverloadResolution +@Deprecated( + "Deprecated for better Coroutine life cycle management. Please filter bot instance on your own.", + level = DeprecationLevel.HIDDEN +) fun <E : BotEvent> Bot.subscribeAlways( eventClass: KClass<E>, coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + concurrency: Listener.ConcurrencyKind = CONCURRENT, priority: Listener.EventPriority = NORMAL, listener: suspend E.(E) -> Unit ): Listener<E> = eventClass.subscribeInternal( @@ -357,8 +401,15 @@ fun <E : BotEvent> Bot.subscribeAlways( * * @see subscribeOnce 获取更多说明 */ +@Suppress("DeprecatedCallableAddReplaceWith") @JvmSynthetic @JvmName("subscribeOnceForBot2") +@PlannedRemoval("1.3.0") +@kotlin.internal.LowPriorityInOverloadResolution +@Deprecated( + "Deprecated for better Coroutine life cycle management. Please filter bot instance on your own.", + level = DeprecationLevel.HIDDEN +) inline fun <reified E : BotEvent> Bot.subscribeOnce( coroutineContext: CoroutineContext = EmptyCoroutineContext, priority: Listener.EventPriority = NORMAL, @@ -371,13 +422,19 @@ inline fun <reified E : BotEvent> Bot.subscribeOnce( * * @see Bot.subscribeOnce */ +@PlannedRemoval("1.3.0") +@kotlin.internal.LowPriorityInOverloadResolution +@Deprecated( + "Deprecated for better Coroutine life cycle management. Please filter bot instance on your own.", + level = DeprecationLevel.HIDDEN +) fun <E : BotEvent> Bot.subscribeOnce( eventClass: KClass<E>, coroutineContext: CoroutineContext = EmptyCoroutineContext, priority: Listener.EventPriority = NORMAL, listener: suspend E.(E) -> Unit ): Listener<E> = - eventClass.subscribeInternal(Handler(coroutineContext, Listener.ConcurrencyKind.LOCKED, priority) { + eventClass.subscribeInternal(Handler(coroutineContext, LOCKED, priority) { if (it.bot === this) { it.listener(it) ListeningStatus.STOPPED @@ -386,6 +443,7 @@ fun <E : BotEvent> Bot.subscribeOnce( // endregion + // region 为了兼容旧版本的方法 @PlannedRemoval("1.2.0") @@ -395,13 +453,13 @@ fun <E : BotEvent> Bot.subscribeOnce( @Suppress("unused") inline fun <reified E : Event> CoroutineScope.subscribeDeprecated( coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED, + concurrency: Listener.ConcurrencyKind = LOCKED, noinline handler: suspend E.(E) -> ListeningStatus ): Listener<E> = subscribe( coroutineContext = coroutineContext, concurrency = concurrency, priority = MONITOR, - handler = handler + listener = handler ) @PlannedRemoval("1.2.0") @@ -412,14 +470,14 @@ inline fun <reified E : Event> CoroutineScope.subscribeDeprecated( fun <E : Event> CoroutineScope.subscribeDeprecated( eventClass: KClass<E>, coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED, + concurrency: Listener.ConcurrencyKind = LOCKED, handler: suspend E.(E) -> ListeningStatus ): Listener<E> = subscribe( eventClass = eventClass, coroutineContext = coroutineContext, concurrency = concurrency, priority = MONITOR, - handler = handler + listener = handler ) @PlannedRemoval("1.2.0") @@ -429,7 +487,7 @@ fun <E : Event> CoroutineScope.subscribeDeprecated( @Suppress("unused") inline fun <reified E : Event> CoroutineScope.subscribeAlwaysDeprecated( coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED, + concurrency: Listener.ConcurrencyKind = LOCKED, noinline listener: suspend E.(E) -> Unit ): Listener<E> = subscribeAlways( coroutineContext = coroutineContext, @@ -446,7 +504,7 @@ inline fun <reified E : Event> CoroutineScope.subscribeAlwaysDeprecated( fun <E : Event> CoroutineScope.subscribeAlwaysDeprecated( eventClass: KClass<E>, coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED, + concurrency: Listener.ConcurrencyKind = LOCKED, listener: suspend E.(E) -> Unit ): Listener<E> = subscribeAlways( eventClass = eventClass, @@ -494,13 +552,13 @@ fun <E : Event> CoroutineScope.subscribeOnceDeprecated( @Suppress("unused") inline fun <reified E : BotEvent> Bot.subscribeDeprecated( coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED, + concurrency: Listener.ConcurrencyKind = LOCKED, noinline handler: suspend E.(E) -> ListeningStatus ): Listener<E> = this.subscribe( coroutineContext = coroutineContext, concurrency = concurrency, priority = MONITOR, - handler = handler + listener = handler ) @PlannedRemoval("1.2.0") @@ -511,14 +569,14 @@ inline fun <reified E : BotEvent> Bot.subscribeDeprecated( fun <E : BotEvent> Bot.subscribeDeprecated( eventClass: KClass<E>, coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.LOCKED, + concurrency: Listener.ConcurrencyKind = LOCKED, handler: suspend E.(E) -> ListeningStatus ): Listener<E> = subscribe( eventClass = eventClass, coroutineContext = coroutineContext, concurrency = concurrency, priority = MONITOR, - handler = handler + listener = handler ) @PlannedRemoval("1.2.0") @@ -529,7 +587,7 @@ fun <E : BotEvent> Bot.subscribeDeprecated( @OptIn(MiraiInternalAPI::class) inline fun <reified E : BotEvent> Bot.subscribeAlwaysDeprecated( coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + concurrency: Listener.ConcurrencyKind = CONCURRENT, noinline listener: suspend E.(E) -> Unit ): Listener<E> = subscribeAlways( coroutineContext = coroutineContext, @@ -546,7 +604,7 @@ inline fun <reified E : BotEvent> Bot.subscribeAlwaysDeprecated( fun <E : BotEvent> Bot.subscribeAlwaysDeprecated( eventClass: KClass<E>, coroutineContext: CoroutineContext = EmptyCoroutineContext, - concurrency: Listener.ConcurrencyKind = Listener.ConcurrencyKind.CONCURRENT, + concurrency: Listener.ConcurrencyKind = CONCURRENT, listener: suspend E.(E) -> Unit ): Listener<E> = subscribeAlways( eventClass = eventClass, diff --git a/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/CancelScopeTest.kt b/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/CancelScopeTest.kt new file mode 100644 index 000000000..0b4717ac9 --- /dev/null +++ b/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/CancelScopeTest.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +package net.mamoe.mirai.event + +import kotlinx.coroutines.* +import net.mamoe.mirai.event.events.MemberJoinEvent +import net.mamoe.mirai.event.events.MemberMuteEvent +import org.junit.Test +import kotlin.test.assertFalse + + +internal class CancelScopeTest { + @Test + fun testCancelScope() { + val scope = CoroutineScope(SupervisorJob()) + + var got = false + scope.subscribeAlways<TestEvent> { + got = true + } + + runBlocking { + scope.coroutineContext[Job]!!.cancelAndJoin() + TestEvent().broadcast() + } + assertFalse { got } + } +} \ No newline at end of file