mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-09 01:30:17 +08:00
Use PacketHandler.Key
This commit is contained in:
parent
d89f8acc43
commit
ad43a92be4
@ -7,8 +7,10 @@ import net.mamoe.mirai.contact.Group
|
|||||||
import net.mamoe.mirai.contact.QQ
|
import net.mamoe.mirai.contact.QQ
|
||||||
import net.mamoe.mirai.network.BotNetworkHandler
|
import net.mamoe.mirai.network.BotNetworkHandler
|
||||||
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
|
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
|
||||||
|
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
|
||||||
import net.mamoe.mirai.utils.BotAccount
|
import net.mamoe.mirai.utils.BotAccount
|
||||||
import net.mamoe.mirai.utils.ContactList
|
import net.mamoe.mirai.utils.ContactList
|
||||||
|
import net.mamoe.mirai.utils.LoginConfiguration
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,7 +46,7 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) {
|
|||||||
|
|
||||||
val contacts = ContactSystem()
|
val contacts = ContactSystem()
|
||||||
|
|
||||||
val network: BotNetworkHandler<*> = TIMBotNetworkHandler(this)
|
var network: BotNetworkHandler<*> = TIMBotNetworkHandler(this)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
instances.add(this)
|
instances.add(this)
|
||||||
@ -54,6 +56,17 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) {
|
|||||||
|
|
||||||
override fun toString(): String = "Bot{id=$id,qq=${account.qqNumber}}"
|
override fun toString(): String = "Bot{id=$id,qq=${account.qqNumber}}"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [关闭][BotNetworkHandler.close]网络处理器, 取消所有运行在 [BotNetworkHandler.NetworkScope] 下的协程.
|
||||||
|
* 然后重新启动并尝试登录
|
||||||
|
*/
|
||||||
|
suspend fun reinitializeNetworkHandler(configuration: LoginConfiguration): LoginResult {
|
||||||
|
logger.logPurple("Reinitializing BotNetworkHandler")
|
||||||
|
network.close()
|
||||||
|
network = TIMBotNetworkHandler(this)
|
||||||
|
return network.login(configuration)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bot 联系人管理.
|
* Bot 联系人管理.
|
||||||
*
|
*
|
||||||
|
@ -3,6 +3,7 @@ package net.mamoe.mirai.contact
|
|||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.contact.Group.Companion.groupNumberToId
|
import net.mamoe.mirai.contact.Group.Companion.groupNumberToId
|
||||||
import net.mamoe.mirai.message.MessageChain
|
import net.mamoe.mirai.message.MessageChain
|
||||||
|
import net.mamoe.mirai.network.protocol.tim.handler.EventPacketHandler
|
||||||
import net.mamoe.mirai.utils.ContactList
|
import net.mamoe.mirai.utils.ContactList
|
||||||
import kotlin.jvm.JvmStatic
|
import kotlin.jvm.JvmStatic
|
||||||
|
|
||||||
@ -28,7 +29,7 @@ class Group(bot: Bot, number: Long) : Contact(bot, number) {
|
|||||||
get() = throw UnsupportedOperationException("Not yet supported")
|
get() = throw UnsupportedOperationException("Not yet supported")
|
||||||
|
|
||||||
override suspend fun sendMessage(message: MessageChain) {
|
override suspend fun sendMessage(message: MessageChain) {
|
||||||
bot.network.event.sendGroupMessage(this, message)
|
bot.network[EventPacketHandler].sendGroupMessage(this, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun sendXMLMessage(message: String) {
|
override suspend fun sendXMLMessage(message: String) {
|
||||||
|
@ -4,6 +4,7 @@ import net.mamoe.mirai.Bot
|
|||||||
import net.mamoe.mirai.message.At
|
import net.mamoe.mirai.message.At
|
||||||
import net.mamoe.mirai.message.Message
|
import net.mamoe.mirai.message.Message
|
||||||
import net.mamoe.mirai.message.MessageChain
|
import net.mamoe.mirai.message.MessageChain
|
||||||
|
import net.mamoe.mirai.network.protocol.tim.handler.EventPacketHandler
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* QQ 账号.
|
* QQ 账号.
|
||||||
@ -19,7 +20,7 @@ import net.mamoe.mirai.message.MessageChain
|
|||||||
*/
|
*/
|
||||||
class QQ(bot: Bot, number: Long) : Contact(bot, number) {
|
class QQ(bot: Bot, number: Long) : Contact(bot, number) {
|
||||||
override suspend fun sendMessage(message: MessageChain) {
|
override suspend fun sendMessage(message: MessageChain) {
|
||||||
bot.network.event.sendFriendMessage(this, message)
|
bot.network[EventPacketHandler].sendFriendMessage(this, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun sendXMLMessage(message: String) {
|
override suspend fun sendXMLMessage(message: String) {
|
||||||
|
@ -6,7 +6,7 @@ import kotlinx.io.core.*
|
|||||||
import net.mamoe.mirai.message.*
|
import net.mamoe.mirai.message.*
|
||||||
import net.mamoe.mirai.utils.*
|
import net.mamoe.mirai.utils.*
|
||||||
|
|
||||||
internal fun ByteArray.parseMessageFace(): Face = read {
|
internal fun IoBuffer.parseMessageFace(): Face {
|
||||||
//00 01 AF 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 F0
|
//00 01 AF 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 F0
|
||||||
//00 01 0C 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 4D
|
//00 01 0C 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 4D
|
||||||
discardExact(1)
|
discardExact(1)
|
||||||
@ -14,30 +14,30 @@ internal fun ByteArray.parseMessageFace(): Face = read {
|
|||||||
val id1 = FaceID.ofId(readLVNumber().toInt().toUByte())//可能这个是id, 也可能下面那个
|
val id1 = FaceID.ofId(readLVNumber().toInt().toUByte())//可能这个是id, 也可能下面那个
|
||||||
discardExact(readByte().toLong())
|
discardExact(readByte().toLong())
|
||||||
readLVNumber()//某id?
|
readLVNumber()//某id?
|
||||||
return@read Face(id1)
|
return Face(id1)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ByteArray.parsePlainText(): PlainText = read {
|
internal fun IoBuffer.parsePlainText(): PlainText {
|
||||||
discardExact(1)
|
discardExact(1)
|
||||||
PlainText(readLVString())
|
return PlainText(readLVString())
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ByteArray.parseMessageImage0x06(): Image = read {
|
internal fun IoBuffer.parseMessageImage0x06(): Image {
|
||||||
discardExact(1)
|
discardExact(1)
|
||||||
MiraiLogger.logDebug("好友的图片")
|
this.debugPrint("好友的图片")
|
||||||
MiraiLogger.logDebug(this@parseMessageImage0x06.toUHexString())
|
//MiraiLogger.logDebug(this.toUHexString())
|
||||||
val filenameLength = readShort()
|
val filenameLength = readShort()
|
||||||
val suffix = readString(filenameLength).substringAfter(".")
|
val suffix = readString(filenameLength).substringAfter(".")
|
||||||
discardExact(this@parseMessageImage0x06.size - 37 - 1 - filenameLength - 2)
|
discardExact(this@parseMessageImage0x06.readRemaining - 37 - 1 - filenameLength - 2)
|
||||||
val imageId = readString(36)
|
val imageId = readString(36)
|
||||||
MiraiLogger.logDebug(imageId)
|
MiraiLogger.logDebug(imageId)
|
||||||
discardExact(1)//0x41
|
discardExact(1)//0x41
|
||||||
return@read Image("{$imageId}.$suffix")
|
return Image("{$imageId}.$suffix")
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ByteArray.parseMessageImage0x03(): Image = read {
|
internal fun IoBuffer.parseMessageImage0x03(): Image {
|
||||||
discardExact(1)
|
discardExact(1)
|
||||||
return@read Image(String(readLVByteArray()))
|
return Image(String(readLVByteArray()))
|
||||||
/*
|
/*
|
||||||
println(String(readLVByteArray()))
|
println(String(readLVByteArray()))
|
||||||
readTLVMap()
|
readTLVMap()
|
||||||
@ -53,14 +53,14 @@ internal fun ByteArray.parseMessageImage0x03(): Image = read {
|
|||||||
return Image(imageId)*/
|
return Image(imageId)*/
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ByteArray.parseMessageChain(): MessageChain = read {
|
internal fun ByteReadPacket.parseMessageChain(): MessageChain {
|
||||||
readMessageChain()
|
return readMessageChain()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ByteReadPacket.readMessage(): Message? {
|
internal fun ByteReadPacket.readMessage(): Message? {
|
||||||
val messageType = this.readByte().toInt()
|
val messageType = this.readByte().toInt()
|
||||||
val sectionLength = this.readShort().toLong()//sectionLength: short
|
val sectionLength = this.readShort().toLong()//sectionLength: short
|
||||||
val sectionData = this.readBytes(sectionLength.toInt())//use buffer instead
|
val sectionData = this.readIoBuffer(sectionLength.toInt())//use buffer instead
|
||||||
return when (messageType) {
|
return when (messageType) {
|
||||||
0x01 -> sectionData.parsePlainText()
|
0x01 -> sectionData.parsePlainText()
|
||||||
0x02 -> sectionData.parseMessageFace()
|
0x02 -> sectionData.parseMessageFace()
|
||||||
@ -68,7 +68,12 @@ internal fun ByteReadPacket.readMessage(): Message? {
|
|||||||
0x06 -> sectionData.parseMessageImage0x06()
|
0x06 -> sectionData.parseMessageImage0x06()
|
||||||
|
|
||||||
|
|
||||||
0x19 -> {//长文本
|
0x19 -> {//未知, 可能是长文本?
|
||||||
|
//bot手机自己跟自己发消息会出这个
|
||||||
|
//sectionData: 01 00 1C AA 02 19 08 00 88 01 00 9A 01 11 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00
|
||||||
|
sectionData.readBytes().debugPrint("sectionData")
|
||||||
|
return PlainText("[UNKNOWN(${this.readBytes().toUHexString()})]")
|
||||||
|
println()
|
||||||
val value = readLVByteArray()
|
val value = readLVByteArray()
|
||||||
//todo 未知压缩算法
|
//todo 未知压缩算法
|
||||||
PlainText(String(value))
|
PlainText(String(value))
|
||||||
@ -87,7 +92,6 @@ internal fun ByteReadPacket.readMessage(): Message? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
0x0E -> {
|
0x0E -> {
|
||||||
//null
|
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,16 +106,11 @@ internal fun ByteReadPacket.readMessage(): Message? {
|
|||||||
|
|
||||||
fun ByteReadPacket.readMessageChain(): MessageChain {
|
fun ByteReadPacket.readMessageChain(): MessageChain {
|
||||||
val chain = MessageChain()
|
val chain = MessageChain()
|
||||||
var got: Message? = null
|
|
||||||
do {
|
do {
|
||||||
if (got != null) {
|
|
||||||
chain.concat(got)
|
|
||||||
}
|
|
||||||
if (this.remaining == 0L) {
|
if (this.remaining == 0L) {
|
||||||
return chain
|
return chain
|
||||||
}
|
}
|
||||||
got = this.readMessage()
|
} while (this.readMessage().takeIf { it != null }?.let { chain.concat(it) } != null)
|
||||||
} while (got != null)
|
|
||||||
return chain
|
return chain
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,22 +45,14 @@ interface BotNetworkHandler<Socket : DataPacketSocket> : Closeable {
|
|||||||
var socket: Socket
|
var socket: Socket
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 事件处理. 如发送好友消息, 接受群消息并触发事件
|
* 得到 [PacketHandler].
|
||||||
|
* `get(EventPacketHandler)` 返回 [EventPacketHandler]
|
||||||
|
* `get(ActionPacketHandler)` 返回 [ActionPacketHandler]
|
||||||
*/
|
*/
|
||||||
val event: EventPacketHandler
|
operator fun <T : PacketHandler> get(key: PacketHandler.Key<T>): T
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 动作处理. 如发送好友请求, 处理别人发来的好友请求等
|
* 依次尝试登录到可用的服务器. 在任一服务器登录完成后返回登录结果
|
||||||
*/
|
|
||||||
val action: ActionPacketHandler
|
|
||||||
|
|
||||||
/**
|
|
||||||
* [PacketHandler] 列表
|
|
||||||
*/
|
|
||||||
val packetHandlers: PacketHandlerList
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 尝试登录. 将会依次尝试登录到可用的服务器. 在任一服务器登录完成后返回登录结果
|
|
||||||
*/
|
*/
|
||||||
suspend fun login(configuration: LoginConfiguration): LoginResult
|
suspend fun login(configuration: LoginConfiguration): LoginResult
|
||||||
|
|
||||||
|
@ -24,24 +24,19 @@ import net.mamoe.mirai.utils.*
|
|||||||
*
|
*
|
||||||
* @see BotNetworkHandler
|
* @see BotNetworkHandler
|
||||||
*/
|
*/
|
||||||
internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler<TIMBotNetworkHandler.BotSocket> {
|
internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler<TIMBotNetworkHandler.BotSocket>, PacketHandlerList() {
|
||||||
override val NetworkScope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
override val NetworkScope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
|
||||||
override lateinit var socket: BotSocket
|
override lateinit var socket: BotSocket
|
||||||
|
|
||||||
override lateinit var event: EventPacketHandler
|
|
||||||
|
|
||||||
override lateinit var action: ActionPacketHandler
|
|
||||||
|
|
||||||
override val packetHandlers: PacketHandlerList = PacketHandlerList()
|
|
||||||
|
|
||||||
internal val temporaryPacketHandlers = mutableListOf<TemporaryPacketHandler<*>>()
|
internal val temporaryPacketHandlers = mutableListOf<TemporaryPacketHandler<*>>()
|
||||||
|
|
||||||
private var heartbeatJob: Job? = null
|
private var heartbeatJob: Job? = null
|
||||||
|
|
||||||
|
|
||||||
override suspend fun addHandler(temporaryPacketHandler: TemporaryPacketHandler<*>) {
|
override suspend fun addHandler(temporaryPacketHandler: TemporaryPacketHandler<*>) {
|
||||||
temporaryPacketHandlers.add(temporaryPacketHandler)
|
temporaryPacketHandlers.add(temporaryPacketHandler)
|
||||||
temporaryPacketHandler.send(action.session)
|
temporaryPacketHandler.send(this[ActionPacketHandler].session)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun login(configuration: LoginConfiguration): LoginResult {
|
override suspend fun login(configuration: LoginConfiguration): LoginResult {
|
||||||
@ -68,13 +63,11 @@ internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler<TI
|
|||||||
|
|
||||||
//private | internal
|
//private | internal
|
||||||
private fun onLoggedIn(sessionKey: ByteArray) {
|
private fun onLoggedIn(sessionKey: ByteArray) {
|
||||||
require(packetHandlers.size == 0) { "Already logged in" }
|
require(size == 0) { "Already logged in" }
|
||||||
val session = LoginSession(bot, sessionKey, socket, NetworkScope)
|
val session = LoginSession(bot, sessionKey, socket, NetworkScope)
|
||||||
event = EventPacketHandler(session)
|
|
||||||
action = ActionPacketHandler(session)
|
|
||||||
|
|
||||||
packetHandlers.add(event.asNode())
|
add(EventPacketHandler(session).asNode(EventPacketHandler))
|
||||||
packetHandlers.add(action.asNode())
|
add(ActionPacketHandler(session).asNode(ActionPacketHandler))
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var sessionKey: ByteArray
|
private lateinit var sessionKey: ByteArray
|
||||||
@ -89,7 +82,7 @@ internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler<TI
|
|||||||
this.loginResult.cancel(CancellationException("socket closed"))
|
this.loginResult.cancel(CancellationException("socket closed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
this.packetHandlers.forEach {
|
this.forEach {
|
||||||
it.instance.close()
|
it.instance.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,21 +170,14 @@ internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler<TI
|
|||||||
|
|
||||||
packet.use {
|
packet.use {
|
||||||
//coz removeIf is not inline
|
//coz removeIf is not inline
|
||||||
with(temporaryPacketHandlers.iterator()) {
|
temporaryPacketHandlers.removeIfInlined {
|
||||||
while (hasNext()) {
|
it.onPacketReceived(this@TIMBotNetworkHandler[ActionPacketHandler].session, packet)
|
||||||
if (next().onPacketReceived(action.session, packet)) {
|
}
|
||||||
remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//For logDebug
|
val name = packet::class.simpleName
|
||||||
{
|
if (name != null && !name.endsWith("Encrypted") && !name.endsWith("Raw")) {
|
||||||
val name = packet::class.simpleName
|
bot.cyan("Packet received: $packet")
|
||||||
if (name != null && !name.endsWith("Encrypted") && !name.endsWith("Raw")) {
|
}
|
||||||
bot.cyan("Packet received: $packet")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if (packet is ServerEventPacket) {
|
if (packet is ServerEventPacket) {
|
||||||
//no need to sync acknowledgement packets
|
//no need to sync acknowledgement packets
|
||||||
@ -205,7 +191,7 @@ internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler<TI
|
|||||||
}
|
}
|
||||||
|
|
||||||
loginHandler.onPacketReceived(packet)
|
loginHandler.onPacketReceived(packet)
|
||||||
packetHandlers.forEach {
|
this@TIMBotNetworkHandler.forEach {
|
||||||
it.instance.onPacketReceived(packet)
|
it.instance.onPacketReceived(packet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -223,7 +209,11 @@ internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler<TI
|
|||||||
try {
|
try {
|
||||||
build.readAvailable(buffer)
|
build.readAvailable(buffer)
|
||||||
channel.send(buffer)//JVM: withContext(IO)
|
channel.send(buffer)//JVM: withContext(IO)
|
||||||
} catch (e: Exception) {
|
} catch (e: SendPacketInternalException) {
|
||||||
|
bot.logger.logError("Caught SendPacketInternalException: ${e.cause?.message}")
|
||||||
|
bot.reinitializeNetworkHandler(configuration)
|
||||||
|
return@withContext
|
||||||
|
} catch (e: Throwable) {
|
||||||
e.log()
|
e.log()
|
||||||
return@withContext
|
return@withContext
|
||||||
} finally {
|
} finally {
|
||||||
@ -379,7 +369,7 @@ internal class TIMBotNetworkHandler(private val bot: Bot) : BotNetworkHandler<TI
|
|||||||
//登录成功后会收到大量上次的消息, 忽略掉 todo 优化
|
//登录成功后会收到大量上次的消息, 忽略掉 todo 优化
|
||||||
NetworkScope.launch {
|
NetworkScope.launch {
|
||||||
delay(3000)
|
delay(3000)
|
||||||
event.ignoreMessage = false
|
this@TIMBotNetworkHandler[EventPacketHandler].ignoreMessage = false
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoggedIn(sessionKey)
|
onLoggedIn(sessionKey)
|
||||||
|
@ -23,6 +23,8 @@ import net.mamoe.mirai.utils.hexToBytes
|
|||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
|
class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
|
||||||
|
companion object Key : PacketHandler.Key<ActionPacketHandler>
|
||||||
|
|
||||||
private val addFriendSessions = mutableListOf<AddFriendSession>()
|
private val addFriendSessions = mutableListOf<AddFriendSession>()
|
||||||
private val uploadImageSessions = mutableListOf<UploadImageSession>()
|
private val uploadImageSessions = mutableListOf<UploadImageSession>()
|
||||||
|
|
||||||
|
@ -24,6 +24,9 @@ import net.mamoe.mirai.utils.MiraiLogger
|
|||||||
*/
|
*/
|
||||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||||
class EventPacketHandler(session: LoginSession) : PacketHandler(session) {
|
class EventPacketHandler(session: LoginSession) : PacketHandler(session) {
|
||||||
|
companion object Key : PacketHandler.Key<EventPacketHandler>
|
||||||
|
|
||||||
|
|
||||||
internal var ignoreMessage: Boolean = true
|
internal var ignoreMessage: Boolean = true
|
||||||
|
|
||||||
override suspend fun onPacketReceived(packet: ServerPacket): Unit = with(session) {
|
override suspend fun onPacketReceived(packet: ServerPacket): Unit = with(session) {
|
||||||
@ -57,6 +60,16 @@ class EventPacketHandler(session: LoginSession) : PacketHandler(session) {
|
|||||||
//TODO
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is ServerFriendTypingStartedPacket -> {
|
||||||
|
MiraiLogger.logInfo("${packet.qq.toLong()} 正在输入")
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
is ServerFriendTypingCanceledPacket -> {
|
||||||
|
MiraiLogger.logInfo("${packet.qq.toLong()} 取消了输入")
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
//ignored
|
//ignored
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ abstract class PacketHandler(
|
|||||||
) {
|
) {
|
||||||
abstract suspend fun onPacketReceived(packet: ServerPacket)
|
abstract suspend fun onPacketReceived(packet: ServerPacket)
|
||||||
|
|
||||||
|
interface Key<T : PacketHandler>
|
||||||
|
|
||||||
open fun close() {
|
open fun close() {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -19,15 +21,18 @@ abstract class PacketHandler(
|
|||||||
|
|
||||||
class PacketHandlerNode<T : PacketHandler>(
|
class PacketHandlerNode<T : PacketHandler>(
|
||||||
val clazz: KClass<T>,
|
val clazz: KClass<T>,
|
||||||
val instance: T
|
val instance: T,
|
||||||
|
val key: PacketHandler.Key<T>
|
||||||
)
|
)
|
||||||
|
|
||||||
fun <T : PacketHandler> T.asNode(): PacketHandlerNode<T> {
|
fun <T : PacketHandler> T.asNode(key: PacketHandler.Key<T>): PacketHandlerNode<T> {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
return PacketHandlerNode(this::class as KClass<T>, this)
|
return PacketHandlerNode(this::class as KClass<T>, this, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
class PacketHandlerList : MutableList<PacketHandlerNode<*>> by mutableListOf() {
|
open class PacketHandlerList : MutableList<PacketHandlerNode<*>> by mutableListOf() {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
operator fun <T : PacketHandler> get(key: PacketHandler.Key<T>): T = this.first { it.key === key }.instance as T
|
||||||
|
|
||||||
operator fun <T : PacketHandler> get(clazz: KClass<T>): T {
|
operator fun <T : PacketHandler> get(clazz: KClass<T>): T {
|
||||||
this.forEach {
|
this.forEach {
|
||||||
|
@ -14,7 +14,7 @@ data class EventPacketIdentity(
|
|||||||
val to: UInt,//对于好友消息, 这个是bot
|
val to: UInt,//对于好友消息, 这个是bot
|
||||||
internal val uniqueId: IoBuffer//8
|
internal val uniqueId: IoBuffer//8
|
||||||
) {
|
) {
|
||||||
override fun toString(): String = "EPI(from=$from, to=$to)"
|
override fun toString(): String = "(from=$from, to=$to)"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun BytePacketBuilder.writeEventPacketIdentity(identity: EventPacketIdentity) = with(identity) {
|
fun BytePacketBuilder.writeEventPacketIdentity(identity: EventPacketIdentity) = with(identity) {
|
||||||
@ -28,11 +28,8 @@ fun BytePacketBuilder.writeEventPacketIdentity(identity: EventPacketIdentity) =
|
|||||||
*
|
*
|
||||||
* @author Him188moe
|
* @author Him188moe
|
||||||
*/
|
*/
|
||||||
abstract class ServerEventPacket(input: ByteReadPacket, packetId: ByteArray, val eventIdentity: EventPacketIdentity) : ServerPacket(input) {
|
abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: EventPacketIdentity) : ServerPacket(input) {
|
||||||
override val idByteArray: ByteArray = packetId
|
class Raw(input: ByteReadPacket) : ServerPacket(input) {
|
||||||
override var idHex: String = packetId.toUHexString()
|
|
||||||
|
|
||||||
class Raw(input: ByteReadPacket, private val packetId: ByteArray) : ServerPacket(input) {
|
|
||||||
|
|
||||||
fun distribute(): ServerEventPacket = with(input) {
|
fun distribute(): ServerEventPacket = with(input) {
|
||||||
val eventIdentity = EventPacketIdentity(
|
val eventIdentity = EventPacketIdentity(
|
||||||
@ -46,25 +43,36 @@ abstract class ServerEventPacket(input: ByteReadPacket, packetId: ByteArray, val
|
|||||||
"00 C4" -> {
|
"00 C4" -> {
|
||||||
discardExact(13)
|
discardExact(13)
|
||||||
if (readBoolean()) {
|
if (readBoolean()) {
|
||||||
ServerAndroidOnlineEventPacket(input, packetId, eventIdentity)
|
ServerAndroidOfflineEventPacket(input, eventIdentity)
|
||||||
} else {
|
} else {
|
||||||
ServerAndroidOfflineEventPacket(input, packetId, eventIdentity)
|
ServerAndroidOnlineEventPacket(input, eventIdentity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"00 2D" -> ServerGroupUploadFileEventPacket(input, packetId, eventIdentity)
|
"00 2D" -> ServerGroupUploadFileEventPacket(input, eventIdentity)
|
||||||
|
|
||||||
"00 52" -> ServerGroupMessageEventPacket(input, packetId, eventIdentity)
|
"00 52" -> ServerGroupMessageEventPacket(input, eventIdentity)
|
||||||
|
|
||||||
"00 A6" -> ServerFriendMessageEventPacket(input, packetId, eventIdentity)
|
"00 A6" -> ServerFriendMessageEventPacket(input.debugPrint("好友消息事件"), eventIdentity)
|
||||||
|
|
||||||
//"02 10", "00 12" -> ServerUnknownEventPacket(input, packetId, eventIdentity)
|
|
||||||
|
|
||||||
else -> UnknownServerEventPacket(input, packetId, eventIdentity)
|
//00 00 00 08 00 0A 00 04 01 00 00 00 00 00 00 16 00 00 00 37 08 02 1A 12 08 95 02 10 90 04 40 98 E1 8C ED 05 48 AF 96 C3 A4 03 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 1A 29 08 00 10 05 18 98 E1 8C ED 05 20 01 28 FF FF FF FF 0F 32 15 E5 AF B9 E6 96 B9 E6 AD A3 E5 9C A8 E8 BE 93 E5 85 A5 2E 2E 2E
|
||||||
|
"02 10" -> {
|
||||||
|
discardExact(19)
|
||||||
|
if (readUByte().toUInt() == 0x37u) ServerFriendTypingStartedPacket(input, eventIdentity)
|
||||||
|
else /*0x22*/ ServerFriendTypingCanceledPacket(input, eventIdentity)
|
||||||
|
}
|
||||||
|
|
||||||
|
//"02 10", "00 12" -> ServerUnknownEventPacket(input, eventIdentity)
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
MiraiLogger.logDebug("UnknownEvent type = ${type.toUHexString()}")
|
||||||
|
UnknownServerEventPacket(input, eventIdentity)
|
||||||
|
}
|
||||||
}.setId(idHex)
|
}.setId(idHex)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Encrypted(input: ByteReadPacket, private val packetId: ByteArray) : ServerPacket(input) {
|
class Encrypted(input: ByteReadPacket) : ServerPacket(input) {
|
||||||
fun decrypt(sessionKey: ByteArray): Raw = Raw(this.decryptBy(sessionKey), packetId).setId(this.idHex)
|
fun decrypt(sessionKey: ByteArray): Raw = Raw(this.decryptBy(sessionKey)).setId(this.idHex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,26 +98,45 @@ abstract class ServerEventPacket(input: ByteReadPacket, packetId: ByteArray, val
|
|||||||
/**
|
/**
|
||||||
* Unknown event
|
* Unknown event
|
||||||
*/
|
*/
|
||||||
class UnknownServerEventPacket(input: ByteReadPacket, packetId: ByteArray, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, packetId, eventIdentity) {
|
class UnknownServerEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
|
||||||
override fun decode() {
|
override fun decode() {
|
||||||
println("UnknownServerEventPacket data: " + this.input.readBytes().toUHexString())
|
MiraiLogger.logDebug("UnknownServerEventPacket data: " + this.input.readBytes().toUHexString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sealed class ServerFriendTypingPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
|
||||||
|
val qq get() = eventIdentity.from
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对方正在输入
|
||||||
|
*/
|
||||||
|
class ServerFriendTypingStartedPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerFriendTypingPacket(input, eventIdentity)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对方取消了输入
|
||||||
|
*/
|
||||||
|
class ServerFriendTypingCanceledPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerFriendTypingPacket(input, eventIdentity)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Android 客户端上线
|
* Android 客户端上线
|
||||||
*/
|
*/
|
||||||
class ServerAndroidOnlineEventPacket(input: ByteReadPacket, packetId: ByteArray, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, packetId, eventIdentity)
|
class ServerAndroidOnlineEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Android 客户端下线
|
* Android 客户端下线
|
||||||
*/
|
*/
|
||||||
class ServerAndroidOfflineEventPacket(input: ByteReadPacket, packetId: ByteArray, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, packetId, eventIdentity)
|
class ServerAndroidOfflineEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 群文件上传
|
* 群文件上传
|
||||||
*/
|
*/
|
||||||
class ServerGroupUploadFileEventPacket(input: ByteReadPacket, packetId: ByteArray, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, packetId, eventIdentity) {
|
class ServerGroupUploadFileEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
|
||||||
private lateinit var xmlMessage: String
|
private lateinit var xmlMessage: String
|
||||||
|
|
||||||
override fun decode() {
|
override fun decode() {
|
||||||
@ -121,7 +148,7 @@ class ServerGroupUploadFileEventPacket(input: ByteReadPacket, packetId: ByteArra
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||||
class ServerGroupMessageEventPacket(input: ByteReadPacket, packetId: ByteArray, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, packetId, eventIdentity) {
|
class ServerGroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
|
||||||
var groupNumber: UInt by Delegates.notNull()
|
var groupNumber: UInt by Delegates.notNull()
|
||||||
var qq: UInt by Delegates.notNull()
|
var qq: UInt by Delegates.notNull()
|
||||||
lateinit var senderName: String
|
lateinit var senderName: String
|
||||||
@ -140,10 +167,11 @@ class ServerGroupMessageEventPacket(input: ByteReadPacket, packetId: ByteArray,
|
|||||||
|
|
||||||
val map = readTLVMap(true)
|
val map = readTLVMap(true)
|
||||||
map.printTLVMap("父map")
|
map.printTLVMap("父map")
|
||||||
if (map.containsKey(0x18)) {
|
if (map.containsKey(18)) {
|
||||||
senderName = map.getValue(0x18).read {
|
senderName = map.getValue(18).read {
|
||||||
val tlv = readTLVMap(true)
|
val tlv = readTLVMap(true)
|
||||||
tlv.printTLVMap("子map")
|
tlv.printTLVMap("子map")
|
||||||
|
//群主的18: 05 00 04 00 00 00 03 08 00 04 00 00 00 04 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08
|
||||||
|
|
||||||
when {
|
when {
|
||||||
tlv.containsKey(0x01) -> String(tlv.getValue(0x01))
|
tlv.containsKey(0x01) -> String(tlv.getValue(0x01))
|
||||||
@ -155,28 +183,48 @@ class ServerGroupMessageEventPacket(input: ByteReadPacket, packetId: ByteArray,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//牛逼[图片]牛逼[图片] 22 96 29 7B B4 DF 94 AA 00 08 74 A4 09 18 8D CC 1F 40 00 52 00 00 00 1B 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 0C 00 05 00 01 00 01 01 22 96 29 7B 01 3E 03 3F A2 00 03 7F 64 5D 7B AC BD 00 00 F3 36 02 03 00 02 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00 5D 7B AC BD 12 73 DB A2 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 03 00 CB 02 00 2A 7B 37 41 41 34 42 33 41 41 2D 38 43 33 43 2D 30 46 34 35 2D 32 44 39 42 2D 37 46 33 30 32 41 30 41 43 45 41 41 7D 2E 6A 70 67 04 00 04 B4 52 77 F1 05 00 04 BC EB 03 B7 06 00 04 00 00 00 50 07 00 01 43 08 00 00 09 00 01 01 0B 00 00 14 00 04 00 00 00 00 15 00 04 00 00 00 41 16 00 04 00 00 00 34 18 00 04 00 00 03 73 FF 00 5C 15 36 20 39 32 6B 41 31 43 62 34 35 32 37 37 66 31 62 63 65 62 30 33 62 37 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7B 37 41 41 34 42 33 41 41 2D 38 43 33 43 2D 30 46 34 35 2D 32 44 39 42 2D 37 46 33 30 32 41 30 41 43 45 41 41 7D 2E 6A 70 67 41 01 00 09 01 00 06 E7 89 9B E9 80 BC 03 00 77 02 00 2A 7B 37 41 41 34 42 33 41 41 2D 38 43 33 43 2D 30 46 34 35 2D 32 44 39 42 2D 37 46 33 30 32 41 30 41 43 45 41 41 7D 2E 6A 70 67 04 00 04 B4 52 77 F1 05 00 04 BC EB 03 B7 06 00 04 00 00 00 50 07 00 01 43 08 00 00 09 00 01 01 0B 00 00 14 00 04 00 00 00 00 15 00 04 00 00 00 41 16 00 04 00 00 00 34 18 00 04 00 00 03 73 FF 00 08 15 37 20 20 38 41 41 41 0E 00 0E 01 00 04 00 00 00 09 07 00 04 00 00 00 01 19 00 35 01 00 32 AA 02 2F 50 03 60 00 68 00 9A 01 26 08 09 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 B8 03 00 C0 03 00 D0 03 00 E8 03 00 12 00 25 05 00 04 00 00 00 01 08 00 04 00 00 00 01 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08
|
//
|
||||||
//牛逼[图片]牛逼 22 96 29 7B B4 DF 94 AA 00 0B C1 0A 09 18 89 93 1F 40 00 52 00 00 00 1B 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 0C 00 05 00 01 00 01 01 22 96 29 7B 01 3E 03 3F A2 00 03 7E F5 5D 7B 97 E7 00 00 F3 32 01 8D 00 02 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00 5D 7B 97 E6 FA BE 7F DC 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 03 00 CF 02 00 2A 7B 39 44 32 44 45 39 31 41 2D 33 39 38 39 2D 39 35 35 43 2D 44 35 42 34 2D 37 46 41 32 37 38 39 37 38 36 30 39 7D 2E 6A 70 67 04 00 04 97 15 7F 03 05 00 04 79 5C B1 A3 06 00 04 00 00 00 50 07 00 01 41 08 00 00 09 00 01 01 0B 00 00 14 00 04 03 00 00 00 15 00 04 00 00 00 3C 16 00 04 00 00 00 40 18 00 04 00 00 03 CC FF 00 60 15 36 20 39 36 6B 45 31 41 39 37 31 35 37 66 30 33 37 39 35 63 62 31 61 33 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7B 39 44 32 44 45 39 31 41 2D 33 39 38 39 2D 39 35 35 43 2D 44 35 42 34 2D 37 46 41 32 37 38 39 37 38 36 30 39 7D 2E 6A 70 67 31 32 31 32 41 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 0E 01 00 04 00 00 00 09 07 00 04 00 00 00 01 19 00 35 01 00 32 AA 02 2F 50 03 60 00 68 00 9A 01 26 08 09 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 B8 03 00 C0 03 00 D0 03 00 E8 03 00 12 00 25 05 00 04 00 00 00 01 08 00 04 00 00 00 01 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08
|
//以前的消息: 00 00 00 25 00 08 00 02 00 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD 58 2C 60 86 35 3A 30 B3 C7 63 4A 80 E7 CD 5B 64 00 0B 78 16 5D A3 0A FD 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A3 0A FD AB 77 16 02 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 04 01 00 01 36 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
|
||||||
|
//刚刚的消息: 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD 11 F4 B2 F2 1A E7 1F C4 F1 3F 23 FB 74 80 42 64 00 0B 78 1A 5D A3 26 C1 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A3 26 C1 AA 34 08 42 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E4 BD A0 E5 A5 BD 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
|
||||||
|
|
||||||
class ServerFriendMessageEventPacket(input: ByteReadPacket, packetId: ByteArray, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, packetId, eventIdentity) {
|
fun main() {
|
||||||
val group: UInt get() = eventIdentity.from
|
println("08 02 1A 12 08 95 02 10 90 04 40 D6 DE 8C ED 05 48 CF B5 90 D6 02 08 DD F1 92 B7 07 10 DD F1 92 B7 07 1A 14 08 00 10 05 18 D6 DE 8C ED 05 20 02 28 FF FF FF FF 0F 32 00".hexToBytes().stringOf())
|
||||||
val qq: UInt get() = eventIdentity.to
|
}
|
||||||
|
|
||||||
|
fun main2() {
|
||||||
|
val data = "00 00 00 20 00 05 00 02 00 06 00 06 00 04 00 01 01 07 00 09 00 06 03 E9 20 02 EB 94 00 0A 00 04 01 00 00 00 0C 17 76 E4 B8 DD 76 E4 B8 DD 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0B A6 D2 5D A3 2A 3F 00 00 5D A3 2A 3F 01 00 00 00 00 4D 53 47 00 00 00 00 00 5D A3 2A 3F 0C 8A 59 3D 00 00 00 00 0A 00 86 02 00 06 E5 AE 8B E4 BD 93 00 00 01 00 06 01 00 03 31 32 33 19 00 1F 01 00 1C AA 02 19 08 00 88 01 00 9A 01 11 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00 0E 00 0E 01 00 04 00 00 00 00 0A 00 04 00 00 00 00".hexToBytes()
|
||||||
|
val packet = ServerFriendMessageEventPacket(data.toReadPacket(), EventPacketIdentity(0u, 0u, IoBuffer.Empty))
|
||||||
|
packet.decode()
|
||||||
|
println(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
class ServerFriendMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
|
||||||
|
val qq: UInt get() = eventIdentity.from
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否是在这次登录之前的消息, 即消息记录
|
||||||
|
*/
|
||||||
|
var isPrevious: Boolean = false
|
||||||
|
|
||||||
lateinit var message: MessageChain
|
lateinit var message: MessageChain
|
||||||
|
|
||||||
//00 00 00 25 00 08 00 02 00 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD E7 86 74 F2 64 55 AD 9A EB 2F B9 DF F1 7F 8C 28 00 0B 78 14 5D A2 F5 CB 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A2 F5 CA 9D 26 CB 5E 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E4 BD A0 E5 A5 BD 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
|
//来自自己发送给自己
|
||||||
|
//00 00 00 20 00 05 00 02 00 06 00 06 00 04 00 01 01 07 00 09 00 06 03 E9 20 02 EB 94 00 0A 00 04 01 00 00 00 0C 17 76 E4 B8 DD 76 E4 B8 DD 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0B A6 D2 5D A3 2A 3F 00 00 5D A3 2A 3F 01 00 00 00 00 4D 53 47 00 00 00 00 00 5D A3 2A 3F 0C 8A 59 3D 00 00 00 00 0A 00 86 02 00 06 E5 AE 8B E4 BD 93 00 00 01 00 06 01 00 03 31 32 33 19 00 1F 01 00 1C AA 02 19 08 00 88 01 00 9A 01 11 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00 0E 00 0E 01 00 04 00 00 00 00 0A 00 04 00 00 00 00
|
||||||
|
|
||||||
override fun decode() = with(input) {
|
override fun decode() = with(input) {
|
||||||
input.discardExact(2)
|
input.discardExact(2)
|
||||||
val l1 = readShort()
|
val l1 = readShort()
|
||||||
discardExact(l1.toInt())
|
discardExact(1)//0x00
|
||||||
|
isPrevious = readByte().toInt() == 0x08
|
||||||
|
discardExact(l1.toInt() - 2)
|
||||||
discardExact(69)
|
discardExact(69)
|
||||||
readLVByteArray()//font
|
readLVByteArray()//font
|
||||||
discardExact(2)//2个0x00
|
discardExact(2)//2个0x00
|
||||||
message = readMessageChain()
|
message = readMessageChain()
|
||||||
|
|
||||||
val map: Map<Int, ByteArray> = readTLVMap(true).withDefault { byteArrayOf() }
|
val map: Map<Int, ByteArray> = readTLVMap(true).withDefault { byteArrayOf() }
|
||||||
println("map.getValue(18)=" + map.getValue(18))
|
map.printTLVMap("readTLVMap")
|
||||||
|
//println("map.getValue(18)=" + map.getValue(18).toUHexString())
|
||||||
|
|
||||||
//19 00 38 01 00 35 AA 02 32 50 03 60 00 68 00 9A 01 29 08 09 20 BF 02 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 B8 03 00 C0 03 00 D0 03 00 E8 03 00 12 00 25 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08 05 00 04 00 00 00 01 08 00 04 00 00 00 01
|
//19 00 38 01 00 35 AA 02 32 50 03 60 00 68 00 9A 01 29 08 09 20 BF 02 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 B8 03 00 C0 03 00 D0 03 00 E8 03 00 12 00 25 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08 05 00 04 00 00 00 01 08 00 04 00 00 00 01
|
||||||
|
|
||||||
@ -232,7 +280,7 @@ B1 89 BE 09 8F 00 1A E5 00 0B 03 A2 09 90 BB 7A 1F 40 00 A6 00 00 00 20 00 05 00
|
|||||||
|
|
||||||
backup
|
backup
|
||||||
|
|
||||||
class ServerFriendMessageEventPacket(input: ByteReadPacket, packetId: ByteArray, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, packetId, eventIdentity) {
|
class ServerFriendMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
|
||||||
var qq: Long = 0
|
var qq: Long = 0
|
||||||
lateinit var event: String
|
lateinit var event: String
|
||||||
|
|
||||||
|
@ -18,12 +18,12 @@ class ClientSendFriendMessagePacket(
|
|||||||
private val message: MessageChain
|
private val message: MessageChain
|
||||||
) : ClientPacket() {
|
) : ClientPacket() {
|
||||||
override fun encode(builder: BytePacketBuilder) = with(builder) {
|
override fun encode(builder: BytePacketBuilder) = with(builder) {
|
||||||
this.writeRandom(2)
|
writeRandom(2)
|
||||||
|
|
||||||
this.writeQQ(botQQ)
|
writeQQ(botQQ)
|
||||||
this.writeHex(TIMProtocol.fixVer2)
|
writeHex(TIMProtocol.fixVer2)
|
||||||
|
|
||||||
this.encryptAndWrite(sessionKey) {
|
encryptAndWrite(sessionKey) {
|
||||||
writeQQ(botQQ)
|
writeQQ(botQQ)
|
||||||
writeQQ(targetQQ)
|
writeQQ(targetQQ)
|
||||||
writeHex("00 00 00 08 00 01 00 04 00 00 00 00")
|
writeHex("00 00 00 08 00 01 00 04 00 00 00 00")
|
||||||
|
@ -86,7 +86,7 @@ fun ByteReadPacket.parseServerPacket(size: Int): ServerPacket {//TODO 优化
|
|||||||
"00 BA" -> ServerCaptchaPacket.Encrypted(this, idHex)
|
"00 BA" -> ServerCaptchaPacket.Encrypted(this, idHex)
|
||||||
|
|
||||||
|
|
||||||
"00 CE", "00 17" -> ServerEventPacket.Raw.Encrypted(this, idHex.hexToBytes())
|
"00 CE", "00 17" -> ServerEventPacket.Raw.Encrypted(this)
|
||||||
|
|
||||||
"00 81" -> ServerFieldOnlineStatusChangedPacket.Encrypted(this)
|
"00 81" -> ServerFieldOnlineStatusChangedPacket.Encrypted(this)
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ fun ByteReadPacket.parseServerPacket(size: Int): ServerPacket {//TODO 优化
|
|||||||
}.setId(idHex)
|
}.setId(idHex)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ByteReadPacket.readIP(): String = buildString(4 + 3) {
|
fun Input.readIP(): String = buildString(4 + 3) {
|
||||||
repeat(4) {
|
repeat(4) {
|
||||||
val byte = readUByte()
|
val byte = readUByte()
|
||||||
this.append(byte.toString())
|
this.append(byte.toString())
|
||||||
@ -110,11 +110,11 @@ fun ByteReadPacket.readIP(): String = buildString(4 + 3) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ByteReadPacket.readLVString(): String = String(this.readLVByteArray())
|
fun Input.readLVString(): String = String(this.readLVByteArray())
|
||||||
|
|
||||||
fun ByteReadPacket.readLVByteArray(): ByteArray = this.readBytes(this.readShort().toInt())
|
fun Input.readLVByteArray(): ByteArray = this.readBytes(this.readShort().toInt())
|
||||||
|
|
||||||
fun ByteReadPacket.readTLVMap(expectingEOF: Boolean = false): Map<Int, ByteArray> {
|
fun Input.readTLVMap(expectingEOF: Boolean = false): Map<Int, ByteArray> {
|
||||||
val map = mutableMapOf<Int, ByteArray>()
|
val map = mutableMapOf<Int, ByteArray>()
|
||||||
var type: UByte
|
var type: UByte
|
||||||
|
|
||||||
@ -144,11 +144,11 @@ fun ByteReadPacket.readTLVMap(expectingEOF: Boolean = false): Map<Int, ByteArray
|
|||||||
|
|
||||||
fun Map<Int, ByteArray>.printTLVMap(name: String) = debugPrintln("TLVMap $name= " + this.mapValues { (_, value) -> value.toUHexString() })
|
fun Map<Int, ByteArray>.printTLVMap(name: String) = debugPrintln("TLVMap $name= " + this.mapValues { (_, value) -> value.toUHexString() })
|
||||||
|
|
||||||
fun ByteReadPacket.readString(length: Number): String = String(this.readBytes(length.toInt()))
|
fun Input.readString(length: Number): String = String(this.readBytes(length.toInt()))
|
||||||
|
|
||||||
private const val TRUE_BYTE_VALUE: Byte = 1
|
private const val TRUE_BYTE_VALUE: Byte = 1
|
||||||
fun ByteReadPacket.readBoolean(): Boolean = this.readByte() == TRUE_BYTE_VALUE
|
fun Input.readBoolean(): Boolean = this.readByte() == TRUE_BYTE_VALUE
|
||||||
fun ByteReadPacket.readLVNumber(): Number {
|
fun Input.readLVNumber(): Number {
|
||||||
return when (this.readShort().toInt()) {
|
return when (this.readShort().toInt()) {
|
||||||
1 -> this.readByte()
|
1 -> this.readByte()
|
||||||
2 -> this.readShort()
|
2 -> this.readShort()
|
||||||
@ -161,7 +161,7 @@ fun ByteReadPacket.readLVNumber(): Number {
|
|||||||
//添加@JvmSynthetic 导致 idea 无法检查这个文件的错误
|
//添加@JvmSynthetic 导致 idea 无法检查这个文件的错误
|
||||||
//@JvmSynthetic
|
//@JvmSynthetic
|
||||||
@Deprecated("Low efficiency", ReplaceWith(""))
|
@Deprecated("Low efficiency", ReplaceWith(""))
|
||||||
fun ByteReadPacket.gotoWhere(matcher: UByteArray): ByteReadPacket {
|
fun <I : Input> I.gotoWhere(matcher: UByteArray): I {
|
||||||
return this.gotoWhere(matcher.toByteArray())
|
return this.gotoWhere(matcher.toByteArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ fun ByteReadPacket.gotoWhere(matcher: UByteArray): ByteReadPacket {
|
|||||||
* 去往下一个含这些连续字节的位置
|
* 去往下一个含这些连续字节的位置
|
||||||
*/
|
*/
|
||||||
@Deprecated("Low efficiency", ReplaceWith(""))
|
@Deprecated("Low efficiency", ReplaceWith(""))
|
||||||
fun ByteReadPacket.gotoWhere(matcher: ByteArray): ByteReadPacket {
|
fun <I : Input> I.gotoWhere(matcher: ByteArray): I {
|
||||||
require(matcher.isNotEmpty())
|
require(matcher.isNotEmpty())
|
||||||
|
|
||||||
loop@
|
loop@
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.mamoe.mirai.utils
|
package net.mamoe.mirai.utils
|
||||||
|
|
||||||
|
import kotlinx.io.core.ByteReadPacket
|
||||||
import kotlinx.io.core.Input
|
import kotlinx.io.core.Input
|
||||||
import kotlinx.io.core.IoBuffer
|
import kotlinx.io.core.IoBuffer
|
||||||
import kotlinx.io.core.readBytes
|
import kotlinx.io.core.readBytes
|
||||||
@ -9,20 +10,26 @@ internal object DebugLogger : MiraiLogger by PlatformLogger("Packet Debug")
|
|||||||
|
|
||||||
internal fun debugPrintln(any: Any?) = DebugLogger.logPurple(any)
|
internal fun debugPrintln(any: Any?) = DebugLogger.logPurple(any)
|
||||||
|
|
||||||
@Deprecated("Debugging Warning", ReplaceWith(""))
|
|
||||||
internal fun ByteArray.debugPrint(name: String): ByteArray {
|
internal fun ByteArray.debugPrint(name: String): ByteArray {
|
||||||
DebugLogger.logPurple(name + "=" + this.toUHexString())
|
DebugLogger.logPurple(name + "=" + this.toUHexString())
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("Debugging Warning", ReplaceWith(""))
|
@Deprecated("Low Efficiency", ReplaceWith(""))
|
||||||
internal fun IoBuffer.debugPrint(name: String): IoBuffer {
|
internal fun IoBuffer.debugPrint(name: String): IoBuffer {
|
||||||
val readBytes = this.readBytes()
|
val readBytes = this.readBytes()
|
||||||
DebugLogger.logPurple(name + "=" + readBytes.toUHexString())
|
DebugLogger.logPurple(name + "=" + readBytes.toUHexString())
|
||||||
return readBytes.toIoBuffer()
|
return readBytes.toIoBuffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("Debugging Warning", ReplaceWith(""))
|
@Deprecated("Low Efficiency", ReplaceWith("discardExact(n)"))
|
||||||
internal fun Input.debugDiscardExact(n: Number, name: String = "") {
|
internal fun Input.debugDiscardExact(n: Number, name: String = "") {
|
||||||
DebugLogger.logPurple("Discarded($n) $name=" + this.readBytes(n.toInt()).toUHexString())
|
DebugLogger.logPurple("Discarded($n) $name=" + this.readBytes(n.toInt()).toUHexString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated("Low Efficiency", ReplaceWith(""))
|
||||||
|
internal fun ByteReadPacket.debugPrint(name: String = ""): ByteReadPacket {
|
||||||
|
val bytes = this.readBytes()
|
||||||
|
DebugLogger.logPurple("ByteReadPacket $name=" + bytes.toUHexString())
|
||||||
|
return bytes.toReadPacket()
|
||||||
|
}
|
||||||
|
@ -11,4 +11,6 @@ expect class MiraiDatagramChannel(serverHost: String, serverPort: Short) : Close
|
|||||||
val isOpen: Boolean
|
val isOpen: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
expect class ClosedChannelException : IOException
|
expect class ClosedChannelException : IOException
|
||||||
|
|
||||||
|
expect class SendPacketInternalException(cause: Throwable?) : Exception
|
@ -14,7 +14,15 @@ actual class MiraiDatagramChannel actual constructor(serverHost: String, serverP
|
|||||||
private val channel: DatagramChannel = DatagramChannel.open().connect(serverAddress)
|
private val channel: DatagramChannel = DatagramChannel.open().connect(serverAddress)
|
||||||
|
|
||||||
actual suspend fun read(buffer: IoBuffer) = withContext(Dispatchers.IO) { (channel as ReadableByteChannel).read(buffer) }
|
actual suspend fun read(buffer: IoBuffer) = withContext(Dispatchers.IO) { (channel as ReadableByteChannel).read(buffer) }
|
||||||
actual suspend fun send(buffer: IoBuffer) = withContext(Dispatchers.IO) { buffer.readDirect { channel.send(it, serverAddress) } }
|
actual suspend fun send(buffer: IoBuffer) = withContext(Dispatchers.IO) {
|
||||||
|
buffer.readDirect {
|
||||||
|
try {
|
||||||
|
channel.send(it, serverAddress)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw SendPacketInternalException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
channel.close()
|
channel.close()
|
||||||
@ -23,4 +31,6 @@ actual class MiraiDatagramChannel actual constructor(serverHost: String, serverP
|
|||||||
actual val isOpen: Boolean get() = channel.isOpen
|
actual val isOpen: Boolean get() = channel.isOpen
|
||||||
}
|
}
|
||||||
|
|
||||||
actual typealias ClosedChannelException = java.nio.channels.ClosedChannelException
|
actual typealias ClosedChannelException = java.nio.channels.ClosedChannelException
|
||||||
|
|
||||||
|
actual class SendPacketInternalException actual constructor(cause: Throwable?) : Exception(cause)
|
@ -20,14 +20,10 @@ import kotlin.math.max
|
|||||||
object HexComparator {
|
object HexComparator {
|
||||||
|
|
||||||
private val RED = "\u001b[31m"
|
private val RED = "\u001b[31m"
|
||||||
|
|
||||||
private val GREEN = "\u001b[33m"
|
private val GREEN = "\u001b[33m"
|
||||||
|
|
||||||
private val UNKNOWN = "\u001b[30m"
|
private val UNKNOWN = "\u001b[30m"
|
||||||
|
|
||||||
private val BLUE = "\u001b[34m"
|
private val BLUE = "\u001b[34m"
|
||||||
|
|
||||||
|
|
||||||
private val clipboardString: String?
|
private val clipboardString: String?
|
||||||
get() {
|
get() {
|
||||||
val trans = Toolkit.getDefaultToolkit().systemClipboard.getContents(null)
|
val trans = Toolkit.getDefaultToolkit().systemClipboard.getContents(null)
|
||||||
@ -44,7 +40,6 @@ object HexComparator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ConstMatcher constructor(hex: String) {
|
class ConstMatcher constructor(hex: String) {
|
||||||
|
|
||||||
private val matches = LinkedList<Match>()
|
private val matches = LinkedList<Match>()
|
||||||
|
|
||||||
object TestConsts {
|
object TestConsts {
|
||||||
@ -59,6 +54,7 @@ object HexComparator {
|
|||||||
val _Him188moe_ = "Him188moe".toByteArray().toUHexString()
|
val _Him188moe_ = "Him188moe".toByteArray().toUHexString()
|
||||||
val 发图片 = "发图片".toByteArray().toUHexString()
|
val 发图片 = "发图片".toByteArray().toUHexString()
|
||||||
val 群 = "群".toByteArray().toUHexString()
|
val 群 = "群".toByteArray().toUHexString()
|
||||||
|
val 你好 = "你好".toByteArray().toUHexString()
|
||||||
|
|
||||||
val SINGLE_PLAIN_MESSAGE_HEAD = "00 00 01 00 09 01"
|
val SINGLE_PLAIN_MESSAGE_HEAD = "00 00 01 00 09 01"
|
||||||
|
|
||||||
@ -69,7 +65,8 @@ object HexComparator {
|
|||||||
@Suppress("SpellCheckingInspection")
|
@Suppress("SpellCheckingInspection")
|
||||||
object PacketIds {
|
object PacketIds {
|
||||||
val heartbeat = "00 58"
|
val heartbeat = "00 58"
|
||||||
val friendmsg = "00 CD"
|
val friendmsgsend = "00 CD"
|
||||||
|
val friendmsgevent = "00 CE"
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -104,7 +101,6 @@ object HexComparator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun match(hex: String, field: Field): List<IntRange> {
|
private fun match(hex: String, field: Field): List<IntRange> {
|
||||||
val constValue: String
|
val constValue: String
|
||||||
try {
|
try {
|
||||||
@ -293,6 +289,10 @@ object HexComparator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
|
// println(HexComparator.colorize("00 00 00 25 00 08 00 02 00 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD E7 86 74 F2 64 55 AD 9A EB 2F B9 DF F1 7F 8C 28 00 0B 78 14 5D A2 F5 CB 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A2 F5 CA 9D 26 CB 5E 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E4 BD A0 E5 A5 BD 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00"))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val scanner = Scanner(System.`in`)
|
val scanner = Scanner(System.`in`)
|
||||||
while (true) {
|
while (true) {
|
||||||
println("Hex1: ")
|
println("Hex1: ")
|
||||||
|
Loading…
Reference in New Issue
Block a user