mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-07 09:40:11 +08:00
NetReplayHelper
This commit is contained in:
parent
0403de2b39
commit
76d23c5b0c
@ -110,7 +110,7 @@ internal open class NettyNetworkHandler(
|
||||
.addLast(OutgoingPacketEncoder())
|
||||
.addLast(LengthFieldBasedFrameDecoder(Int.MAX_VALUE, 0, 4, -4, 4))
|
||||
.addLast(ByteBufToIncomingPacketDecoder())
|
||||
.addLast(RawIncomingPacketCollector(decodePipeline))
|
||||
.addLast("raw-packet-collector", RawIncomingPacketCollector(decodePipeline))
|
||||
}
|
||||
|
||||
protected open fun createDummyDecodePipeline() = PacketDecodePipeline(this@NettyNetworkHandler.coroutineContext)
|
||||
|
253
mirai-core/src/jvmTest/kotlin/bootstrap/NetReplayHelper.kt
Normal file
253
mirai-core/src/jvmTest/kotlin/bootstrap/NetReplayHelper.kt
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* 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/dev/LICENSE
|
||||
*/
|
||||
|
||||
@file:JvmName("NetReplayHelper")
|
||||
@file:Suppress("TestFunctionName")
|
||||
|
||||
package net.mamoe.mirai.internal.bootstrap
|
||||
|
||||
import io.netty.channel.*
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.BotFactory
|
||||
import net.mamoe.mirai.internal.asQQAndroidBot
|
||||
import net.mamoe.mirai.internal.network.components.PacketLoggingStrategyImpl
|
||||
import net.mamoe.mirai.internal.network.components.RawIncomingPacket
|
||||
import net.mamoe.mirai.internal.network.components.ServerList
|
||||
import net.mamoe.mirai.internal.network.handler.NetworkHandlerContext
|
||||
import net.mamoe.mirai.internal.network.handler.NetworkHandlerContextImpl
|
||||
import net.mamoe.mirai.internal.network.handler.NetworkHandlerFactory
|
||||
import net.mamoe.mirai.internal.network.handler.selector.KeepAliveNetworkHandlerSelector
|
||||
import net.mamoe.mirai.internal.network.handler.selector.SelectorNetworkHandler
|
||||
import net.mamoe.mirai.internal.network.impl.netty.NettyNetworkHandler
|
||||
import net.mamoe.mirai.internal.utils.subLogger
|
||||
import net.mamoe.mirai.utils.*
|
||||
import java.awt.Component
|
||||
import java.awt.event.MouseAdapter
|
||||
import java.awt.event.MouseEvent
|
||||
import java.lang.invoke.MethodHandles
|
||||
import java.net.SocketAddress
|
||||
import javax.swing.*
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.full.declaredMembers
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.reflect.jvm.javaField
|
||||
|
||||
private val droppedCommands: Collection<String> by lazy {
|
||||
listOf(
|
||||
"Heartbeat.Alive",
|
||||
"wtlogin.exchange_emp",
|
||||
"StatSvc.register",
|
||||
"StatSvc.GetDevLoginInfo",
|
||||
"MessageSvc.PbGetMsg",
|
||||
"friendlist.getFriendGroupList",
|
||||
"friendlist.GetTroopListReqV2",
|
||||
"friendlist.GetTroopMemberListReq",
|
||||
"ConfigPushSvc.PushReq",
|
||||
*PacketLoggingStrategyImpl.getDefaultBlacklist().toTypedArray(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun NetReplayHelperClass(): Class<*> {
|
||||
return MethodHandles.lookup().lookupClass()
|
||||
}
|
||||
|
||||
private val logger by lazy {
|
||||
MiraiLogger.Factory.create(NetReplayHelperClass())
|
||||
}
|
||||
|
||||
private fun attachNetReplayHelper(channel: Channel) {
|
||||
channel.pipeline()
|
||||
.addBefore("raw-packet-collector", "raw-packet-dumper", newRawPacketDumper())
|
||||
|
||||
attachNetReplayWView(channel)
|
||||
}
|
||||
|
||||
private fun newRawPacketDumper(): ChannelHandler = object : ChannelInboundHandlerAdapter() {
|
||||
override fun channelRead(ctx: ChannelHandlerContext?, msg: Any?) {
|
||||
if (msg is RawIncomingPacket) {
|
||||
if (msg.commandName in droppedCommands) {
|
||||
logger.debug { "sid=${msg.sequenceId}, cmd=${msg.commandName}, body=<DROPPED>" }
|
||||
} else {
|
||||
logger.debug { "sid=${msg.sequenceId}, cmd=${msg.commandName}, body=${msg.body.toUHexString()}" }
|
||||
}
|
||||
}
|
||||
super.channelRead(ctx, msg)
|
||||
}
|
||||
}
|
||||
|
||||
private fun attachNetReplayWView(channel: Channel) {
|
||||
val frame = JFrame("Net Replay Helper")
|
||||
val panel = JPanel()
|
||||
val layout = GroupLayout(panel)
|
||||
panel.layout = layout
|
||||
frame.add(panel)
|
||||
|
||||
val cmd = JTextField()
|
||||
val sid = JTextField()
|
||||
val bdy = JTextField()
|
||||
val log = JTextField()
|
||||
|
||||
val cmdLabel = JLabel("cmd").also { it.labelFor = cmd }
|
||||
val sidLabel = JLabel("seq").also { it.labelFor = sid }
|
||||
val bdyLabel = JLabel("body").also { it.labelFor = bdy }
|
||||
val logLabel = JLabel("log").also { it.labelFor = log }
|
||||
|
||||
val fireCustom = JButton("Fire Cus")
|
||||
val fireLog = JButton("Fire Log")
|
||||
|
||||
// region
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup().addGroup(
|
||||
layout.createSequentialGroup().addGroup(
|
||||
layout.createParallelGroup()
|
||||
.addComponent(cmdLabel)
|
||||
.addComponent(sidLabel)
|
||||
.addComponent(bdyLabel)
|
||||
.addComponent(logLabel)
|
||||
).addGroup(
|
||||
layout.createParallelGroup()
|
||||
.addComponent(cmd)
|
||||
.addComponent(sid)
|
||||
.addComponent(bdy)
|
||||
.addComponent(log)
|
||||
)
|
||||
).addGroup(
|
||||
layout.createSequentialGroup()
|
||||
.addComponent(fireCustom)
|
||||
.addComponent(fireLog)
|
||||
)
|
||||
)
|
||||
layout.setVerticalGroup(
|
||||
layout.createSequentialGroup()
|
||||
.addGroup(
|
||||
layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(cmdLabel)
|
||||
.addComponent(cmd)
|
||||
)
|
||||
.addGroup(
|
||||
layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(sidLabel)
|
||||
.addComponent(sid)
|
||||
)
|
||||
.addGroup(
|
||||
layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(bdyLabel)
|
||||
.addComponent(bdy)
|
||||
)
|
||||
.addGroup(
|
||||
layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(logLabel)
|
||||
.addComponent(log)
|
||||
)
|
||||
.addGroup(
|
||||
layout.createParallelGroup()
|
||||
.addComponent(fireCustom)
|
||||
.addComponent(fireLog)
|
||||
)
|
||||
)
|
||||
// endregion
|
||||
|
||||
fun Component.onClick(handle: () -> Unit) {
|
||||
addMouseListener(object : MouseAdapter() {
|
||||
override fun mouseClicked(e: MouseEvent?) {
|
||||
runCatching(handle).onFailure { logger.error(it) }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fireCustom.onClick {
|
||||
val rp = RawIncomingPacket(
|
||||
commandName = cmd.text.trim(),
|
||||
sequenceId = sid.text.toInt(),
|
||||
body = bdy.text.hexToBytes(),
|
||||
)
|
||||
channel.pipeline().fireChannelRead(rp)
|
||||
}
|
||||
|
||||
@Suppress("LocalVariableName")
|
||||
fireLog.onClick {
|
||||
var line = log.text.substringAfter("sid=")
|
||||
// 2021-11-07 11:49:38 D/NetReplayHelper: sid=123, cmd=HelloWorld!, body=00
|
||||
val sid_ = line.substringBefore(",").toInt()
|
||||
line = line.substringAfter("cmd=")
|
||||
val cmd_ = line.substringBeforeLast("body=").trim().removeSuffix(",").trim()
|
||||
val bdy_ = line.substringAfterLast("body=").trim().hexToBytes()
|
||||
|
||||
val rp = RawIncomingPacket(
|
||||
commandName = cmd_,
|
||||
sequenceId = sid_,
|
||||
body = bdy_,
|
||||
)
|
||||
channel.pipeline().fireChannelRead(rp)
|
||||
}
|
||||
|
||||
frame.pack()
|
||||
frame.defaultCloseOperation = JFrame.DO_NOTHING_ON_CLOSE
|
||||
frame.setLocationRelativeTo(null)
|
||||
frame.isVisible = true
|
||||
|
||||
channel.pipeline().addLast(object : ChannelInboundHandlerAdapter() {
|
||||
override fun channelInactive(ctx: ChannelHandlerContext?) {
|
||||
SwingUtilities.invokeLater {
|
||||
frame.dispose()
|
||||
}
|
||||
super.channelInactive(ctx)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
private object NRHNettyNetworkHandlerFactory : NetworkHandlerFactory<NettyNetworkHandler> {
|
||||
override fun create(context: NetworkHandlerContext, address: SocketAddress): NettyNetworkHandler {
|
||||
return object : NettyNetworkHandler(context, address) {
|
||||
override fun setupChannelPipeline(pipeline: ChannelPipeline, decodePipeline: PacketDecodePipeline) {
|
||||
super.setupChannelPipeline(pipeline, decodePipeline)
|
||||
attachNetReplayHelper(pipeline.channel())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call before bot.login()
|
||||
fun Bot.attachNetReplayHelper() {
|
||||
asQQAndroidBot()
|
||||
val networkLogger = this::class.declaredMembers.first { it.name == "networkLogger" }.let { property ->
|
||||
property as KProperty<*>
|
||||
property.isAccessible = true
|
||||
property.getter.call(this@attachNetReplayHelper)
|
||||
} as MiraiLogger
|
||||
|
||||
|
||||
val snh = network.cast<SelectorNetworkHandler<*>>()
|
||||
val field = snh::selector.javaField!!
|
||||
field.isAccessible = true
|
||||
field.set(
|
||||
snh,
|
||||
KeepAliveNetworkHandlerSelector(
|
||||
maxAttempts = configuration.reconnectionRetryTimes.coerceIn(1, Int.MAX_VALUE),
|
||||
logger = networkLogger.subLogger("Selector")
|
||||
) {
|
||||
val context = NetworkHandlerContextImpl(
|
||||
bot,
|
||||
networkLogger,
|
||||
createNetworkLevelComponents(),
|
||||
)
|
||||
NRHNettyNetworkHandlerFactory.create(
|
||||
context,
|
||||
context[ServerList].pollAny().toSocketAddress(),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val bot = BotFactory.newBot(0, "")
|
||||
bot.attachNetReplayHelper()
|
||||
}
|
Loading…
Reference in New Issue
Block a user