mirror of
https://github.com/mamoe/mirai.git
synced 2025-04-25 21:12:40 +08:00
Fix event broadcast directly without checks. Add notes for broadcasting an event.
This commit is contained in:
parent
f83d20bed9
commit
4495e36e7c
mirai-core-api/src/commonMain/kotlin/event
mirai-core/src/commonMain/kotlin
@ -64,7 +64,7 @@ public fun CoroutineScope.globalEventChannel(coroutineContext: CoroutineContext
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.11
|
||||
* @since 2.12
|
||||
*/
|
||||
@MiraiInternalApi
|
||||
public interface InternalGlobalEventChannelProvider {
|
||||
|
@ -14,8 +14,6 @@ import io.ktor.client.engine.okhttp.*
|
||||
import io.ktor.client.features.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.request.forms.*
|
||||
import io.ktor.util.*
|
||||
import kotlinx.coroutines.currentCoroutineContext
|
||||
import kotlinx.io.core.discardExact
|
||||
import kotlinx.io.core.readBytes
|
||||
import kotlinx.serialization.json.Json
|
||||
@ -34,6 +32,7 @@ import net.mamoe.mirai.internal.contact.info.FriendInfoImpl.Companion.impl
|
||||
import net.mamoe.mirai.internal.contact.info.MemberInfoImpl
|
||||
import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl.Companion.impl
|
||||
import net.mamoe.mirai.internal.event.EventChannelToEventDispatcherAdapter
|
||||
import net.mamoe.mirai.internal.event.InternalEventMechanism
|
||||
import net.mamoe.mirai.internal.message.*
|
||||
import net.mamoe.mirai.internal.message.DeepMessageRefiner.refineDeep
|
||||
import net.mamoe.mirai.internal.network.components.EventDispatcher
|
||||
@ -299,6 +298,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
override suspend fun ignoreInvitedJoinGroupRequest(event: BotInvitedJoinGroupRequestEvent) =
|
||||
solveInvitedJoinGroupRequest(event, accept = false)
|
||||
|
||||
@OptIn(InternalEventMechanism::class)
|
||||
override suspend fun broadcastEvent(event: Event) {
|
||||
if (event is BotEvent) {
|
||||
val bot = event.bot
|
||||
@ -306,7 +306,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
bot.components[EventDispatcher].broadcast(event)
|
||||
}
|
||||
} else {
|
||||
EventChannelToEventDispatcherAdapter.instance.callListeners(event)
|
||||
EventChannelToEventDispatcherAdapter.instance.broadcastEventImpl(event)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ import net.mamoe.mirai.event.*
|
||||
import net.mamoe.mirai.event.events.BotEvent
|
||||
import net.mamoe.mirai.event.events.MessageEvent
|
||||
import net.mamoe.mirai.internal.network.Packet
|
||||
import net.mamoe.mirai.internal.network.components.EventDispatcher
|
||||
import net.mamoe.mirai.internal.network.components.SHOW_VERBOSE_EVENT
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.verbose
|
||||
@ -27,14 +28,27 @@ import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
// You probably should only use EventChannelToEventDispatcherAdapter.instance, or just use EventDispatchers. Event.broadcast is also good to use internally!
|
||||
// See docs below
|
||||
@RequiresOptIn(
|
||||
"Every EventChannelImpl has dedicated EventListeners registries. Use the constructor only when you know what you are doing.",
|
||||
"You must not use this API unless you are writing Event infrastructure.",
|
||||
level = RequiresOptIn.Level.ERROR
|
||||
)
|
||||
internal annotation class DangerousEventChannelImplConstructor
|
||||
internal annotation class InternalEventMechanism
|
||||
|
||||
internal open class EventChannelImpl<E : Event> @DangerousEventChannelImplConstructor constructor(
|
||||
// Note: You probably should only use EventChannelToEventDispatcherAdapter.instance, or just use EventDispatchers. Event.broadcast is also good to use internally!
|
||||
/**
|
||||
* Implementation of [EventChannel]. Every [EventChannelImpl] holds its own list of listeners, so one [EventChannelImpl] instance, [EventChannelToEventDispatcherAdapter] is shared in mirai.
|
||||
*
|
||||
* ## Broadcasting an event
|
||||
*
|
||||
* You should first consider using [EventDispatcher.broadcast] or [EventDispatcher.broadcastAsync].
|
||||
* Use [Event.broadcast] if you have no access to [EventDispatcher] (though you should have).
|
||||
*
|
||||
* Note: using [Event.broadcast] for [BotEvent] is the same as using [EventDispatcher.broadcast] but the former is slower. So it's recommended to use [EventDispatcher].
|
||||
*
|
||||
* **Never ever** use [EventChannelToEventDispatcherAdapter.instance] directly.
|
||||
*/
|
||||
internal sealed class EventChannelImpl<E : Event> constructor(
|
||||
baseEventClass: KClass<out E>, defaultCoroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||
) : EventChannel<E>(baseEventClass, defaultCoroutineContext) {
|
||||
private val eventListeners = EventListeners()
|
||||
@ -46,7 +60,26 @@ internal open class EventChannelImpl<E : Event> @DangerousEventChannelImplConstr
|
||||
private val logger by lazy { MiraiLogger.Factory.create(EventChannelImpl::class, "EventChannelImpl") }
|
||||
}
|
||||
|
||||
suspend fun callListeners(event: Event) {
|
||||
/**
|
||||
* Basic entrance for broadcasting an event.
|
||||
*/
|
||||
@InternalEventMechanism
|
||||
suspend fun <E : Event> broadcastEventImpl(event: E): E {
|
||||
require(event is AbstractEvent) { "Events must extend AbstractEvent" }
|
||||
|
||||
if (event is BroadcastControllable && !event.shouldBroadcast) {
|
||||
return event
|
||||
}
|
||||
event.broadCastLock.withLock {
|
||||
event._intercepted = false
|
||||
callListeners(event)
|
||||
}
|
||||
|
||||
return event
|
||||
}
|
||||
|
||||
@InternalEventMechanism
|
||||
private suspend fun callListeners(event: Event) {
|
||||
event as AbstractEvent
|
||||
logEvent(event)
|
||||
eventListeners.callListeners(event)
|
||||
@ -78,21 +111,6 @@ internal open class EventChannelImpl<E : Event> @DangerousEventChannelImplConstr
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private suspend fun <E : Event> broadcastImpl(event: E): E {
|
||||
check(event is AbstractEvent) { "Events must extend AbstractEvent" }
|
||||
|
||||
if (event is BroadcastControllable && !event.shouldBroadcast) {
|
||||
return event
|
||||
}
|
||||
event.broadCastLock.withLock {
|
||||
event._intercepted = false
|
||||
callListeners(event)
|
||||
}
|
||||
|
||||
return event
|
||||
}
|
||||
|
||||
private fun isVerboseEvent(event: Event): Boolean {
|
||||
if (SHOW_VERBOSE_EVENT) return false
|
||||
if (event is VerboseEvent) {
|
||||
|
@ -14,11 +14,11 @@ import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@OptIn(DangerousEventChannelImplConstructor::class)
|
||||
internal class EventChannelToEventDispatcherAdapter<E : Event> private constructor(
|
||||
baseEventClass: KClass<out E>, defaultCoroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||
) : EventChannelImpl<E>(baseEventClass, defaultCoroutineContext) {
|
||||
companion object {
|
||||
@InternalEventMechanism
|
||||
val instance by lazy { EventChannelToEventDispatcherAdapter(Event::class, EmptyCoroutineContext) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,11 @@ import net.mamoe.mirai.event.Event
|
||||
import net.mamoe.mirai.event.EventChannel
|
||||
import net.mamoe.mirai.event.InternalGlobalEventChannelProvider
|
||||
|
||||
@InternalEventMechanism
|
||||
internal class GlobalEventChannelProviderImpl : InternalGlobalEventChannelProvider {
|
||||
@InternalEventMechanism
|
||||
val instance = EventChannelToEventDispatcherAdapter.instance
|
||||
|
||||
@OptIn(InternalEventMechanism::class)
|
||||
override fun getInstance(): EventChannel<Event> = instance
|
||||
}
|
@ -10,11 +10,13 @@
|
||||
package net.mamoe.mirai.internal.network.components
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import net.mamoe.mirai.event.*
|
||||
import net.mamoe.mirai.event.Event
|
||||
import net.mamoe.mirai.event.EventChannel
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.internal.event.EventChannelToEventDispatcherAdapter
|
||||
import net.mamoe.mirai.internal.event.InternalEventMechanism
|
||||
import net.mamoe.mirai.internal.network.component.ComponentKey
|
||||
import net.mamoe.mirai.utils.*
|
||||
import java.util.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
@ -25,18 +27,12 @@ internal interface EventDispatcher {
|
||||
val isActive: Boolean
|
||||
|
||||
/**
|
||||
* Implement [Event.broadcast]
|
||||
* Broadcast an event using [EventChannel]. It's safe to use this function internally.
|
||||
*/
|
||||
suspend fun broadcast(event: Event)
|
||||
|
||||
/**
|
||||
* Implementor must call `event.broadcast()` within a coroutine with [EventDispatcherScopeFlag]
|
||||
*/
|
||||
fun broadcastAsync(event: Event, additionalContext: CoroutineContext = EmptyCoroutineContext): EventBroadcastJob
|
||||
|
||||
/**
|
||||
* Implementor must call `event.broadcast()` within a coroutine with [EventDispatcherScopeFlag]
|
||||
*/
|
||||
fun broadcastAsync(
|
||||
additionalContext: CoroutineContext = EmptyCoroutineContext,
|
||||
event: suspend () -> Event?,
|
||||
@ -96,9 +92,10 @@ internal open class EventDispatcherImpl(
|
||||
override val isActive: Boolean
|
||||
get() = this.coroutineContext.isActive
|
||||
|
||||
@OptIn(InternalEventMechanism::class)
|
||||
override suspend fun broadcast(event: Event) {
|
||||
try {
|
||||
EventChannelToEventDispatcherAdapter.instance.callListeners(event)
|
||||
EventChannelToEventDispatcherAdapter.instance.broadcastEventImpl(event)
|
||||
} catch (e: Exception) {
|
||||
if (e is CancellationException) return
|
||||
if (logger.isEnabled) {
|
||||
|
Loading…
Reference in New Issue
Block a user