Prototype EventDispatcher

This commit is contained in:
Him188 2021-05-03 08:15:33 +08:00
parent 5d3130448c
commit b53e546743
3 changed files with 88 additions and 19 deletions

View File

@ -75,4 +75,17 @@ public fun CoroutineContext.childScopeContext(
public inline fun <E : U, U : CoroutineContext.Element> CoroutineContext.getOrElse(
key: CoroutineContext.Key<E>,
default: () -> U
): U = this[key] ?: default()
): U = this[key] ?: default()
public inline fun <E : CoroutineContext.Element> CoroutineContext.addIfAbsent(
key: CoroutineContext.Key<E>,
default: () -> CoroutineContext.Element
): CoroutineContext = if (this[key] == null) this + default() else this
public inline fun CoroutineContext.addNameIfAbsent(
name: () -> String
): CoroutineContext = addIfAbsent(CoroutineName) { CoroutineName(name()) }
public fun CoroutineContext.addNameHierarchically(
name: String
): CoroutineContext = this + CoroutineName(this[CoroutineName]?.name?.plus('.')?.plus(name) ?: name)

View File

@ -0,0 +1,70 @@
/*
* Copyright 2019-2021 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.internal.network.components
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.job
import kotlinx.coroutines.launch
import net.mamoe.mirai.event.Event
import net.mamoe.mirai.event.broadcast
import net.mamoe.mirai.internal.network.component.ComponentKey
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.addNameHierarchically
import net.mamoe.mirai.utils.childScope
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
internal interface EventDispatcher {
suspend fun broadcast(event: Event)
fun broadcastAsync(event: Event, additionalContext: CoroutineContext = EmptyCoroutineContext)
/**
* Join all jobs. Joins also jobs launched during this call.
*/
suspend fun joinBroadcast()
companion object : ComponentKey<EventDispatcher>
}
internal class EventDispatcherImpl(
private val lifecycleContext: CoroutineContext,
private val logger: MiraiLogger,
) : EventDispatcher,
CoroutineScope by lifecycleContext
.addNameHierarchically("EventDispatcher")
.childScope() {
override suspend fun broadcast(event: Event) {
try {
event.broadcast()
} catch (e: Exception) {
if (logger.isEnabled) {
val msg = optimizeEventToString(event)
logger.error(IllegalStateException("Exception while broadcasting event '$msg'", e))
}
}
}
override fun broadcastAsync(event: Event, additionalContext: CoroutineContext) {
launch(additionalContext) { broadcast(event) }
}
private fun optimizeEventToString(event: Event): String {
val qualified = event::class.java.canonicalName ?: return event.toString()
return qualified.substringAfter("net.mamoe.mirai.event.events.", "").ifEmpty { event.toString() }
}
override suspend fun joinBroadcast() {
for (child in coroutineContext.job.children) {
child.join()
}
}
}

View File

@ -11,15 +11,14 @@ package net.mamoe.mirai.internal.network.components
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import net.mamoe.mirai.event.BroadcastControllable
import net.mamoe.mirai.event.CancellableEvent
import net.mamoe.mirai.event.Event
import net.mamoe.mirai.event.broadcast
import net.mamoe.mirai.internal.QQAndroidBot
import net.mamoe.mirai.internal.network.MultiPacket
import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.internal.network.component.ComponentKey
import net.mamoe.mirai.internal.network.component.ComponentStorage
import net.mamoe.mirai.internal.network.protocol.packet.*
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.cast
@ -65,6 +64,7 @@ internal class LoggingPacketHandlerAdapter(
internal class EventBroadcasterPacketHandler(
private val targetScope: CoroutineScope,
private val components: ComponentStorage,
private val logger: MiraiLogger,
) : PacketHandler {
@ -74,7 +74,7 @@ internal class EventBroadcasterPacketHandler(
}
private val coroutineName = CoroutineName("Mirai-EventDispatcher-${logger.identity}")
private suspend fun impl(packet: Packet) {
private fun impl(packet: Packet) {
if (packet is MultiPacket<*>) {
for (p in packet) {
impl(p)
@ -84,25 +84,11 @@ internal class EventBroadcasterPacketHandler(
packet is CancellableEvent && packet.isCancelled -> return
packet is BroadcastControllable && !packet.shouldBroadcast -> return
packet is Event -> {
targetScope.launch(coroutineName) {
try {
packet.broadcast()
} catch (e: Throwable) {
if (logger.isEnabled) {
val msg = optimizeEventToString(packet)
logger.error(IllegalStateException("Exception while broadcasting event '$msg'", e))
}
}
}
components[EventDispatcher].broadcastAsync(packet)
}
}
}
private fun optimizeEventToString(event: Event): String {
val qualified = event::class.java.canonicalName ?: return this.toString()
return qualified.substringAfter("net.mamoe.mirai.event.events.")
}
override fun toString(): String = "EventBroadcasterPacketHandler"
}