mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-20 20:49:54 +08:00
Improve logging
This commit is contained in:
parent
5fa54114c1
commit
a7a4879d05
@ -15,7 +15,8 @@ import kotlinx.coroutines.runBlocking
|
|||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import net.mamoe.mirai.event.events.BotEvent
|
import net.mamoe.mirai.event.events.BotEvent
|
||||||
import net.mamoe.mirai.internal.event.broadcastInternal
|
import net.mamoe.mirai.event.events.MessageEvent
|
||||||
|
import net.mamoe.mirai.internal.event.callAndRemoveIfRequired
|
||||||
import net.mamoe.mirai.internal.network.Packet
|
import net.mamoe.mirai.internal.network.Packet
|
||||||
import net.mamoe.mirai.utils.JavaFriendlyAPI
|
import net.mamoe.mirai.utils.JavaFriendlyAPI
|
||||||
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||||
@ -143,26 +144,32 @@ public interface CancellableEvent : Event {
|
|||||||
* @see __broadcastJava Java 使用
|
* @see __broadcastJava Java 使用
|
||||||
*/
|
*/
|
||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
public suspend fun <E : Event> E.broadcast(): E = apply {
|
public suspend fun <E : Event> E.broadcast(): E {
|
||||||
check(this is AbstractEvent) {
|
check(this is AbstractEvent) {
|
||||||
"Events must extend AbstractEvent"
|
"Events must extend AbstractEvent"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this is BroadcastControllable && !this.shouldBroadcast) {
|
if (this is BroadcastControllable && !this.shouldBroadcast) {
|
||||||
return@apply
|
return this
|
||||||
}
|
}
|
||||||
this.broadCastLock.withLock {
|
this.broadCastLock.withLock {
|
||||||
this._intercepted = false
|
this._intercepted = false
|
||||||
if (EventDisabled) return@withLock
|
if (EventDisabled) return@withLock
|
||||||
if (this is Packet.NoEventLog) return@withLock
|
if (this is Packet.NoEventLog) return@withLock
|
||||||
if (this is Packet) return@withLock // all [Packet]s are logged in [LoggingPacketHandler]
|
if (this is Packet.NoLog) return@withLock
|
||||||
|
if (this is MessageEvent) return@withLock // specially handled in [LoggingPacketHandlerAdapter]
|
||||||
|
// if (this is Packet) return@withLock // all [Packet]s are logged in [LoggingPacketHandlerAdapter]
|
||||||
|
|
||||||
if (this is BotEvent) {
|
if (this is BotEvent) {
|
||||||
this.bot.logger.verbose { "Event: $this" }
|
this.bot.logger.verbose { "Event: $this" }
|
||||||
} else {
|
} else {
|
||||||
MiraiLogger.TopLevel.verbose { "Event: $this" }
|
MiraiLogger.TopLevel.verbose { "Event: $this" }
|
||||||
}
|
}
|
||||||
this.broadcastInternal() // inline, no extra cost
|
|
||||||
|
callAndRemoveIfRequired(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,66 +97,53 @@ internal object GlobalEventListeners {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// inline: NO extra Continuation
|
internal suspend fun <E : AbstractEvent> callAndRemoveIfRequired(event: E) {
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
internal suspend inline fun AbstractEvent.broadcastInternal() {
|
|
||||||
callAndRemoveIfRequired(this@broadcastInternal)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal inline fun <E, T : Iterable<E>> T.forEach0(block: T.(E) -> Unit) {
|
|
||||||
forEach { block(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("DuplicatedCode")
|
|
||||||
internal suspend inline fun <E : AbstractEvent> callAndRemoveIfRequired(
|
|
||||||
event: E
|
|
||||||
) {
|
|
||||||
for (p in EventPriority.prioritiesExcludedMonitor) {
|
for (p in EventPriority.prioritiesExcludedMonitor) {
|
||||||
GlobalEventListeners[p].forEach0 { registeredRegistry ->
|
val container = GlobalEventListeners[p]
|
||||||
if (event.isIntercepted) {
|
for (registry in container) {
|
||||||
return
|
if (event.isIntercepted) return
|
||||||
}
|
if (!registry.type.isInstance(event)) continue
|
||||||
if (!registeredRegistry.type.isInstance(event)) return@forEach0
|
val listener = registry.listener
|
||||||
val listener = registeredRegistry.listener
|
process(container, registry, listener, event)
|
||||||
when (listener.concurrencyKind) {
|
}
|
||||||
ConcurrencyKind.LOCKED -> {
|
}
|
||||||
(listener as Handler).lock!!.withLock {
|
|
||||||
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
if (event.isIntercepted) return
|
||||||
remove(registeredRegistry)
|
val container = GlobalEventListeners[EventPriority.MONITOR]
|
||||||
}
|
when (container.size) {
|
||||||
}
|
0 -> return
|
||||||
}
|
1 -> {
|
||||||
ConcurrencyKind.CONCURRENT -> {
|
val registry = container.firstOrNull() ?: return
|
||||||
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
if (!registry.type.isInstance(event)) return
|
||||||
remove(registeredRegistry)
|
process(container, registry, registry.listener, event)
|
||||||
}
|
}
|
||||||
}
|
else -> supervisorScope {
|
||||||
|
for (registry in GlobalEventListeners[EventPriority.MONITOR]) {
|
||||||
|
if (!registry.type.isInstance(event)) continue
|
||||||
|
launch { process(container, registry, registry.listener, event) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
coroutineScope {
|
}
|
||||||
GlobalEventListeners[EventPriority.MONITOR].forEach0 { registeredRegistry ->
|
|
||||||
if (event.isIntercepted) {
|
private suspend fun <E : AbstractEvent> process(
|
||||||
return@coroutineScope
|
container: ConcurrentLinkedQueue<ListenerRegistry>,
|
||||||
}
|
registry: ListenerRegistry,
|
||||||
if (!registeredRegistry.type.isInstance(event)) return@forEach0
|
listener: Listener<Event>,
|
||||||
val listener = registeredRegistry.listener
|
event: E,
|
||||||
launch {
|
) {
|
||||||
when (listener.concurrencyKind) {
|
when (listener.concurrencyKind) {
|
||||||
ConcurrencyKind.LOCKED -> {
|
ConcurrencyKind.LOCKED -> {
|
||||||
(listener as Handler).lock!!.withLock {
|
(listener as Handler).lock!!.withLock {
|
||||||
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
||||||
remove(registeredRegistry)
|
container.remove(registry)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ConcurrencyKind.CONCURRENT -> {
|
|
||||||
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
|
||||||
remove(registeredRegistry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ConcurrencyKind.CONCURRENT -> {
|
||||||
|
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
||||||
|
container.remove(registry)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,7 +27,7 @@ import java.util.*
|
|||||||
*
|
*
|
||||||
* 示例:
|
* 示例:
|
||||||
* ```log
|
* ```log
|
||||||
* 2020-05-21 19:51:09 V/Bot 1994701021: Send: OidbSvc.0x88d_7
|
* 2020-05-21 19:51:09 V/Bot 123456789: Send: OidbSvc.0x88d_7
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* 日期时间格式为 `yyyy-MM-dd HH:mm:ss`,
|
* 日期时间格式为 `yyyy-MM-dd HH:mm:ss`,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||||
*
|
*
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
* 此源代码的使用受 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.
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
@ -234,7 +234,7 @@ public inline fun MiraiLogger.error(message: () -> String?, e: Throwable?) {
|
|||||||
*
|
*
|
||||||
* 示例:
|
* 示例:
|
||||||
* ```log
|
* ```log
|
||||||
* 2020-05-21 19:51:09 V/Bot 1994701021: Send: OidbSvc.0x88d_7
|
* 2020-05-21 19:51:09 V/Bot 123456789: Send: OidbSvc.0x88d_7
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* 日期时间格式为 `yyyy-MM-dd HH:mm:ss`,
|
* 日期时间格式为 `yyyy-MM-dd HH:mm:ss`,
|
||||||
|
@ -27,7 +27,7 @@ import java.util.*
|
|||||||
*
|
*
|
||||||
* 示例:
|
* 示例:
|
||||||
* ```log
|
* ```log
|
||||||
* 2020-05-21 19:51:09 V/Bot 1994701021: Send: OidbSvc.0x88d_7
|
* 2020-05-21 19:51:09 V/Bot 123456789: Send: OidbSvc.0x88d_7
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* 日期时间格式为 `yyyy-MM-dd HH:mm:ss`,
|
* 日期时间格式为 `yyyy-MM-dd HH:mm:ss`,
|
||||||
|
@ -163,9 +163,10 @@ internal open class QQAndroidBot constructor(
|
|||||||
set(ContactUpdater, ContactUpdaterImpl(bot, components, networkLogger))
|
set(ContactUpdater, ContactUpdaterImpl(bot, components, networkLogger))
|
||||||
set(BdhSessionSyncer, BdhSessionSyncerImpl(configuration, networkLogger, components))
|
set(BdhSessionSyncer, BdhSessionSyncerImpl(configuration, networkLogger, components))
|
||||||
set(ServerList, ServerListImpl())
|
set(ServerList, ServerListImpl())
|
||||||
|
set(PacketLoggingStrategy, PacketLoggingStrategyImpl(bot))
|
||||||
set(
|
set(
|
||||||
PacketHandler, PacketHandlerChain(
|
PacketHandler, PacketHandlerChain(
|
||||||
LoggingPacketHandler(bot, networkLogger),
|
LoggingPacketHandlerAdapter(networkLogger, get(PacketLoggingStrategy)),
|
||||||
EventBroadcasterPacketHandler(networkLogger),
|
EventBroadcasterPacketHandler(networkLogger),
|
||||||
CallPacketFactoryPacketHandler(bot)
|
CallPacketFactoryPacketHandler(bot)
|
||||||
)
|
)
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.internal.network
|
package net.mamoe.mirai.internal.network
|
||||||
|
|
||||||
import net.mamoe.mirai.internal.QQAndroidBot
|
import net.mamoe.mirai.internal.AbstractBot
|
||||||
import net.mamoe.mirai.internal.network.handler.logger
|
import net.mamoe.mirai.internal.network.handler.logger
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
|
|
||||||
@ -52,12 +52,12 @@ internal class ParseErrorPacket(
|
|||||||
) : Packet, Packet.NoLog {
|
) : Packet, Packet.NoLog {
|
||||||
enum class Direction {
|
enum class Direction {
|
||||||
TO_BOT_LOGGER {
|
TO_BOT_LOGGER {
|
||||||
override fun getLogger(bot: QQAndroidBot): MiraiLogger = bot.logger
|
override fun getLogger(bot: AbstractBot): MiraiLogger = bot.logger
|
||||||
},
|
},
|
||||||
TO_NETWORK_LOGGER {
|
TO_NETWORK_LOGGER {
|
||||||
override fun getLogger(bot: QQAndroidBot): MiraiLogger = bot.network.logger
|
override fun getLogger(bot: AbstractBot): MiraiLogger = bot.network.logger
|
||||||
};
|
};
|
||||||
|
|
||||||
abstract fun getLogger(bot: QQAndroidBot): MiraiLogger
|
abstract fun getLogger(bot: AbstractBot): MiraiLogger
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,17 +13,13 @@ 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.event.broadcast
|
||||||
import net.mamoe.mirai.event.events.MessageEvent
|
|
||||||
import net.mamoe.mirai.internal.QQAndroidBot
|
import net.mamoe.mirai.internal.QQAndroidBot
|
||||||
import net.mamoe.mirai.internal.contact.logMessageReceived
|
import net.mamoe.mirai.internal.network.MultiPacket
|
||||||
import net.mamoe.mirai.internal.contact.replaceMagicCodes
|
|
||||||
import net.mamoe.mirai.internal.network.Packet
|
import net.mamoe.mirai.internal.network.Packet
|
||||||
import net.mamoe.mirai.internal.network.ParseErrorPacket
|
|
||||||
import net.mamoe.mirai.internal.network.component.ComponentKey
|
import net.mamoe.mirai.internal.network.component.ComponentKey
|
||||||
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
|
||||||
import net.mamoe.mirai.utils.verbose
|
|
||||||
|
|
||||||
internal interface PacketHandler {
|
internal interface PacketHandler {
|
||||||
suspend fun handlePacket(incomingPacket: IncomingPacket)
|
suspend fun handlePacket(incomingPacket: IncomingPacket)
|
||||||
@ -53,29 +49,15 @@ internal data class ExceptionInPacketHandlerException(
|
|||||||
override val cause: Throwable,
|
override val cause: Throwable,
|
||||||
) : IllegalStateException("Exception in PacketHandler '$packetHandler'.")
|
) : IllegalStateException("Exception in PacketHandler '$packetHandler'.")
|
||||||
|
|
||||||
internal class LoggingPacketHandler(
|
internal class LoggingPacketHandlerAdapter(
|
||||||
private val bot: QQAndroidBot,
|
|
||||||
private val logger: MiraiLogger,
|
private val logger: MiraiLogger,
|
||||||
|
private val strategy: PacketLoggingStrategy,
|
||||||
) : PacketHandler {
|
) : PacketHandler {
|
||||||
override suspend fun handlePacket(incomingPacket: IncomingPacket) {
|
override suspend fun handlePacket(incomingPacket: IncomingPacket) {
|
||||||
val packet = incomingPacket.data ?: return
|
strategy.logReceived(logger, incomingPacket)
|
||||||
if (!bot.logger.isEnabled && !logger.isEnabled) return
|
|
||||||
when {
|
|
||||||
packet is ParseErrorPacket -> {
|
|
||||||
packet.direction.getLogger(bot).error(packet.error)
|
|
||||||
}
|
|
||||||
packet is MessageEvent -> packet.logMessageReceived()
|
|
||||||
packet is Packet.NoLog -> {
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
packet is Event && packet !is Packet.NoEventLog -> bot.logger.verbose {
|
|
||||||
"Event: $packet".replaceMagicCodes()
|
|
||||||
}
|
|
||||||
else -> logger.verbose { "Recv: ${incomingPacket.commandName} ${incomingPacket.data}".replaceMagicCodes() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String = "LoggingPacketHandler"
|
override fun toString(): String = "LoggingPacketHandlerAdapter"
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class EventBroadcasterPacketHandler(
|
internal class EventBroadcasterPacketHandler(
|
||||||
@ -83,7 +65,16 @@ internal class EventBroadcasterPacketHandler(
|
|||||||
) : PacketHandler {
|
) : PacketHandler {
|
||||||
|
|
||||||
override suspend fun handlePacket(incomingPacket: IncomingPacket) {
|
override suspend fun handlePacket(incomingPacket: IncomingPacket) {
|
||||||
val packet = incomingPacket.data ?: return
|
val data = incomingPacket.data ?: return
|
||||||
|
impl(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun impl(packet: Packet) {
|
||||||
|
if (packet is MultiPacket<*>) {
|
||||||
|
for (p in packet) {
|
||||||
|
impl(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
when {
|
when {
|
||||||
packet is CancellableEvent && packet.isCancelled -> return
|
packet is CancellableEvent && packet.isCancelled -> return
|
||||||
packet is BroadcastControllable && !packet.shouldBroadcast -> return
|
packet is BroadcastControllable && !packet.shouldBroadcast -> return
|
||||||
@ -105,7 +96,7 @@ internal class EventBroadcasterPacketHandler(
|
|||||||
return qualified.substringAfter("net.mamoe.mirai.event.events.")
|
return qualified.substringAfter("net.mamoe.mirai.event.events.")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String = "LoggingPacketHandler"
|
override fun toString(): String = "EventBroadcasterPacketHandler"
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class CallPacketFactoryPacketHandler(
|
internal class CallPacketFactoryPacketHandler(
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* 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 net.mamoe.mirai.event.Event
|
||||||
|
import net.mamoe.mirai.event.events.MessageEvent
|
||||||
|
import net.mamoe.mirai.internal.AbstractBot
|
||||||
|
import net.mamoe.mirai.internal.contact.logMessageReceived
|
||||||
|
import net.mamoe.mirai.internal.contact.replaceMagicCodes
|
||||||
|
import net.mamoe.mirai.internal.network.Packet
|
||||||
|
import net.mamoe.mirai.internal.network.ParseErrorPacket
|
||||||
|
import net.mamoe.mirai.internal.network.component.ComponentKey
|
||||||
|
import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacket
|
||||||
|
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
|
||||||
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
|
import net.mamoe.mirai.utils.systemProp
|
||||||
|
import net.mamoe.mirai.utils.verbose
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation must be fast and non-blocking, throwing no exception.
|
||||||
|
*/
|
||||||
|
internal interface PacketLoggingStrategy {
|
||||||
|
fun logSent(logger: MiraiLogger, outgoingPacket: OutgoingPacket)
|
||||||
|
fun logReceived(logger: MiraiLogger, incomingPacket: IncomingPacket)
|
||||||
|
|
||||||
|
companion object : ComponentKey<PacketLoggingStrategy>
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class PacketLoggingStrategyImpl(
|
||||||
|
private val bot: AbstractBot,
|
||||||
|
private val blacklist: Set<String> = DEFAULT_BLACKLIST,
|
||||||
|
) : PacketLoggingStrategy {
|
||||||
|
override fun logSent(logger: MiraiLogger, outgoingPacket: OutgoingPacket) {
|
||||||
|
if (outgoingPacket.commandName in blacklist) return
|
||||||
|
logger.verbose { "Send: ${outgoingPacket.commandName}" }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun logReceived(logger: MiraiLogger, incomingPacket: IncomingPacket) {
|
||||||
|
val packet = incomingPacket.data ?: return
|
||||||
|
if (!bot.logger.isEnabled && !logger.isEnabled) return
|
||||||
|
when {
|
||||||
|
packet is ParseErrorPacket -> {
|
||||||
|
packet.direction.getLogger(bot).error(packet.error)
|
||||||
|
}
|
||||||
|
packet is MessageEvent -> packet.logMessageReceived()
|
||||||
|
packet is Packet.NoLog -> {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
packet is Event && packet !is Packet.NoEventLog -> bot.logger.verbose {
|
||||||
|
"Event: $packet".replaceMagicCodes()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
if (SHOW_PACKET_DETAILS) {
|
||||||
|
logger.verbose { "Recv: ${incomingPacket.commandName} ${incomingPacket.data}".replaceMagicCodes() }
|
||||||
|
} else {
|
||||||
|
logger.verbose { "Recv: ${incomingPacket.commandName}".replaceMagicCodes() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmField
|
||||||
|
val DEFAULT_BLACKLIST = setOf(
|
||||||
|
"MessageSvc.PbDeleteMsg",
|
||||||
|
"MessageSvc.PbGetMsg", // they are too verbose.
|
||||||
|
"OnlinePush.RespPush"
|
||||||
|
)
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var SHOW_PACKET_DETAILS = systemProp("mirai.debug.network.show.packet.details", false)
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.internal.network.handler
|
package net.mamoe.mirai.internal.network.handler
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.selects.SelectClause1
|
import kotlinx.coroutines.selects.SelectClause1
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.internal.network.Packet
|
import net.mamoe.mirai.internal.network.Packet
|
||||||
@ -30,7 +31,7 @@ import net.mamoe.mirai.utils.MiraiLogger
|
|||||||
* @see NetworkHandlerSupport
|
* @see NetworkHandlerSupport
|
||||||
* @see NetworkHandlerFactory
|
* @see NetworkHandlerFactory
|
||||||
*/
|
*/
|
||||||
internal interface NetworkHandler {
|
internal interface NetworkHandler : CoroutineScope {
|
||||||
val context: NetworkHandlerContext
|
val context: NetworkHandlerContext
|
||||||
|
|
||||||
fun isOk() = state == State.OK
|
fun isOk() = state == State.OK
|
||||||
|
@ -14,6 +14,7 @@ import kotlinx.coroutines.selects.SelectClause1
|
|||||||
import net.mamoe.mirai.internal.network.Packet
|
import net.mamoe.mirai.internal.network.Packet
|
||||||
import net.mamoe.mirai.internal.network.components.PacketCodec
|
import net.mamoe.mirai.internal.network.components.PacketCodec
|
||||||
import net.mamoe.mirai.internal.network.components.PacketHandler
|
import net.mamoe.mirai.internal.network.components.PacketHandler
|
||||||
|
import net.mamoe.mirai.internal.network.components.PacketLoggingStrategy
|
||||||
import net.mamoe.mirai.internal.network.components.RawIncomingPacket
|
import net.mamoe.mirai.internal.network.components.RawIncomingPacket
|
||||||
import net.mamoe.mirai.internal.network.handler.state.StateObserver
|
import net.mamoe.mirai.internal.network.handler.state.StateObserver
|
||||||
import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacket
|
import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacket
|
||||||
@ -69,7 +70,7 @@ internal abstract class NetworkHandlerSupport(
|
|||||||
val listener = PacketListener(packet.commandName, packet.sequenceId)
|
val listener = PacketListener(packet.commandName, packet.sequenceId)
|
||||||
var exception: Throwable? = null
|
var exception: Throwable? = null
|
||||||
repeat(attempts.coerceAtLeast(1)) {
|
repeat(attempts.coerceAtLeast(1)) {
|
||||||
logger.verbose { "Send: ${packet.commandName}" }
|
context[PacketLoggingStrategy].logSent(logger, packet)
|
||||||
try {
|
try {
|
||||||
packetListeners.add(listener)
|
packetListeners.add(listener)
|
||||||
sendPacketImpl(packet)
|
sendPacketImpl(packet)
|
||||||
@ -92,7 +93,7 @@ internal abstract class NetworkHandlerSupport(
|
|||||||
}
|
}
|
||||||
|
|
||||||
final override suspend fun sendWithoutExpect(packet: OutgoingPacket) {
|
final override suspend fun sendWithoutExpect(packet: OutgoingPacket) {
|
||||||
logger.verbose { "Send: ${packet.commandName}" }
|
context[PacketLoggingStrategy].logSent(logger, packet)
|
||||||
sendPacketImpl(packet)
|
sendPacketImpl(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +103,7 @@ internal abstract class NetworkHandlerSupport(
|
|||||||
// } else {
|
// } else {
|
||||||
// logger.info { "NetworkHandler '$this' closed: $cause" }
|
// logger.info { "NetworkHandler '$this' closed: $cause" }
|
||||||
// }
|
// }
|
||||||
coroutineContext.job.cancel("NetworkHandler closed.", cause)
|
coroutineContext.job.cancel("NetworkHandler closed", cause)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected val packetLogger: MiraiLogger by lazy {
|
protected val packetLogger: MiraiLogger by lazy {
|
||||||
|
@ -18,6 +18,7 @@ import net.mamoe.mirai.internal.network.handler.NetworkHandler
|
|||||||
import net.mamoe.mirai.internal.network.handler.NetworkHandler.State
|
import net.mamoe.mirai.internal.network.handler.NetworkHandler.State
|
||||||
import net.mamoe.mirai.internal.network.handler.NetworkHandlerContext
|
import net.mamoe.mirai.internal.network.handler.NetworkHandlerContext
|
||||||
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
|
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A proxy to [NetworkHandler] that delegates calls to instance returned by [NetworkHandlerSelector.awaitResumeInstance].
|
* A proxy to [NetworkHandler] that delegates calls to instance returned by [NetworkHandlerSelector.awaitResumeInstance].
|
||||||
@ -52,6 +53,9 @@ internal class SelectorNetworkHandler(
|
|||||||
selector.getResumedInstance()?.close(cause)
|
selector.getResumedInstance()?.close(cause)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val coroutineContext: CoroutineContext
|
||||||
|
get() = selector.getResumedInstance()?.coroutineContext ?: scope.coroutineContext // merely use fallback
|
||||||
|
|
||||||
override fun toString(): String = "SelectorNetworkHandler(currentInstance=${selector.getResumedInstance()})"
|
override fun toString(): String = "SelectorNetworkHandler(currentInstance=${selector.getResumedInstance()})"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ internal open class NettyNetworkHandler(
|
|||||||
|
|
||||||
private inner class OutgoingPacketEncoder : MessageToByteEncoder<OutgoingPacket>(OutgoingPacket::class.java) {
|
private inner class OutgoingPacketEncoder : MessageToByteEncoder<OutgoingPacket>(OutgoingPacket::class.java) {
|
||||||
override fun encode(ctx: ChannelHandlerContext, msg: OutgoingPacket, out: ByteBuf) {
|
override fun encode(ctx: ChannelHandlerContext, msg: OutgoingPacket, out: ByteBuf) {
|
||||||
PacketCodec.PacketLogger.debug { "encode: $msg" }
|
packetLogger.debug { "encode: $msg" }
|
||||||
out.writeBytes(msg.delegate)
|
out.writeBytes(msg.delegate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -261,19 +261,29 @@ internal open class NettyNetworkHandler(
|
|||||||
connection.writeAndFlush(packet)
|
connection.writeAndFlush(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val configPush = this@NettyNetworkHandler.launch(CoroutineName("ConfigPush sync")) {
|
||||||
|
try {
|
||||||
|
context[ConfigPushProcessor].syncConfigPush(this@NettyNetworkHandler)
|
||||||
|
} catch (e: ConfigPushProcessor.RequireReconnectException) {
|
||||||
|
setState { StateConnecting(ExceptionCollector(e), false) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun resumeConnection0() {
|
override suspend fun resumeConnection0() {
|
||||||
(coroutineContext.job as CompletableJob).run {
|
(coroutineContext.job as CompletableJob).run {
|
||||||
complete()
|
complete()
|
||||||
join()
|
join()
|
||||||
}
|
}
|
||||||
setState { StateOK(connection) }
|
joinCompleted(configPush) // throw exception
|
||||||
|
setState { StateOK(connection, configPush) }
|
||||||
} // noop
|
} // noop
|
||||||
|
|
||||||
override fun toString(): String = "StateLoading"
|
override fun toString(): String = "StateLoading"
|
||||||
}
|
}
|
||||||
|
|
||||||
protected inner class StateOK(
|
protected inner class StateOK(
|
||||||
private val connection: NettyChannel
|
private val connection: NettyChannel,
|
||||||
|
private val configPush: Job,
|
||||||
) : NettyState(State.OK) {
|
) : NettyState(State.OK) {
|
||||||
init {
|
init {
|
||||||
coroutineContext.job.invokeOnCompletion {
|
coroutineContext.job.invokeOnCompletion {
|
||||||
@ -307,14 +317,6 @@ internal open class NettyNetworkHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val configPush = launch(CoroutineName("ConfigPush sync")) {
|
|
||||||
try {
|
|
||||||
context[ConfigPushProcessor].syncConfigPush(this@NettyNetworkHandler)
|
|
||||||
} catch (e: ConfigPushProcessor.RequireReconnectException) {
|
|
||||||
setState { StateClosed(e) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we can also move them as observers if needed.
|
// we can also move them as observers if needed.
|
||||||
|
|
||||||
private val keyRefresh = launch(CoroutineName("Key refresh")) {
|
private val keyRefresh = launch(CoroutineName("Key refresh")) {
|
||||||
@ -332,10 +334,6 @@ internal open class NettyNetworkHandler(
|
|||||||
joinCompleted(keyRefresh)
|
joinCompleted(keyRefresh)
|
||||||
} // noop
|
} // noop
|
||||||
|
|
||||||
private suspend inline fun joinCompleted(job: Job) {
|
|
||||||
if (job.isCompleted) job.join()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String = "StateOK"
|
override fun toString(): String = "StateOK"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import io.netty.buffer.ByteBufInputStream
|
|||||||
import io.netty.channel.ChannelFuture
|
import io.netty.channel.ChannelFuture
|
||||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||||
import kotlinx.coroutines.CoroutineName
|
import kotlinx.coroutines.CoroutineName
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.io.core.ByteReadPacket
|
import kotlinx.io.core.ByteReadPacket
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
import net.mamoe.mirai.utils.SimpleLogger
|
import net.mamoe.mirai.utils.SimpleLogger
|
||||||
@ -55,3 +56,8 @@ internal fun MiraiLogger.asCoroutineExceptionHandler(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal suspend inline fun joinCompleted(job: Job) {
|
||||||
|
if (job.isCompleted) job.join()
|
||||||
|
}
|
||||||
|
@ -18,6 +18,7 @@ import kotlinx.coroutines.flow.*
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.io.core.*
|
import kotlinx.io.core.*
|
||||||
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.Mirai
|
import net.mamoe.mirai.Mirai
|
||||||
import net.mamoe.mirai.contact.Group
|
import net.mamoe.mirai.contact.Group
|
||||||
import net.mamoe.mirai.contact.MemberPermission
|
import net.mamoe.mirai.contact.MemberPermission
|
||||||
@ -55,7 +56,10 @@ import net.mamoe.mirai.message.data.MessageSourceKind.STRANGER
|
|||||||
import net.mamoe.mirai.message.data.MessageSourceKind.TEMP
|
import net.mamoe.mirai.message.data.MessageSourceKind.TEMP
|
||||||
import net.mamoe.mirai.message.data.PlainText
|
import net.mamoe.mirai.message.data.PlainText
|
||||||
import net.mamoe.mirai.message.data.buildMessageChain
|
import net.mamoe.mirai.message.data.buildMessageChain
|
||||||
import net.mamoe.mirai.utils.*
|
import net.mamoe.mirai.utils.cast
|
||||||
|
import net.mamoe.mirai.utils.debug
|
||||||
|
import net.mamoe.mirai.utils.read
|
||||||
|
import net.mamoe.mirai.utils.toUHexString
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
||||||
@ -93,12 +97,13 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
open class GetMsgSuccess(delegate: List<Packet>, syncCookie: ByteArray?, val bot: QQAndroidBot) : Response(
|
open class GetMsgSuccess(delegate: List<Packet>, syncCookie: ByteArray?, bot: QQAndroidBot) : Response(
|
||||||
MsgSvc.SyncFlag.STOP, delegate,
|
MsgSvc.SyncFlag.STOP, delegate,
|
||||||
syncCookie
|
syncCookie,
|
||||||
|
bot
|
||||||
), Event,
|
), Event,
|
||||||
Packet.NoLog {
|
Packet.NoLog {
|
||||||
override fun toString(): String = "MessageSvcPbGetMsg.GetMsgSuccess(messages=<Iterable>))"
|
override fun toString(): String = "MessageSvcPbGetMsg.GetMsgSuccess"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -107,15 +112,16 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
|||||||
open class Response(
|
open class Response(
|
||||||
internal val syncFlagFromServer: MsgSvc.SyncFlag,
|
internal val syncFlagFromServer: MsgSvc.SyncFlag,
|
||||||
delegate: List<Packet>,
|
delegate: List<Packet>,
|
||||||
val syncCookie: ByteArray?
|
val syncCookie: ByteArray?, override val bot: Bot
|
||||||
) :
|
) :
|
||||||
AbstractEvent(),
|
AbstractEvent(),
|
||||||
MultiPacket<Packet>,
|
MultiPacket<Packet>,
|
||||||
Iterable<Packet> by (delegate),
|
Iterable<Packet> by (delegate),
|
||||||
Packet.NoLog {
|
Packet.NoLog,
|
||||||
|
BotEvent {
|
||||||
|
|
||||||
override fun toString(): String =
|
override fun toString(): String =
|
||||||
"MessageSvcPbGetMsg.Response(syncFlagFromServer=$syncFlagFromServer, messages=<Iterable>))"
|
"MessageSvcPbGetMsg.Response(flag=$syncFlagFromServer)"
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmptyResponse(
|
class EmptyResponse(
|
||||||
@ -128,9 +134,12 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
|||||||
val resp = readProtoBuf(MsgSvc.PbGetMsgResp.serializer())
|
val resp = readProtoBuf(MsgSvc.PbGetMsgResp.serializer())
|
||||||
|
|
||||||
if (resp.result != 0) {
|
if (resp.result != 0) {
|
||||||
bot.network.logger
|
// this is normally recoverable, no need to log
|
||||||
.warning { "MessageSvcPushNotify: result != 0, result = ${resp.result}, errorMsg=${resp.errmsg}" }
|
|
||||||
bot.launch(CoroutineName("MessageSvcPushNotify.retry")) {
|
|
||||||
|
// bot.network.logger
|
||||||
|
// .warning { "MessageSvcPushNotify: result != 0, result = ${resp.result}, errorMsg=${resp.errmsg}" }
|
||||||
|
bot.network.launch(CoroutineName("MessageSvcPushNotify.retry")) {
|
||||||
delay(500 + Random.nextLong(0, 1000))
|
delay(500 + Random.nextLong(0, 1000))
|
||||||
bot.network.run {
|
bot.network.run {
|
||||||
MessageSvcPbGetMsg(bot.client, syncCookie = null).sendWithoutExpect()
|
MessageSvcPbGetMsg(bot.client, syncCookie = null).sendWithoutExpect()
|
||||||
@ -188,7 +197,7 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
|||||||
if (resp.syncFlag == MsgSvc.SyncFlag.STOP) {
|
if (resp.syncFlag == MsgSvc.SyncFlag.STOP) {
|
||||||
return GetMsgSuccess(list, resp.syncCookie, bot)
|
return GetMsgSuccess(list, resp.syncCookie, bot)
|
||||||
}
|
}
|
||||||
return Response(resp.syncFlag, list, resp.syncCookie)
|
return Response(resp.syncFlag, list, resp.syncCookie, bot)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun QQAndroidBot.handle(packet: Response) {
|
override suspend fun QQAndroidBot.handle(packet: Response) {
|
||||||
|
@ -110,7 +110,8 @@ internal abstract class AbstractRealNetworkHandlerTest<H : NetworkHandler> : Abs
|
|||||||
set(ContactUpdater, ContactUpdaterImpl(bot, components, networkLogger))
|
set(ContactUpdater, ContactUpdaterImpl(bot, components, networkLogger))
|
||||||
set(BdhSessionSyncer, BdhSessionSyncerImpl(configuration, networkLogger, components))
|
set(BdhSessionSyncer, BdhSessionSyncerImpl(configuration, networkLogger, components))
|
||||||
set(ServerList, ServerListImpl())
|
set(ServerList, ServerListImpl())
|
||||||
set(PacketHandler, LoggingPacketHandler(bot, networkLogger))
|
set(PacketLoggingStrategy, PacketLoggingStrategyImpl(bot))
|
||||||
|
set(PacketHandler, LoggingPacketHandlerAdapter(networkLogger, get(PacketLoggingStrategy)))
|
||||||
set(PacketCodec, PacketCodecImpl())
|
set(PacketCodec, PacketCodecImpl())
|
||||||
set(OtherClientUpdater, OtherClientUpdaterImpl(bot, components, bot.logger))
|
set(OtherClientUpdater, OtherClientUpdaterImpl(bot, components, bot.logger))
|
||||||
set(ConfigPushSyncer, ConfigPushSyncerImpl())
|
set(ConfigPushSyncer, ConfigPushSyncerImpl())
|
||||||
|
Loading…
Reference in New Issue
Block a user