Deprecate Bot.subscribe* for better Coroutine life cycle management; Add docs

This commit is contained in:
Him188 2020-05-09 20:11:25 +08:00
parent 5db9d1d0db
commit 0f0ca8e2cc
10 changed files with 447 additions and 296 deletions

View File

@ -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() }

View File

@ -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)
}

View File

@ -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

View File

@ -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())) {

View File

@ -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)

View File

@ -27,6 +27,8 @@ import kotlin.reflect.KClass
* @see subscribe 普通地监听一个事件
* @see nextEvent 挂起当前协程, 并获取下一个事件实例
*
* @see syncFromEventOrNull 本函数的在超时后返回 `null` 的版本
*
* @throws TimeoutCancellationException 在超时后抛出.
* @throws Throwable [mapper] 抛出任何异常时, 本函数会抛出该异常
*/

View File

@ -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(

View File

@ -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)

View File

@ -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,

View File

@ -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 }
}
}