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