mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-09 19:50:27 +08:00
NetReplayHelper
This commit is contained in:
parent
0403de2b39
commit
76d23c5b0c
@ -110,7 +110,7 @@ internal open class NettyNetworkHandler(
|
|||||||
.addLast(OutgoingPacketEncoder())
|
.addLast(OutgoingPacketEncoder())
|
||||||
.addLast(LengthFieldBasedFrameDecoder(Int.MAX_VALUE, 0, 4, -4, 4))
|
.addLast(LengthFieldBasedFrameDecoder(Int.MAX_VALUE, 0, 4, -4, 4))
|
||||||
.addLast(ByteBufToIncomingPacketDecoder())
|
.addLast(ByteBufToIncomingPacketDecoder())
|
||||||
.addLast(RawIncomingPacketCollector(decodePipeline))
|
.addLast("raw-packet-collector", RawIncomingPacketCollector(decodePipeline))
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun createDummyDecodePipeline() = PacketDecodePipeline(this@NettyNetworkHandler.coroutineContext)
|
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