Skip to content

Commit 701039e

Browse files
authored
弃用无 receiver 的事件扩展函数, 增加其 EventChannel receiver 版本替换 (#1754)
* Deprecate no-receiver functions `nextEvent*`, `syncFromEvent*`, `asyncFromEvent*`. Add their `EventChannel`-receiver counterparts. #1827 * Fix migration * Migrate `nextMessage` to new API
1 parent 6f24035 commit 701039e

File tree

9 files changed

+505
-41
lines changed

9 files changed

+505
-41
lines changed

mirai-core-api/compatibility-validation/android/api/android.api

+5
Original file line numberDiff line numberDiff line change
@@ -1789,6 +1789,11 @@ public final class net/mamoe/mirai/event/ExceptionInEventHandlerException : java
17891789
public fun getMessage ()Ljava/lang/String;
17901790
}
17911791

1792+
public final class net/mamoe/mirai/event/ExtensionsKt {
1793+
public static final fun nextEventImpl (Lnet/mamoe/mirai/event/EventChannel;Lkotlin/reflect/KClass;Lkotlinx/coroutines/CoroutineScope;Lnet/mamoe/mirai/event/EventPriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
1794+
public static final fun syncFromEventImpl (Lnet/mamoe/mirai/event/EventChannel;Lkotlin/reflect/KClass;Lkotlinx/coroutines/CoroutineScope;Lnet/mamoe/mirai/event/EventPriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
1795+
}
1796+
17921797
public final class net/mamoe/mirai/event/GlobalEventChannel : net/mamoe/mirai/event/EventChannel {
17931798
public static final field INSTANCE Lnet/mamoe/mirai/event/GlobalEventChannel;
17941799
}

mirai-core-api/compatibility-validation/jvm/api/jvm.api

+5
Original file line numberDiff line numberDiff line change
@@ -1789,6 +1789,11 @@ public final class net/mamoe/mirai/event/ExceptionInEventHandlerException : java
17891789
public fun getMessage ()Ljava/lang/String;
17901790
}
17911791

1792+
public final class net/mamoe/mirai/event/ExtensionsKt {
1793+
public static final fun nextEventImpl (Lnet/mamoe/mirai/event/EventChannel;Lkotlin/reflect/KClass;Lkotlinx/coroutines/CoroutineScope;Lnet/mamoe/mirai/event/EventPriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
1794+
public static final fun syncFromEventImpl (Lnet/mamoe/mirai/event/EventChannel;Lkotlin/reflect/KClass;Lkotlinx/coroutines/CoroutineScope;Lnet/mamoe/mirai/event/EventPriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
1795+
}
1796+
17921797
public final class net/mamoe/mirai/event/GlobalEventChannel : net/mamoe/mirai/event/EventChannel {
17931798
public static final field INSTANCE Lnet/mamoe/mirai/event/GlobalEventChannel;
17941799
}

mirai-core-api/src/commonMain/kotlin/event/EventChannel.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public open class EventChannel<out BaseEvent : Event> @JvmOverloads internal con
8181
),
8282
level = DeprecationLevel.WARNING,
8383
)
84-
@DeprecatedSinceMirai(warningSince = "2.10.0-RC")
84+
@DeprecatedSinceMirai(warningSince = "2.10")
8585
@MiraiExperimentalApi
8686
public fun asChannel(
8787
capacity: Int = Channel.RENDEZVOUS,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright 2019-2021 Mamoe Technologies and contributors.
3+
*
4+
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
5+
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
6+
*
7+
* https://github.com/mamoe/mirai/blob/dev/LICENSE
8+
*/
9+
10+
package net.mamoe.mirai.event
11+
12+
import kotlinx.coroutines.*
13+
import kotlin.coroutines.resume
14+
import kotlin.reflect.KClass
15+
16+
17+
/**
18+
* 挂起当前协程, 直到监听到事件 [E] 的广播并通过 [filter], 返回这个事件实例.
19+
*
20+
* @param filter 过滤器. 返回 `true` 时表示得到了需要的实例. 返回 `false` 时表示继续监听
21+
*
22+
* @see EventChannel.subscribe 普通地监听一个事件
23+
* @see EventChannel.syncFromEvent 挂起当前协程, 并尝试从事件中同步一个值
24+
*
25+
* @since 2.10
26+
*/
27+
public suspend inline fun <reified E : Event> EventChannel<*>.nextEvent(
28+
priority: EventPriority = EventPriority.NORMAL,
29+
noinline filter: suspend (E) -> Boolean = { true }
30+
): E = coroutineScope { this@nextEvent.nextEventImpl(E::class, this@coroutineScope, priority, filter) }
31+
32+
/**
33+
* 挂起当前协程, 监听事件 [E], 并尝试从这个事件中**获取**一个值, 在超时时抛出 [TimeoutCancellationException]
34+
*
35+
* @param mapper 过滤转换器. 返回非 null 则代表得到了需要的值. [syncFromEvent] 会返回这个值
36+
*
37+
* @see asyncFromEvent 本函数的异步版本
38+
* @see EventChannel.subscribe 普通地监听一个事件
39+
* @see nextEvent 挂起当前协程, 并获取下一个事件实例
40+
*
41+
* @see syncFromEventOrNull 本函数的在超时后返回 `null` 的版本
42+
*
43+
* @throws Throwable 当 [mapper] 抛出任何异常时, 本函数会抛出该异常
44+
*
45+
* @since 2.10
46+
*/
47+
public suspend inline fun <reified E : Event, R : Any> EventChannel<*>.syncFromEvent(
48+
priority: EventPriority = EventPriority.NORMAL,
49+
noinline mapper: suspend (E) -> R?
50+
): R = coroutineScope { this@syncFromEvent.syncFromEventImpl(E::class, this, priority, mapper) }
51+
52+
53+
/**
54+
* @since 2.10
55+
*/
56+
@PublishedApi
57+
internal suspend fun <E : Event> EventChannel<Event>.nextEventImpl(
58+
eventClass: KClass<E>,
59+
coroutineScope: CoroutineScope,
60+
priority: EventPriority,
61+
filter: suspend (E) -> Boolean
62+
): E = suspendCancellableCoroutine { cont ->
63+
var listener: Listener<E>? = null
64+
listener = parentScope(coroutineScope)
65+
.subscribe(eventClass, priority = priority) { event ->
66+
if (!filter(event)) return@subscribe ListeningStatus.LISTENING
67+
68+
try {
69+
cont.resume(event)
70+
} finally {
71+
listener?.complete() // ensure completed on exceptions
72+
}
73+
return@subscribe ListeningStatus.STOPPED
74+
}
75+
76+
cont.invokeOnCancellation {
77+
runCatching { listener.cancel("nextEvent outer scope cancelled", it) }
78+
}
79+
}
80+
81+
/**
82+
* @since 2.10
83+
*/
84+
@PublishedApi
85+
internal suspend fun <E : Event, R> EventChannel<*>.syncFromEventImpl(
86+
eventClass: KClass<E>,
87+
coroutineScope: CoroutineScope,
88+
priority: EventPriority,
89+
mapper: suspend (E) -> R?
90+
): R = suspendCancellableCoroutine { cont ->
91+
parentScope(coroutineScope).subscribe(eventClass, priority = priority) { event ->
92+
try {
93+
cont.resumeWith(kotlin.runCatching {
94+
mapper.invoke(event) ?: return@subscribe ListeningStatus.LISTENING
95+
})
96+
} catch (_: Exception) {
97+
}
98+
return@subscribe ListeningStatus.STOPPED
99+
}
100+
}

mirai-core-api/src/commonMain/kotlin/event/nextEvent.kt mirai-core-api/src/commonMain/kotlin/event/deprecated.nextEvent.kt

+58-16
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,26 @@
88
*/
99

1010
@file:Suppress("unused", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
11+
@file:JvmName("NextEventKt")
1112

1213
package net.mamoe.mirai.event
1314

1415
import kotlinx.coroutines.*
1516
import net.mamoe.mirai.Bot
1617
import net.mamoe.mirai.event.events.BotEvent
18+
import net.mamoe.mirai.utils.DeprecatedSinceMirai
1719
import kotlin.coroutines.resume
1820
import kotlin.reflect.KClass
1921

2022

2123
/**
2224
* 挂起当前协程, 直到监听到事件 [E] 的广播并通过 [filter], 返回这个事件实例.
2325
*
26+
* ### 已弃用
27+
*
28+
* 该函数相当于 [GlobalEventChannel.nextEvent].
29+
* 不一定需要将所有被弃用的 [nextEvent] 都换成 `GlobalEventChannel.nextEvent`, 请根据情况选择合适的 [EventChannel].
30+
*
2431
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制.
2532
* @param filter 过滤器. 返回 `true` 时表示得到了需要的实例. 返回 `false` 时表示继续监听
2633
*
@@ -30,21 +37,34 @@ import kotlin.reflect.KClass
3037
* @throws TimeoutCancellationException 在超时后抛出.
3138
*/
3239
@JvmSynthetic
40+
@DeprecatedSinceMirai(warningSince = "2.10")
41+
@Deprecated(
42+
"Use GlobalEventChannel.nextEvent",
43+
ReplaceWith(
44+
"if (timeoutMillis == -1L) { GlobalEventChannel.nextEvent<E>(priority, filter) } else { withTimeout(timeoutMillis) { GlobalEventChannel.nextEvent<E>(priority, filter) } }",
45+
"net.mamoe.mirai.event.GlobalEventChannel",
46+
"kotlinx.coroutines.withTimeout",
47+
),
48+
level = DeprecationLevel.WARNING
49+
)
3350
public suspend inline fun <reified E : Event> nextEvent(
3451
timeoutMillis: Long = -1,
3552
priority: EventPriority = EventPriority.MONITOR,
3653
crossinline filter: (E) -> Boolean = { true }
37-
): E {
38-
require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" }
39-
return withTimeoutOrCoroutineScope(timeoutMillis) {
40-
nextEventImpl(E::class, this, priority, filter)
41-
}
54+
): E = if (timeoutMillis == -1L) {
55+
GlobalEventChannel.nextEvent(priority) { filter(it) }
56+
} else {
57+
withTimeout(timeoutMillis) { GlobalEventChannel.nextEvent(priority) { filter(it) } }
4258
}
4359

44-
4560
/**
4661
* 挂起当前协程, 直到监听到事件 [E] 的广播并通过 [filter], 返回这个事件实例.
4762
*
63+
* ### 已弃用
64+
*
65+
* 该函数相当于 [GlobalEventChannel.nextEvent].
66+
* 不一定需要将所有被弃用的 [nextEvent] 都换成 `GlobalEventChannel.nextEvent`, 请根据情况选择合适的 [EventChannel].
67+
*
4868
* @param timeoutMillis 超时. 单位为毫秒.
4969
* @param filter 过滤器. 返回 `true` 时表示得到了需要的实例. 返回 `false` 时表示继续监听
5070
*
@@ -54,19 +74,37 @@ public suspend inline fun <reified E : Event> nextEvent(
5474
* @return 事件实例, 在超时后返回 `null`
5575
*/
5676
@JvmSynthetic
77+
@DeprecatedSinceMirai(warningSince = "2.10")
78+
@Deprecated(
79+
"Use GlobalEventChannel.nextEvent",
80+
ReplaceWith(
81+
"withTimeoutOrNull(timeoutMillis) { GlobalEventChannel.nextEvent<E>(priority, filter) }",
82+
83+
"kotlinx.coroutines.withTimeoutOrNull",
84+
"net.mamoe.mirai.event.GlobalEventChannel",
85+
"net.mamoe.mirai.event.nextEvent"
86+
),
87+
level = DeprecationLevel.WARNING
88+
)
5789
public suspend inline fun <reified E : Event> nextEventOrNull(
5890
timeoutMillis: Long,
5991
priority: EventPriority = EventPriority.MONITOR,
6092
crossinline filter: (E) -> Boolean = { true }
61-
): E? {
62-
return withTimeoutOrNull(timeoutMillis) {
63-
nextEventImpl(E::class, this, priority, filter)
64-
}
65-
}
93+
): E? = withTimeoutOrNull(timeoutMillis) { GlobalEventChannel.nextEvent(priority) { filter(it) } }
6694

6795

96+
///////////////////////////////////////////////////////////////////////////
97+
// internals
98+
///////////////////////////////////////////////////////////////////////////
99+
100+
101+
/**
102+
* @since 2.0
103+
*/
68104
@JvmSynthetic
69105
@PublishedApi
106+
@Deprecated("Kept for binary compatibility", level = DeprecationLevel.HIDDEN)
107+
@DeprecatedSinceMirai(hiddenSince = "2.10")
70108
internal suspend inline fun <E : Event> nextEventImpl(
71109
eventClass: KClass<E>,
72110
coroutineScope: CoroutineScope,
@@ -80,7 +118,7 @@ internal suspend inline fun <E : Event> nextEventImpl(
80118

81119
try {
82120
cont.resume(this)
83-
} catch (e: Exception) {
121+
} catch (_: Exception) {
84122
}
85123
return@subscribe ListeningStatus.STOPPED
86124
}
@@ -98,6 +136,7 @@ internal inline fun <BaseEvent : Event> EventChannel<BaseEvent>.parentJob(job: J
98136

99137
@JvmSynthetic
100138
@PublishedApi
139+
@Deprecated("For binary compatibility", level = DeprecationLevel.HIDDEN)
101140
internal suspend inline fun <E : BotEvent> nextBotEventImpl(
102141
bot: Bot,
103142
eventClass: KClass<E>,
@@ -109,7 +148,7 @@ internal suspend inline fun <E : BotEvent> nextBotEventImpl(
109148
.subscribe(eventClass, priority = priority) {
110149
try {
111150
if (this.bot == bot) cont.resume(this)
112-
} catch (e: Exception) {
151+
} catch (_: Exception) {
113152
}
114153
return@subscribe ListeningStatus.STOPPED
115154
}
@@ -121,10 +160,12 @@ internal suspend inline fun <E : BotEvent> nextBotEventImpl(
121160

122161
@JvmSynthetic
123162
@PublishedApi
124-
internal suspend inline fun <R> withTimeoutOrCoroutineScope(
163+
@Deprecated("Kept for binary compatibility", level = DeprecationLevel.HIDDEN)
164+
@DeprecatedSinceMirai(hiddenSince = "2.10")
165+
internal suspend fun <R> withTimeoutOrCoroutineScope(
125166
timeoutMillis: Long,
126167
useCoroutineScope: CoroutineScope? = null,
127-
noinline block: suspend CoroutineScope.() -> R
168+
block: suspend CoroutineScope.() -> R
128169
): R {
129170
require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0 " }
130171

@@ -138,7 +179,8 @@ internal suspend inline fun <R> withTimeoutOrCoroutineScope(
138179

139180
@JvmSynthetic
140181
@PublishedApi
141-
@Deprecated("For binary compatibility", level = DeprecationLevel.HIDDEN)
182+
@Deprecated("Kept for binary compatibility", level = DeprecationLevel.HIDDEN)
183+
@DeprecatedSinceMirai(hiddenSince = "2.10")
142184
internal suspend inline fun <R> withTimeoutOrCoroutineScope(
143185
timeoutMillis: Long,
144186
noinline block: suspend CoroutineScope.() -> R

0 commit comments

Comments
 (0)