Broadcast BotReloginEvent stably

This commit is contained in:
Him188 2021-06-24 01:04:03 +08:00
parent b8de3f77ff
commit b02fa15b33
2 changed files with 33 additions and 4 deletions

View File

@ -43,7 +43,9 @@ import net.mamoe.mirai.internal.network.handler.state.safe
import net.mamoe.mirai.internal.network.impl.netty.ForceOfflineException
import net.mamoe.mirai.internal.network.impl.netty.NettyNetworkHandlerFactory
import net.mamoe.mirai.internal.utils.subLogger
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.lateinitMutableProperty
import kotlin.contracts.contract
internal fun Bot.asQQAndroidBot(): QQAndroidBot {
@ -91,10 +93,10 @@ internal open class QQAndroidBot constructor(
previous: BaseStateImpl,
new: BaseStateImpl
) {
eventDispatcher.broadcastAsync(BotOnlineEvent(bot)).onSuccess {
eventDispatcher.broadcastAsync(BotOnlineEvent(bot)).thenBroadcast(eventDispatcher) {
if (!shouldBroadcastRelogin.compareAndSet(false, true)) {
eventDispatcher.broadcastAsync(BotReloginEvent(bot, new.getCause()))
}
BotReloginEvent(bot, new.getCause())
} else null
}
}

View File

@ -34,6 +34,14 @@ internal interface EventDispatcher {
*/
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?,
): EventBroadcastJob
/**
* Join all jobs. Joins also jobs launched during this call.
*/
@ -58,6 +66,13 @@ internal value class EventBroadcastJob(
if (it == null) action()
}
}
inline fun thenBroadcast(eventDispatcher: EventDispatcher, crossinline event: suspend () -> Event?) {
eventDispatcher.broadcastAsync {
job.join()
event()
}
}
}
@ -93,6 +108,18 @@ internal open class EventDispatcherImpl(
return EventBroadcastJob(job)
}
override fun broadcastAsync(additionalContext: CoroutineContext, event: suspend () -> Event?): EventBroadcastJob {
val job = launch(
additionalContext + EventDispatcherScopeFlag,
start = CoroutineStart.UNDISPATCHED
) {
event()?.let { broadcast(it) }
}
// UNDISPATCHED: starts the coroutine NOW in the current thread until its first suspension point,
// so that after `broadcastAsync` the job is always already started and `joinBroadcast` will work normally.
return EventBroadcastJob(job)
}
protected 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() }