Add subscribingGet, CoroutineScope.subscribingGetAsync

This commit is contained in:
Him188 2020-02-21 22:28:57 +08:00
parent e580992e0b
commit 03c6143269
2 changed files with 104 additions and 0 deletions

View File

@ -9,3 +9,104 @@
package net.mamoe.mirai.event
import kotlinx.coroutines.*
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
/**
* 监听这个事件, 并尝试从这个事件中获取一个值.
*
* [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
* @param filter 过滤器. 返回非 null 则代表得到了需要的值. [subscribingGet] 会返回这个值
*
* @see subscribingGetAsync 本函数的异步版本
*/
@MiraiExperimentalAPI
suspend inline fun <reified E : Event, R : Any> subscribingGet(
timeoutMillis: Long = -1,
noinline filter: E.(E) -> R?
): R {
require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" }
return subscribingGetOrNull(timeoutMillis, filter) ?: error("timeout subscribingGet")
}
/**
* 监听这个事件, 并尝试从这个事件中获取一个值.
*
* [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
* @param filter 过滤器. 返回非 null 则代表得到了需要的值. [subscribingGet] 会返回这个值
*
* @see subscribingGetAsync 本函数的异步版本
*/
@MiraiExperimentalAPI
suspend inline fun <reified E : Event, R : Any> subscribingGetOrNull(
timeoutMillis: Long = -1,
noinline filter: E.(E) -> R?
): R? {
require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" }
var result: R? = null
var resultThrowable: Throwable? = null
if (timeoutMillis == -1L) {
@Suppress("DuplicatedCode") // for better performance
coroutineScope {
var listener: Listener<E>? = null
listener = this.subscribe {
val value = try {
filter.invoke(this, it)
} catch (e: Exception) {
resultThrowable = e
return@subscribe ListeningStatus.STOPPED.also { listener!!.complete() }
}
if (value != null) {
result = value
return@subscribe ListeningStatus.STOPPED.also { listener!!.complete() }
} else return@subscribe ListeningStatus.LISTENING
}
}
} else {
withTimeoutOrNull(timeoutMillis) {
var listener: Listener<E>? = null
@Suppress("DuplicatedCode") // for better performance
listener = this.subscribe {
val value = try {
filter.invoke(this, it)
} catch (e: Exception) {
resultThrowable = e
return@subscribe ListeningStatus.STOPPED.also { listener!!.complete() }
}
if (value != null) {
result = value
return@subscribe ListeningStatus.STOPPED.also { listener!!.complete() }
} else return@subscribe ListeningStatus.LISTENING
}
}
}
resultThrowable?.let { throw it }
return result
}
/**
* 异步监听这个事件, 并尝试从这个事件中获取一个值.
*
* [filter] 抛出了一个异常, [Deferred.await] 会抛出这个异常或.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
* @param coroutineContext 额外的 [CoroutineContext]
* @param filter 过滤器. 返回非 null 则代表得到了需要的值. [subscribingGet] 会返回这个值
*/
@MiraiExperimentalAPI
inline fun <reified E : Event, R : Any> CoroutineScope.subscribingGetAsync(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
timeoutMillis: Long = -1,
noinline filter: E.(E) -> R?
): Deferred<R> = this.async(coroutineContext) {
subscribingGet(timeoutMillis, filter)
}

View File

@ -101,6 +101,9 @@ interface Listener<in E : Event> : CompletableJob {
*
* @param coroutineContext 给事件监听协程的额外的 [CoroutineContext]
*
* @see subscribingGet 监听一个事件, 并尝试从这个事件中获取一个值.
* @see subscribingGetAsync 异步监听一个事件, 并尝试从这个事件中获取一个值.
*
* @see subscribeAlways 一直监听
* @see subscribeOnce 只监听一次
*