From a82c68c7ec202fb31191c340efd9fa1c4d9ec38f Mon Sep 17 00:00:00 2001 From: Him188 Date: Fri, 29 Jan 2021 11:21:56 +0800 Subject: [PATCH] Fix nextEvent cancellation --- .../src/commonMain/kotlin/event/nextEvent.kt | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/mirai-core-api/src/commonMain/kotlin/event/nextEvent.kt b/mirai-core-api/src/commonMain/kotlin/event/nextEvent.kt index 94cd166db..1c1afe669 100644 --- a/mirai-core-api/src/commonMain/kotlin/event/nextEvent.kt +++ b/mirai-core-api/src/commonMain/kotlin/event/nextEvent.kt @@ -73,17 +73,29 @@ internal suspend inline fun nextEventImpl( priority: EventPriority, crossinline filter: (E) -> Boolean ): E = suspendCancellableCoroutine { cont -> - coroutineScope.globalEventChannel().subscribe(eventClass, priority = priority) { - if (!filter(this)) return@subscribe ListeningStatus.LISTENING + val listener = coroutineScope.globalEventChannel() + .parentJob(coroutineScope.coroutineContext[Job]) + .subscribe(eventClass, priority = priority) { + if (!filter(this)) return@subscribe ListeningStatus.LISTENING - try { - cont.resume(this) - } catch (e: Exception) { + try { + cont.resume(this) + } catch (e: Exception) { + } + return@subscribe ListeningStatus.STOPPED } - return@subscribe ListeningStatus.STOPPED + + cont.invokeOnCancellation { + runCatching { listener.cancel("nextEvent outer scope cancelled", it) } } } +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "NOTHING_TO_INLINE") +@kotlin.internal.HidesMembers +@PublishedApi +internal inline fun EventChannel.parentJob(job: Job?): EventChannel = + if (job != null) parentJob(job) else this + @JvmSynthetic @PublishedApi internal suspend inline fun nextBotEventImpl( @@ -92,12 +104,18 @@ internal suspend inline fun nextBotEventImpl( coroutineScope: CoroutineScope, priority: EventPriority ): E = suspendCancellableCoroutine { cont -> - coroutineScope.globalEventChannel().subscribe(eventClass, priority = priority) { - try { - if (this.bot == bot) cont.resume(this) - } catch (e: Exception) { + val listener = coroutineScope.globalEventChannel() + .parentJob(coroutineScope.coroutineContext[Job]) + .subscribe(eventClass, priority = priority) { + try { + if (this.bot == bot) cont.resume(this) + } catch (e: Exception) { + } + return@subscribe ListeningStatus.STOPPED } - return@subscribe ListeningStatus.STOPPED + + cont.invokeOnCancellation { + runCatching { listener.cancel("nextEvent outer scope cancelled", it) } } } @@ -105,12 +123,14 @@ internal suspend inline fun nextBotEventImpl( @PublishedApi internal suspend inline fun withTimeoutOrCoroutineScope( timeoutMillis: Long, + useCoroutineScope: CoroutineScope? = null, noinline block: suspend CoroutineScope.() -> R ): R { require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0 " } return if (timeoutMillis == -1L) { - coroutineScope(block) + if (useCoroutineScope == null) coroutineScope(block) + else block(useCoroutineScope) } else { withTimeout(timeoutMillis, block) }