|
@@ -1,13 +1,13 @@
|
|
|
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS", "unused", "MemberVisibilityCanBePrivate")
|
|
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS", "unused", "MemberVisibilityCanBePrivate")
|
|
|
|
|
|
|
|
-package net.mamoe.mirai.timpc.network.packet
|
|
|
|
|
|
|
+package net.mamoe.mirai.network.packet
|
|
|
|
|
|
|
|
import kotlinx.io.core.*
|
|
import kotlinx.io.core.*
|
|
|
import kotlinx.serialization.SerializationStrategy
|
|
import kotlinx.serialization.SerializationStrategy
|
|
|
import kotlinx.serialization.protobuf.ProtoBuf
|
|
import kotlinx.serialization.protobuf.ProtoBuf
|
|
|
-import net.mamoe.mirai.network.BotNetworkHandler
|
|
|
|
|
import net.mamoe.mirai.data.Packet
|
|
import net.mamoe.mirai.data.Packet
|
|
|
-import net.mamoe.mirai.timpc.network.TIMProtocol
|
|
|
|
|
|
|
+import net.mamoe.mirai.network.BotNetworkHandler
|
|
|
|
|
+import net.mamoe.mirai.utils.MiraiInternalAPI
|
|
|
import net.mamoe.mirai.utils.io.hexToBytes
|
|
import net.mamoe.mirai.utils.io.hexToBytes
|
|
|
import net.mamoe.mirai.utils.io.writeQQ
|
|
import net.mamoe.mirai.utils.io.writeQQ
|
|
|
import kotlin.contracts.ExperimentalContracts
|
|
import kotlin.contracts.ExperimentalContracts
|
|
@@ -18,11 +18,11 @@ import kotlin.jvm.JvmOverloads
|
|
|
/**
|
|
/**
|
|
|
* 待发送给服务器的数据包. 它代表着一个 [ByteReadPacket],
|
|
* 待发送给服务器的数据包. 它代表着一个 [ByteReadPacket],
|
|
|
*/
|
|
*/
|
|
|
-internal class OutgoingPacket(
|
|
|
|
|
|
|
+class OutgoingPacket(
|
|
|
name: String?,
|
|
name: String?,
|
|
|
val packetId: PacketId,
|
|
val packetId: PacketId,
|
|
|
val sequenceId: UShort,
|
|
val sequenceId: UShort,
|
|
|
- internal val delegate: ByteReadPacket
|
|
|
|
|
|
|
+ val delegate: ByteReadPacket
|
|
|
) : Packet {
|
|
) : Packet {
|
|
|
val name: String by lazy {
|
|
val name: String by lazy {
|
|
|
name ?: packetId.toString()
|
|
name ?: packetId.toString()
|
|
@@ -35,7 +35,9 @@ internal class OutgoingPacket(
|
|
|
*
|
|
*
|
|
|
* @param TPacket invariant
|
|
* @param TPacket invariant
|
|
|
*/
|
|
*/
|
|
|
-internal abstract class SessionPacketFactory<TPacket : Packet> : PacketFactory<TPacket, SessionKey>(SessionKey) {
|
|
|
|
|
|
|
+abstract class SessionPacketFactory<TPacket : Packet> : PacketFactory<TPacket, SessionKey>(
|
|
|
|
|
+ SessionKey
|
|
|
|
|
+) {
|
|
|
/**
|
|
/**
|
|
|
* 在 [BotNetworkHandler] 下处理这个包. 广播事件等.
|
|
* 在 [BotNetworkHandler] 下处理这个包. 广播事件等.
|
|
|
*/
|
|
*/
|
|
@@ -45,13 +47,16 @@ internal abstract class SessionPacketFactory<TPacket : Packet> : PacketFactory<T
|
|
|
/**
|
|
/**
|
|
|
* 构造一个待发送给服务器的数据包.
|
|
* 构造一个待发送给服务器的数据包.
|
|
|
*/
|
|
*/
|
|
|
-@UseExperimental(ExperimentalContracts::class)
|
|
|
|
|
|
|
+@UseExperimental(ExperimentalContracts::class, MiraiInternalAPI::class)
|
|
|
@JvmOverloads
|
|
@JvmOverloads
|
|
|
-internal inline fun PacketFactory<*, *>.buildOutgoingPacket(
|
|
|
|
|
|
|
+inline fun PacketFactory<*, *>.buildOutgoingPacket0(
|
|
|
name: String? = null,
|
|
name: String? = null,
|
|
|
id: PacketId = this.id,
|
|
id: PacketId = this.id,
|
|
|
sequenceId: UShort = PacketFactory.atomicNextSequenceId(),
|
|
sequenceId: UShort = PacketFactory.atomicNextSequenceId(),
|
|
|
headerSizeHint: Int = 0,
|
|
headerSizeHint: Int = 0,
|
|
|
|
|
+ head: ByteArray,
|
|
|
|
|
+ ver: ByteArray,
|
|
|
|
|
+ tail: ByteArray,
|
|
|
block: BytePacketBuilder.() -> Unit
|
|
block: BytePacketBuilder.() -> Unit
|
|
|
): OutgoingPacket {
|
|
): OutgoingPacket {
|
|
|
contract {
|
|
contract {
|
|
@@ -60,12 +65,12 @@ internal inline fun PacketFactory<*, *>.buildOutgoingPacket(
|
|
|
|
|
|
|
|
BytePacketBuilder(headerSizeHint).use {
|
|
BytePacketBuilder(headerSizeHint).use {
|
|
|
with(it) {
|
|
with(it) {
|
|
|
- writeFully(TIMProtocol.head)
|
|
|
|
|
- writeFully(TIMProtocol.ver)
|
|
|
|
|
|
|
+ writeFully(head)
|
|
|
|
|
+ writeFully(ver)
|
|
|
writeUShort(id.value)
|
|
writeUShort(id.value)
|
|
|
writeUShort(sequenceId)
|
|
writeUShort(sequenceId)
|
|
|
block(this)
|
|
block(this)
|
|
|
- writeFully(TIMProtocol.tail)
|
|
|
|
|
|
|
+ writeFully(tail)
|
|
|
}
|
|
}
|
|
|
return OutgoingPacket(name, id, sequenceId, it.build())
|
|
return OutgoingPacket(name, id, sequenceId, it.build())
|
|
|
}
|
|
}
|
|
@@ -75,22 +80,33 @@ internal inline fun PacketFactory<*, *>.buildOutgoingPacket(
|
|
|
/**
|
|
/**
|
|
|
* 构造一个待发送给服务器的会话数据包.
|
|
* 构造一个待发送给服务器的会话数据包.
|
|
|
*/
|
|
*/
|
|
|
-@UseExperimental(ExperimentalContracts::class)
|
|
|
|
|
|
|
+@UseExperimental(ExperimentalContracts::class, MiraiInternalAPI::class)
|
|
|
@JvmOverloads
|
|
@JvmOverloads
|
|
|
-internal inline fun PacketFactory<*, *>.buildSessionPacket(
|
|
|
|
|
|
|
+inline fun PacketFactory<*, *>.buildSessionPacket0(
|
|
|
bot: Long,
|
|
bot: Long,
|
|
|
sessionKey: SessionKey,
|
|
sessionKey: SessionKey,
|
|
|
name: String? = null,
|
|
name: String? = null,
|
|
|
id: PacketId = this.id,
|
|
id: PacketId = this.id,
|
|
|
sequenceId: UShort = PacketFactory.atomicNextSequenceId(),
|
|
sequenceId: UShort = PacketFactory.atomicNextSequenceId(),
|
|
|
headerSizeHint: Int = 0,
|
|
headerSizeHint: Int = 0,
|
|
|
- version: ByteArray = TIMProtocol.version0x02,
|
|
|
|
|
|
|
+ version: ByteArray, // in packet body
|
|
|
|
|
+ head: ByteArray,
|
|
|
|
|
+ ver: ByteArray, // in packet head
|
|
|
|
|
+ tail: ByteArray,
|
|
|
block: BytePacketBuilder.() -> Unit
|
|
block: BytePacketBuilder.() -> Unit
|
|
|
): OutgoingPacket {
|
|
): OutgoingPacket {
|
|
|
contract {
|
|
contract {
|
|
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
|
|
}
|
|
}
|
|
|
- return buildOutgoingPacket(name, id, sequenceId, headerSizeHint) {
|
|
|
|
|
|
|
+ return buildOutgoingPacket0(
|
|
|
|
|
+ name = name,
|
|
|
|
|
+ id = id,
|
|
|
|
|
+ sequenceId = sequenceId,
|
|
|
|
|
+ headerSizeHint = headerSizeHint,
|
|
|
|
|
+ head = head,
|
|
|
|
|
+ ver = ver,
|
|
|
|
|
+ tail = tail
|
|
|
|
|
+ ) {
|
|
|
writeQQ(bot)
|
|
writeQQ(bot)
|
|
|
writeFully(version)
|
|
writeFully(version)
|
|
|
encryptAndWrite(sessionKey) {
|
|
encryptAndWrite(sessionKey) {
|
|
@@ -102,22 +118,25 @@ internal inline fun PacketFactory<*, *>.buildSessionPacket(
|
|
|
/**
|
|
/**
|
|
|
* 构造一个待发送给服务器的会话数据包.
|
|
* 构造一个待发送给服务器的会话数据包.
|
|
|
*/
|
|
*/
|
|
|
-@UseExperimental(ExperimentalContracts::class)
|
|
|
|
|
|
|
+@UseExperimental(ExperimentalContracts::class, MiraiInternalAPI::class)
|
|
|
@JvmOverloads
|
|
@JvmOverloads
|
|
|
-internal fun <T> PacketFactory<*, *>.buildSessionProtoPacket(
|
|
|
|
|
|
|
+fun <T> PacketFactory<*, *>.buildSessionProtoPacket0(
|
|
|
bot: Long,
|
|
bot: Long,
|
|
|
sessionKey: SessionKey,
|
|
sessionKey: SessionKey,
|
|
|
name: String? = null,
|
|
name: String? = null,
|
|
|
id: PacketId = this.id,
|
|
id: PacketId = this.id,
|
|
|
sequenceId: UShort = PacketFactory.atomicNextSequenceId(),
|
|
sequenceId: UShort = PacketFactory.atomicNextSequenceId(),
|
|
|
headerSizeHint: Int = 0,
|
|
headerSizeHint: Int = 0,
|
|
|
- version: ByteArray = TIMProtocol.version0x04,
|
|
|
|
|
|
|
+ version: ByteArray,
|
|
|
head: Any,
|
|
head: Any,
|
|
|
serializer: SerializationStrategy<T>,
|
|
serializer: SerializationStrategy<T>,
|
|
|
- protoObj: T
|
|
|
|
|
|
|
+ protoObj: T,
|
|
|
|
|
+ packetHead: ByteArray,
|
|
|
|
|
+ ver: ByteArray, // in packet head
|
|
|
|
|
+ tail: ByteArray
|
|
|
): OutgoingPacket {
|
|
): OutgoingPacket {
|
|
|
require(head is ByteArray || head is UByteArray || head is String) { "Illegal head type" }
|
|
require(head is ByteArray || head is UByteArray || head is String) { "Illegal head type" }
|
|
|
- return buildOutgoingPacket(name, id, sequenceId, headerSizeHint) {
|
|
|
|
|
|
|
+ return buildOutgoingPacket0(name, id, sequenceId, headerSizeHint, head = packetHead, ver = ver, tail = tail) {
|
|
|
writeQQ(bot)
|
|
writeQQ(bot)
|
|
|
writeFully(version)
|
|
writeFully(version)
|
|
|
encryptAndWrite(sessionKey) {
|
|
encryptAndWrite(sessionKey) {
|
|
@@ -136,17 +155,20 @@ internal fun <T> PacketFactory<*, *>.buildSessionProtoPacket(
|
|
|
writeFully(head)
|
|
writeFully(head)
|
|
|
writeFully(proto)
|
|
writeFully(proto)
|
|
|
}
|
|
}
|
|
|
- is String -> buildSessionProtoPacket(
|
|
|
|
|
- bot,
|
|
|
|
|
- sessionKey,
|
|
|
|
|
- name,
|
|
|
|
|
- id,
|
|
|
|
|
- sequenceId,
|
|
|
|
|
- headerSizeHint,
|
|
|
|
|
- version,
|
|
|
|
|
- head.hexToBytes(),
|
|
|
|
|
- serializer,
|
|
|
|
|
- protoObj
|
|
|
|
|
|
|
+ is String -> buildSessionProtoPacket0(
|
|
|
|
|
+ bot = bot,
|
|
|
|
|
+ sessionKey = sessionKey,
|
|
|
|
|
+ name = name,
|
|
|
|
|
+ id = id,
|
|
|
|
|
+ sequenceId = sequenceId,
|
|
|
|
|
+ headerSizeHint = headerSizeHint,
|
|
|
|
|
+ version = version,
|
|
|
|
|
+ head = head.hexToBytes(),
|
|
|
|
|
+ serializer = serializer,
|
|
|
|
|
+ protoObj = protoObj,
|
|
|
|
|
+ packetHead = packetHead,
|
|
|
|
|
+ ver = ver,
|
|
|
|
|
+ tail = tail
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|