mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-24 14:30:09 +08:00
Deprecate Bot.subscribe*
for better Coroutine life cycle management; Add docs
This commit is contained in:
parent
5db9d1d0db
commit
0f0ca8e2cc
@ -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() }
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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())) {
|
||||
|
@ -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)
|
@ -27,6 +27,8 @@ import kotlin.reflect.KClass
|
||||
* @see subscribe 普通地监听一个事件
|
||||
* @see nextEvent 挂起当前协程, 并获取下一个事件实例
|
||||
*
|
||||
* @see syncFromEventOrNull 本函数的在超时后返回 `null` 的版本
|
||||
*
|
||||
* @throws TimeoutCancellationException 在超时后抛出.
|
||||
* @throws Throwable 当 [mapper] 抛出任何异常时, 本函数会抛出该异常
|
||||
*/
|
||||
|
@ -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(
|
||||
|
@ -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)
|
@ -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,
|
||||
|
@ -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 }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user