Ver código fonte

Move packet stuffs to mirai-core

Him188 6 anos atrás
pai
commit
c8eac6aff4
38 arquivos alterados com 376 adições e 223 exclusões
  1. 40 5
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/TIMPCBot.kt
  2. 3 3
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/TIMBotNetworkHandler.kt
  3. 97 0
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/OutgoingPacketHelper.kt
  4. 0 100
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/PacketId.kt
  5. 2 1
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/AddContact.kt
  6. 4 3
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/FriendImage.kt
  7. 2 2
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/FriendList.kt
  8. 2 1
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/GradeInfo.kt
  9. 2 1
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/GroupImage.kt
  10. 3 3
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/GroupPacket.kt
  11. 3 2
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/Profile.kt
  12. 2 1
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/Remark.kt
  13. 2 1
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/RequestFriendListPacket.kt
  14. 2 1
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/SendFriendMessagePacket.kt
  15. 1 1
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/event/AndroidOnlineStatusChange.kt
  16. 2 1
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/event/EventPacketFactory.kt
  17. 1 1
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/event/FriendAddRequestEventPacket.kt
  18. 1 2
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/event/FriendConversationIniliaze.kt
  19. 2 4
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/event/FriendOnlineStatusChanged.kt
  20. 1 1
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/event/GroupFileUpload.kt
  21. 3 3
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/event/MemberPermission.kt
  22. 1 1
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/event/MessageEvent.kt
  23. 4 2
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/login/Captcha.kt
  24. 5 2
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/login/ChangeOnlineStatusPacket.kt
  25. 2 1
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/login/Heartbeat.kt
  26. 4 2
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/login/PasswordSubmission.kt
  27. 2 1
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/login/SKey.kt
  28. 4 1
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/login/Session.kt
  29. 5 3
      mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/login/Touch.kt
  30. 11 11
      mirai-core-timpc/src/jvmTest/kotlin/PacketDebugger.kt
  31. 2 2
      mirai-core-timpc/src/jvmTest/kotlin/packetdebugger/PacketDecoder.kt
  32. 6 2
      mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt
  33. 3 3
      mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/packet/Annotations.kt
  34. 14 16
      mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/packet/Decrypters.kt
  35. 53 31
      mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/packet/OutgoingPacket.kt
  36. 4 4
      mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/packet/Packet.kt
  37. 5 4
      mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/packet/PacketFactory.kt
  38. 76 0
      mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/packet/PacketId.kt

+ 40 - 5
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/TIMPCBot.kt

@@ -11,6 +11,9 @@ import net.mamoe.mirai.data.Packet
 import net.mamoe.mirai.message.data.Image
 import net.mamoe.mirai.message.data.ImageId0x03
 import net.mamoe.mirai.message.data.ImageId0x06
+import net.mamoe.mirai.network.packet.KnownPacketId
+import net.mamoe.mirai.network.packet.OutgoingPacket
+import net.mamoe.mirai.network.packet.SessionKey
 import net.mamoe.mirai.qqAccount
 import net.mamoe.mirai.timpc.internal.RawGroupInfo
 import net.mamoe.mirai.timpc.network.GroupImpl
@@ -18,10 +21,10 @@ import net.mamoe.mirai.timpc.network.MemberImpl
 import net.mamoe.mirai.timpc.network.QQImpl
 import net.mamoe.mirai.timpc.network.TIMBotNetworkHandler
 import net.mamoe.mirai.timpc.network.handler.TemporaryPacketHandler
-import net.mamoe.mirai.timpc.network.packet.KnownPacketId
-import net.mamoe.mirai.timpc.network.packet.OutgoingPacket
-import net.mamoe.mirai.timpc.network.packet.SessionKey
 import net.mamoe.mirai.timpc.network.packet.action.*
+import net.mamoe.mirai.timpc.network.packet.event.EventPacketFactory
+import net.mamoe.mirai.timpc.network.packet.event.FriendOnlineStatusChangedPacket
+import net.mamoe.mirai.timpc.network.packet.login.*
 import net.mamoe.mirai.timpc.utils.assertUnreachable
 import net.mamoe.mirai.utils.*
 import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail
@@ -44,9 +47,41 @@ internal abstract class TIMPCBotBase constructor(
     logger: MiraiLogger?,
     context: CoroutineContext
 ) : BotImpl<TIMBotNetworkHandler>(account, logger ?: DefaultLogger("Bot(" + account.id + ")"), context) {
+
+    @UseExperimental(ExperimentalUnsignedTypes::class)
     companion object {
         init {
-            KnownPacketId.values() /* load id classes */
+            KnownPacketId[0x0825u] = TouchPacket
+            KnownPacketId[0x0828u] = RequestSessionPacket
+            KnownPacketId[0x0836u] = SubmitPasswordPacket
+            KnownPacketId[0x00BAu] = CaptchaPacket
+            KnownPacketId[0x00CEu] = EventPacketFactory
+            KnownPacketId[0x0017u] = EventPacketFactory
+            KnownPacketId[0x0081u] = FriendOnlineStatusChangedPacket
+            KnownPacketId[0x00ECu] = ChangeOnlineStatusPacket
+
+            KnownPacketId[0x0058u] = HeartbeatPacket
+            KnownPacketId[0x001Du] = RequestSKeyPacket
+            KnownPacketId[0x005Cu] = RequestAccountInfoPacket
+            KnownPacketId[0x0002u] = GroupPacket
+            KnownPacketId[0x00CDu] = SendFriendMessagePacket
+            KnownPacketId[0x00A7u] = CanAddFriendPacket
+            KnownPacketId[0x00A8u] = AddFriendPacket
+            KnownPacketId[0x00AEu] = RequestFriendAdditionKeyPacket
+            KnownPacketId[0x0388u] = GroupImagePacket
+            KnownPacketId[0x0352u] = FriendImagePacket
+
+            KnownPacketId[0x0031u] = RequestProfileAvatarPacket
+            KnownPacketId[0x003Cu] = RequestProfileDetailsPacket
+            KnownPacketId[0x0126u] = QueryNicknamePacket
+
+            KnownPacketId[0x01BCu] = QueryPreviousNamePacket
+
+            KnownPacketId[0x003Eu] = QueryFriendRemarkPacket
+            // 031F  查询 "新朋友" 记录
+
+            // @Suppress("DEPRECATION")
+            // inline SUBMIT_IMAGE_FILE_NAME(0x01BDu, SubmitImageFilenamePacket),
         }
     }
 
@@ -69,7 +104,7 @@ internal abstract class TIMPCBotBase constructor(
                 reinitializeNetworkHandler(configuration, cause)
                 logger.info("Reconnected successfully")
                 return@launch
-            } catch (e: LoginFailedException){
+            } catch (e: LoginFailedException) {
                 delay(configuration.reconnectPeriodMillis)
             }
         }

+ 3 - 3
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/TIMBotNetworkHandler.kt

@@ -6,19 +6,19 @@ import kotlinx.coroutines.*
 import kotlinx.io.core.*
 import kotlinx.io.pool.useInstance
 import net.mamoe.mirai.Bot
+import net.mamoe.mirai.data.LoginResult
+import net.mamoe.mirai.data.Packet
 import net.mamoe.mirai.event.BroadcastControllable
 import net.mamoe.mirai.event.Cancellable
 import net.mamoe.mirai.event.Subscribable
 import net.mamoe.mirai.event.broadcast
 import net.mamoe.mirai.event.events.BotLoginSucceedEvent
 import net.mamoe.mirai.network.BotNetworkHandler
-import net.mamoe.mirai.data.LoginResult
-import net.mamoe.mirai.data.Packet
+import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.qqAccount
 import net.mamoe.mirai.timpc.TIMPCBot
 import net.mamoe.mirai.timpc.network.handler.DataPacketSocketAdapter
 import net.mamoe.mirai.timpc.network.handler.TemporaryPacketHandler
-import net.mamoe.mirai.timpc.network.packet.*
 import net.mamoe.mirai.timpc.network.packet.login.*
 import net.mamoe.mirai.utils.*
 import net.mamoe.mirai.utils.io.*

+ 97 - 0
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/OutgoingPacketHelper.kt

@@ -0,0 +1,97 @@
+package net.mamoe.mirai.timpc.network.packet
+
+import kotlinx.io.core.BytePacketBuilder
+import kotlinx.serialization.SerializationStrategy
+import net.mamoe.mirai.network.packet.*
+import net.mamoe.mirai.timpc.network.TIMProtocol
+import net.mamoe.mirai.utils.MiraiInternalAPI
+import kotlin.contracts.ExperimentalContracts
+import kotlin.contracts.InvocationKind
+import kotlin.contracts.contract
+import kotlin.jvm.JvmOverloads
+
+
+/**
+ * 构造一个待发送给服务器的数据包.
+ */
+@UseExperimental(ExperimentalContracts::class, MiraiInternalAPI::class, ExperimentalUnsignedTypes::class)
+@JvmOverloads
+inline fun PacketFactory<*, *>.buildOutgoingPacket(
+    name: String? = null,
+    id: PacketId = this.id,
+    sequenceId: UShort = PacketFactory.atomicNextSequenceId(),
+    headerSizeHint: Int = 0,
+    block: BytePacketBuilder.() -> Unit
+): OutgoingPacket {
+    contract {
+        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
+    }
+
+    return buildOutgoingPacket0(name, id, sequenceId, headerSizeHint, TIMProtocol.head, TIMProtocol.ver, TIMProtocol.tail, block)
+}
+
+
+/**
+ * 构造一个待发送给服务器的会话数据包.
+ */
+@UseExperimental(ExperimentalContracts::class, MiraiInternalAPI::class, ExperimentalUnsignedTypes::class)
+@JvmOverloads
+inline fun PacketFactory<*, *>.buildSessionPacket(
+    bot: Long,
+    sessionKey: SessionKey,
+    name: String? = null,
+    id: PacketId = this.id,
+    sequenceId: UShort = PacketFactory.atomicNextSequenceId(),
+    headerSizeHint: Int = 0,
+    version: ByteArray = TIMProtocol.version0x02, // in packet body
+    block: BytePacketBuilder.() -> Unit
+): OutgoingPacket {
+    contract {
+        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
+    }
+    return buildSessionPacket0(
+        bot = bot,
+        sessionKey = sessionKey,
+        name = name,
+        id = id,
+        sequenceId = sequenceId,
+        headerSizeHint = headerSizeHint,
+        version = version,
+        head = TIMProtocol.head,
+        ver = TIMProtocol.ver,
+        tail = TIMProtocol.tail,
+        block = block
+    )
+}
+
+/**
+ * 构造一个待发送给服务器的会话数据包.
+ */
+@UseExperimental(ExperimentalContracts::class, MiraiInternalAPI::class, ExperimentalUnsignedTypes::class)
+@JvmOverloads
+fun <T> PacketFactory<*, *>.buildSessionProtoPacket(
+    bot: Long,
+    sessionKey: SessionKey,
+    name: String? = null,
+    id: PacketId = this.id,
+    sequenceId: UShort = PacketFactory.atomicNextSequenceId(),
+    headerSizeHint: Int = 0,
+    version: ByteArray = TIMProtocol.version0x04,
+    head: Any,
+    serializer: SerializationStrategy<T>,
+    protoObj: T
+): OutgoingPacket = buildSessionProtoPacket0(
+    bot = bot,
+    sessionKey = sessionKey,
+    name = name,
+    id = id,
+    sequenceId = sequenceId,
+    headerSizeHint = headerSizeHint,
+    version = version,
+    head = head,
+    serializer = serializer,
+    protoObj = protoObj,
+    packetHead = TIMProtocol.head,
+    ver = TIMProtocol.ver,
+    tail = TIMProtocol.tail
+)

+ 0 - 100
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/PacketId.kt

@@ -1,100 +0,0 @@
-@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
-
-package net.mamoe.mirai.timpc.network.packet
-
-import net.mamoe.mirai.timpc.network.packet.action.*
-import net.mamoe.mirai.timpc.network.packet.event.EventPacketFactory
-import net.mamoe.mirai.timpc.network.packet.event.FriendOnlineStatusChangedPacket
-import net.mamoe.mirai.timpc.network.packet.login.*
-import net.mamoe.mirai.utils.io.toUHexString
-
-
-/**
- * 通过 [value] 匹配一个 [IgnoredPacketId] 或 [KnownPacketId], 无匹配则返回一个 [UnknownPacketId].
- */
-internal fun matchPacketId(value: UShort): PacketId =
-    IgnoredPacketIds.firstOrNull { it.value == value } ?: KnownPacketId.values().firstOrNull { it.value == value } ?: UnknownPacketId(value)
-
-/**
- * 包 ID.
- */
-internal interface PacketId {
-    val value: UShort
-    val factory: PacketFactory<*, *>
-}
-
-/**
- * 用于代表 `null`. 调用任何属性时都将会得到一个 [error]
- */
-@Suppress("unused")
-internal object NullPacketId : PacketId {
-    override val factory: PacketFactory<*, *> get() = error("uninitialized")
-    override val value: UShort get() = error("uninitialized")
-    override fun toString(): String = "NullPacketId"
-}
-
-/**
- * 未知的 [PacketId]
- */
-internal inline class UnknownPacketId(override inline val value: UShort) : PacketId {
-    override val factory: PacketFactory<*, *> get() = UnknownPacketFactory
-    override fun toString(): String = "UnknownPacketId(${value.toUHexString()})"
-}
-
-internal object IgnoredPacketIds : List<IgnoredPacketId> by {
-    listOf<UShort>(
-    ).map { IgnoredPacketId(it.toUShort()) }
-}()
-
-internal inline class IgnoredPacketId constructor(override val value: UShort) : PacketId {
-    override val factory: PacketFactory<*, *> get() = IgnoredPacketFactory
-    override fun toString(): String = "IgnoredPacketId(${value.toUHexString()})"
-}
-
-/**
- * 已知的 [matchPacketId]. 所有在 Mirai 中实现过的包都会使用这些 Id
- */
-@Suppress("unused")
-internal enum class KnownPacketId(override val value: UShort, override val factory: PacketFactory<*, *>) :
-    PacketId {
-    TOUCH(0x0825u, TouchPacket),
-    SESSION_KEY(0x0828u, RequestSessionPacket),
-    LOGIN(0x0836u, SubmitPasswordPacket),
-    CAPTCHA(0x00BAu, CaptchaPacket),
-    SERVER_EVENT_1(0x00CEu, EventPacketFactory),
-    SERVER_EVENT_2(0x0017u, EventPacketFactory),
-    FRIEND_ONLINE_STATUS_CHANGE(0x0081u, FriendOnlineStatusChangedPacket),
-    CHANGE_ONLINE_STATUS(0x00ECu, ChangeOnlineStatusPacket),
-
-    HEARTBEAT(0x0058u, HeartbeatPacket),
-    S_KEY(0x001Du, RequestSKeyPacket),
-    ACCOUNT_INFO(0x005Cu, RequestAccountInfoPacket),
-    GROUP_PACKET(0x0002u, GroupPacket),
-    SEND_FRIEND_MESSAGE(0x00CDu, SendFriendMessagePacket),
-    CAN_ADD_FRIEND(0x00A7u, CanAddFriendPacket),
-    ADD_FRIEND(0x00A8u, AddFriendPacket),
-    REQUEST_FRIEND_ADDITION_KEY(0x00AEu, RequestFriendAdditionKeyPacket),
-    GROUP_IMAGE_ID(0x0388u, GroupImagePacket),
-    FRIEND_IMAGE_ID(0x0352u, FriendImagePacket),
-
-    REQUEST_PROFILE_AVATAR(0x0031u, RequestProfileAvatarPacket),
-    REQUEST_PROFILE_DETAILS(0x003Cu, RequestProfileDetailsPacket),
-    QUERY_NICKNAME(0x0126u, QueryNicknamePacket),
-
-    QUERY_PREVIOUS_NAME(0x01BCu, QueryPreviousNamePacket),
-
-    QUERY_FRIEND_REMARK(0x003Eu, QueryFriendRemarkPacket)
-    // 031F  查询 "新朋友" 记录
-
-
-    // @Suppress("DEPRECATION")
-    // inline SUBMIT_IMAGE_FILE_NAME(0x01BDu, SubmitImageFilenamePacket),
-
-    ;
-
-    init {
-        factory._id = this
-    }
-
-    override fun toString(): String = (factory::class.simpleName ?: this.name) + "(${value.toUHexString()})"
-}

+ 2 - 1
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/AddContact.kt

@@ -8,8 +8,9 @@ import net.mamoe.mirai.network.BotNetworkHandler
 import net.mamoe.mirai.data.EventPacket
 import net.mamoe.mirai.data.Packet
 import net.mamoe.mirai.data.PreviousNameList
+import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.timpc.network.TIMProtocol
-import net.mamoe.mirai.timpc.network.packet.*
+import net.mamoe.mirai.timpc.network.packet.buildSessionPacket
 import net.mamoe.mirai.utils.io.*
 
 

+ 4 - 3
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/FriendImage.kt

@@ -4,14 +4,15 @@ package net.mamoe.mirai.timpc.network.packet.action
 
 import kotlinx.io.charsets.Charsets
 import kotlinx.io.core.*
+import net.mamoe.mirai.data.EventPacket
+import net.mamoe.mirai.data.ImageLink
 import net.mamoe.mirai.message.data.ImageId
 import net.mamoe.mirai.message.data.ImageId0x06
 import net.mamoe.mirai.message.data.requireLength
 import net.mamoe.mirai.network.BotNetworkHandler
-import net.mamoe.mirai.data.EventPacket
-import net.mamoe.mirai.data.ImageLink
+import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.timpc.network.TIMProtocol
-import net.mamoe.mirai.timpc.network.packet.*
+import net.mamoe.mirai.timpc.network.packet.buildSessionPacket
 import net.mamoe.mirai.utils.ExternalImage
 import net.mamoe.mirai.utils.io.*
 

+ 2 - 2
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/FriendList.kt

@@ -5,8 +5,8 @@ package net.mamoe.mirai.timpc.network.packet.action
 import kotlinx.io.core.ByteReadPacket
 import net.mamoe.mirai.network.BotNetworkHandler
 import net.mamoe.mirai.data.Packet
-import net.mamoe.mirai.timpc.network.packet.PacketId
-import net.mamoe.mirai.timpc.network.packet.SessionPacketFactory
+import net.mamoe.mirai.network.packet.PacketId
+import net.mamoe.mirai.network.packet.SessionPacketFactory
 
 
 // 0001

+ 2 - 1
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/GradeInfo.kt

@@ -7,8 +7,9 @@ import kotlinx.io.core.writeFully
 import kotlinx.io.core.writeUByte
 import net.mamoe.mirai.network.BotNetworkHandler
 import net.mamoe.mirai.data.Packet
+import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.timpc.network.TIMProtocol
-import net.mamoe.mirai.timpc.network.packet.*
+import net.mamoe.mirai.timpc.network.packet.buildOutgoingPacket
 import net.mamoe.mirai.utils.io.writeQQ
 
 /**

+ 2 - 1
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/GroupImage.kt

@@ -11,7 +11,8 @@ import net.mamoe.mirai.message.data.requireLength
 import net.mamoe.mirai.network.BotNetworkHandler
 import net.mamoe.mirai.data.EventPacket
 import net.mamoe.mirai.data.ImageLink
-import net.mamoe.mirai.timpc.network.packet.*
+import net.mamoe.mirai.network.packet.*
+import net.mamoe.mirai.timpc.network.packet.buildSessionProtoPacket
 import net.mamoe.mirai.timpc.utils.assertUnreachable
 import net.mamoe.mirai.utils.ExternalImage
 import net.mamoe.mirai.utils.io.toUHexString

+ 3 - 3
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/GroupPacket.kt

@@ -6,17 +6,17 @@ import kotlinx.io.core.*
 import net.mamoe.mirai.contact.GroupInternalId
 import net.mamoe.mirai.contact.MemberPermission
 import net.mamoe.mirai.contact.groupInternalId
+import net.mamoe.mirai.data.Packet
 import net.mamoe.mirai.message.data.MessageChain
 import net.mamoe.mirai.message.internal.toPacket
 import net.mamoe.mirai.network.BotNetworkHandler
-import net.mamoe.mirai.data.Packet
+import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.timpc.internal.RawGroupInfo
 import net.mamoe.mirai.timpc.network.TIMProtocol
-import net.mamoe.mirai.timpc.network.packet.*
+import net.mamoe.mirai.timpc.network.packet.buildSessionPacket
 import net.mamoe.mirai.timpc.utils.unsupportedFlag
 import net.mamoe.mirai.timpc.utils.unsupportedType
 import net.mamoe.mirai.utils.io.*
-import kotlin.collections.mutableMapOf
 import kotlin.collections.set
 
 

+ 3 - 2
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/Profile.kt

@@ -5,10 +5,11 @@ package net.mamoe.mirai.timpc.network.packet.action
 import io.ktor.util.date.GMTDate
 import kotlinx.io.core.*
 import net.mamoe.mirai.data.Gender
+import net.mamoe.mirai.data.Packet
 import net.mamoe.mirai.data.Profile
 import net.mamoe.mirai.network.BotNetworkHandler
-import net.mamoe.mirai.data.Packet
-import net.mamoe.mirai.timpc.network.packet.*
+import net.mamoe.mirai.network.packet.*
+import net.mamoe.mirai.timpc.network.packet.buildSessionPacket
 import net.mamoe.mirai.utils.io.*
 
 inline class AvatarLink(val value: String) : Packet

+ 2 - 1
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/Remark.kt

@@ -6,7 +6,8 @@ import kotlinx.io.core.ByteReadPacket
 import kotlinx.io.core.discardExact
 import net.mamoe.mirai.network.BotNetworkHandler
 import net.mamoe.mirai.data.FriendNameRemark
-import net.mamoe.mirai.timpc.network.packet.*
+import net.mamoe.mirai.network.packet.*
+import net.mamoe.mirai.timpc.network.packet.buildSessionPacket
 import net.mamoe.mirai.utils.io.readUShortLVString
 import net.mamoe.mirai.utils.io.writeQQ
 import net.mamoe.mirai.utils.io.writeZero

+ 2 - 1
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/RequestFriendListPacket.kt

@@ -5,8 +5,9 @@ package net.mamoe.mirai.timpc.network.packet.action
 import kotlinx.io.core.ByteReadPacket
 import net.mamoe.mirai.network.BotNetworkHandler
 import net.mamoe.mirai.data.Packet
+import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.timpc.network.TIMProtocol
-import net.mamoe.mirai.timpc.network.packet.*
+import net.mamoe.mirai.timpc.network.packet.buildSessionPacket
 import net.mamoe.mirai.utils.io.writeZero
 
 class FriendList : Packet

+ 2 - 1
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/action/SendFriendMessagePacket.kt

@@ -7,8 +7,9 @@ import net.mamoe.mirai.message.data.MessageChain
 import net.mamoe.mirai.message.internal.toPacket
 import net.mamoe.mirai.network.BotNetworkHandler
 import net.mamoe.mirai.data.Packet
+import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.timpc.network.TIMProtocol
-import net.mamoe.mirai.timpc.network.packet.*
+import net.mamoe.mirai.timpc.network.packet.buildSessionPacket
 import net.mamoe.mirai.utils.io.*
 import net.mamoe.mirai.utils.md5
 

+ 1 - 1
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/event/AndroidOnlineStatusChange.kt

@@ -6,7 +6,7 @@ import kotlinx.io.core.ByteReadPacket
 import kotlinx.io.core.discardExact
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.data.Packet
-import net.mamoe.mirai.timpc.network.packet.PacketVersion
+import net.mamoe.mirai.network.packet.PacketVersion
 import net.mamoe.mirai.utils.io.readBoolean
 
 

+ 2 - 1
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/event/EventPacketFactory.kt

@@ -6,9 +6,10 @@ import kotlinx.io.core.*
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.network.BotNetworkHandler
 import net.mamoe.mirai.data.Packet
+import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.timpc.network.TIMBotNetworkHandler
-import net.mamoe.mirai.timpc.network.packet.*
 import net.mamoe.mirai.qqAccount
+import net.mamoe.mirai.timpc.network.packet.buildSessionPacket
 import net.mamoe.mirai.utils.io.readIoBuffer
 
 /**

+ 1 - 1
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/event/FriendAddRequestEventPacket.kt

@@ -6,7 +6,7 @@ import kotlinx.io.core.ByteReadPacket
 import kotlinx.io.core.discardExact
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.event.events.ReceiveFriendAddRequestEvent
-import net.mamoe.mirai.timpc.network.packet.PacketVersion
+import net.mamoe.mirai.network.packet.PacketVersion
 import net.mamoe.mirai.utils.io.readQQ
 import net.mamoe.mirai.utils.io.readUShortLVString
 

+ 1 - 2
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/event/FriendConversationIniliaze.kt

@@ -4,10 +4,9 @@ package net.mamoe.mirai.timpc.network.packet.event
 
 import kotlinx.io.core.ByteReadPacket
 import kotlinx.io.core.discardExact
-import kotlinx.io.core.readUInt
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.data.EventPacket
-import net.mamoe.mirai.timpc.network.packet.PacketVersion
+import net.mamoe.mirai.network.packet.PacketVersion
 import net.mamoe.mirai.utils.io.readQQ
 
 

+ 2 - 4
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/event/FriendOnlineStatusChanged.kt

@@ -5,12 +5,10 @@ package net.mamoe.mirai.timpc.network.packet.event
 import kotlinx.io.core.ByteReadPacket
 import kotlinx.io.core.discardExact
 import kotlinx.io.core.readUByte
-import kotlinx.io.core.readUInt
 import net.mamoe.mirai.event.events.FriendStatusChanged
 import net.mamoe.mirai.network.BotNetworkHandler
-import net.mamoe.mirai.timpc.network.packet.KnownPacketId
-import net.mamoe.mirai.timpc.network.packet.PacketId
-import net.mamoe.mirai.timpc.network.packet.SessionPacketFactory
+import net.mamoe.mirai.network.packet.PacketId
+import net.mamoe.mirai.network.packet.SessionPacketFactory
 import net.mamoe.mirai.utils.OnlineStatus
 import net.mamoe.mirai.utils.io.readQQ
 

+ 1 - 1
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/event/GroupFileUpload.kt

@@ -5,7 +5,7 @@ package net.mamoe.mirai.timpc.network.packet.event
 import kotlinx.io.core.ByteReadPacket
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.data.EventPacket
-import net.mamoe.mirai.timpc.network.packet.PacketVersion
+import net.mamoe.mirai.network.packet.PacketVersion
 import net.mamoe.mirai.utils.io.debugPrint
 
 

+ 3 - 3
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/event/MemberPermission.kt

@@ -5,11 +5,11 @@ package net.mamoe.mirai.timpc.network.packet.event
 import kotlinx.io.core.ByteReadPacket
 import kotlinx.io.core.discardExact
 import net.mamoe.mirai.Bot
+import net.mamoe.mirai.contact.Group
+import net.mamoe.mirai.contact.Member
 import net.mamoe.mirai.data.EventPacket
-import net.mamoe.mirai.timpc.network.packet.PacketVersion
+import net.mamoe.mirai.network.packet.PacketVersion
 import net.mamoe.mirai.utils.io.readQQ
-import net.mamoe.mirai.contact.Member
-import net.mamoe.mirai.contact.Group
 
 
 data class MemberPermissionChangePacket(

+ 1 - 1
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/event/MessageEvent.kt

@@ -7,7 +7,7 @@ import net.mamoe.mirai.contact.MemberPermission
 import net.mamoe.mirai.message.GroupMessage
 import net.mamoe.mirai.message.internal.readMessageChain
 import net.mamoe.mirai.message.FriendMessage
-import net.mamoe.mirai.timpc.network.packet.PacketVersion
+import net.mamoe.mirai.network.packet.PacketVersion
 import net.mamoe.mirai.utils.MiraiLogger
 import net.mamoe.mirai.utils.io.*
 

+ 4 - 2
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/login/Captcha.kt

@@ -5,11 +5,13 @@ package net.mamoe.mirai.timpc.network.packet.login
 import kotlinx.io.core.*
 import net.mamoe.mirai.network.BotNetworkHandler
 import net.mamoe.mirai.data.Packet
+import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.timpc.network.TIMProtocol
-import net.mamoe.mirai.timpc.network.packet.*
+import net.mamoe.mirai.timpc.network.packet.buildOutgoingPacket
 import net.mamoe.mirai.utils.io.*
 
-internal object CaptchaKey : DecrypterByteArray, DecrypterType<CaptchaKey> {
+internal object CaptchaKey : DecrypterByteArray,
+    DecrypterType<CaptchaKey> {
     override val value: ByteArray = TIMProtocol.key00BA
 }
 

+ 5 - 2
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/login/ChangeOnlineStatusPacket.kt

@@ -7,8 +7,9 @@ import kotlinx.io.core.writeFully
 import kotlinx.io.core.writeUByte
 import net.mamoe.mirai.network.BotNetworkHandler
 import net.mamoe.mirai.data.Packet
+import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.timpc.network.TIMProtocol
-import net.mamoe.mirai.timpc.network.packet.*
+import net.mamoe.mirai.timpc.network.packet.buildOutgoingPacket
 import net.mamoe.mirai.utils.OnlineStatus
 import net.mamoe.mirai.utils.io.writeHex
 import net.mamoe.mirai.utils.io.writeQQ
@@ -16,7 +17,9 @@ import net.mamoe.mirai.utils.io.writeQQ
 /**
  * 改变在线状态: "我在线上", "隐身" 等
  */
-internal object ChangeOnlineStatusPacket : PacketFactory<ChangeOnlineStatusPacket.ChangeOnlineStatusResponse, NoDecrypter>(NoDecrypter) {
+internal object ChangeOnlineStatusPacket : PacketFactory<ChangeOnlineStatusPacket.ChangeOnlineStatusResponse, NoDecrypter>(
+    NoDecrypter
+) {
     operator fun invoke(
         bot: Long,
         sessionKey: SessionKey,

+ 2 - 1
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/login/Heartbeat.kt

@@ -7,8 +7,9 @@ import kotlinx.io.core.writeFully
 import net.mamoe.mirai.event.Subscribable
 import net.mamoe.mirai.network.BotNetworkHandler
 import net.mamoe.mirai.data.Packet
+import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.timpc.network.TIMProtocol
-import net.mamoe.mirai.timpc.network.packet.*
+import net.mamoe.mirai.timpc.network.packet.buildOutgoingPacket
 import net.mamoe.mirai.utils.io.writeHex
 import net.mamoe.mirai.utils.io.writeQQ
 

+ 4 - 2
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/login/PasswordSubmission.kt

@@ -7,12 +7,14 @@ import net.mamoe.mirai.data.Gender
 import net.mamoe.mirai.network.BotNetworkHandler
 import net.mamoe.mirai.data.LoginResult
 import net.mamoe.mirai.data.Packet
+import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.timpc.network.TIMProtocol
-import net.mamoe.mirai.timpc.network.packet.*
+import net.mamoe.mirai.timpc.network.packet.buildOutgoingPacket
 import net.mamoe.mirai.utils.*
 import net.mamoe.mirai.utils.io.*
 
-internal object ShareKey : DecrypterByteArray, DecrypterType<ShareKey> {
+internal object ShareKey : DecrypterByteArray,
+    DecrypterType<ShareKey> {
     override val value: ByteArray = TIMProtocol.shareKey
 }
 

+ 2 - 1
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/login/SKey.kt

@@ -7,8 +7,9 @@ import kotlinx.io.core.discardExact
 import kotlinx.io.core.writeFully
 import net.mamoe.mirai.network.BotNetworkHandler
 import net.mamoe.mirai.data.Packet
+import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.timpc.network.TIMProtocol
-import net.mamoe.mirai.timpc.network.packet.*
+import net.mamoe.mirai.timpc.network.packet.buildOutgoingPacket
 import net.mamoe.mirai.utils.io.*
 
 internal inline class SKey(

+ 4 - 1
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/login/Session.kt

@@ -5,8 +5,11 @@ package net.mamoe.mirai.timpc.network.packet.login
 import kotlinx.io.core.*
 import net.mamoe.mirai.network.BotNetworkHandler
 import net.mamoe.mirai.data.Packet
+import net.mamoe.mirai.network.packet.PacketFactory
+import net.mamoe.mirai.network.packet.PacketId
+import net.mamoe.mirai.network.packet.SessionKey
 import net.mamoe.mirai.timpc.network.TIMProtocol
-import net.mamoe.mirai.timpc.network.packet.*
+import net.mamoe.mirai.timpc.network.packet.buildOutgoingPacket
 import net.mamoe.mirai.utils.io.*
 import net.mamoe.mirai.utils.localIpAddress
 

+ 5 - 3
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/login/Touch.kt

@@ -6,13 +6,15 @@ import kotlinx.io.core.ByteReadPacket
 import kotlinx.io.core.discardExact
 import kotlinx.io.core.readBytes
 import kotlinx.io.core.writeFully
-import net.mamoe.mirai.network.BotNetworkHandler
 import net.mamoe.mirai.data.Packet
+import net.mamoe.mirai.network.BotNetworkHandler
+import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.timpc.network.TIMProtocol
-import net.mamoe.mirai.timpc.network.packet.*
+import net.mamoe.mirai.timpc.network.packet.buildOutgoingPacket
 import net.mamoe.mirai.utils.io.*
 
-internal object TouchKey : DecrypterByteArray, DecrypterType<TouchKey> {
+internal object TouchKey : DecrypterByteArray,
+    DecrypterType<TouchKey> {
     override val value: ByteArray = TIMProtocol.touchKey
 }
 

+ 11 - 11
mirai-core-timpc/src/jvmTest/kotlin/PacketDebugger.kt

@@ -16,13 +16,12 @@ import kotlinx.serialization.internal.ArrayListSerializer
 import kotlinx.serialization.json.Json
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.network.BotNetworkHandler
+import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.timpc.TIMPC
 import net.mamoe.mirai.timpc.network.TIMProtocol
-import net.mamoe.mirai.timpc.network.packet.*
+import net.mamoe.mirai.timpc.network.packet.event.FriendOnlineStatusChangedPacket
 import net.mamoe.mirai.timpc.network.packet.event.IgnoredEventPacket
-import net.mamoe.mirai.timpc.network.packet.login.CaptchaKey
-import net.mamoe.mirai.timpc.network.packet.login.ShareKey
-import net.mamoe.mirai.timpc.network.packet.login.TouchKey
+import net.mamoe.mirai.timpc.network.packet.login.*
 import net.mamoe.mirai.utils.DecryptionFailedException
 import net.mamoe.mirai.utils.decryptBy
 import net.mamoe.mirai.utils.io.*
@@ -181,7 +180,8 @@ internal object PacketDebugger {
      * 7. 运行完 `mov eax,dword ptr ss:[ebp+10]`
      * 8. 查看内存, `eax` 到 `eax+10` 的 16 字节就是 `sessionKey`
      */
-    val sessionKey: SessionKey = SessionKey("95 F3 24 8E 7B B6 62 AA 98 C0 EE 45 CE CE 2B 69".hexToBytes())
+    val sessionKey: SessionKey =
+        SessionKey("95 F3 24 8E 7B B6 62 AA 98 C0 EE 45 CE CE 2B 69".hexToBytes())
     // TODO: 2019/12/7 无法访问 internal 是 kotlin bug, KT-34849
 
     /**
@@ -194,9 +194,9 @@ internal object PacketDebugger {
     val recorder: Recorder? = Recorder()
 
     val IgnoredPacketIdList: List<PacketId> = listOf(
-        KnownPacketId.FRIEND_ONLINE_STATUS_CHANGE,
-        KnownPacketId.CHANGE_ONLINE_STATUS,
-        KnownPacketId.HEARTBEAT
+        KnownPacketId.get<FriendOnlineStatusChangedPacket>(),
+        KnownPacketId.get<ChangeOnlineStatusPacket>(),
+        KnownPacketId.get<HeartbeatPacket>()
     )
 
     suspend fun dataReceived(data: ByteArray) {
@@ -204,10 +204,10 @@ internal object PacketDebugger {
         //println("raw = " + data.toUHexString())
         data.read {
             discardExact(3)
-            val id = matchPacketId(readUShort())
+            val id = net.mamoe.mirai.network.packet.matchPacketId(readUShort())
             val sequenceId = readUShort()
             val packetQQ = readQQ()
-            if (id == KnownPacketId.HEARTBEAT || (qq != null && packetQQ != qq))
+            if (id == KnownPacketId.get<HeartbeatPacket>() || (qq != null && packetQQ != qq))
                 return@read
 
             if (IgnoredPacketIdList.contains(id)) {
@@ -301,7 +301,7 @@ internal object PacketDebugger {
         // 3E 03 3F A2 02 00 00 00 01 2E 01 00 00 69 35
 
         discardExact(3)//head
-        val id = matchPacketId(readUShort())
+        val id = net.mamoe.mirai.network.packet.matchPacketId(readUShort())
         val sequence = readUShort().toUHexString()
         if (IgnoredPacketIdList.contains(id)) {
             return

+ 2 - 2
mirai-core-timpc/src/jvmTest/kotlin/packetdebugger/PacketDecoder.kt

@@ -3,8 +3,8 @@ package packetdebugger
 import kotlinx.io.core.ByteReadPacket
 import kotlinx.io.core.discardExact
 import kotlinx.io.core.readUShort
-import net.mamoe.mirai.timpc.network.packet.PacketId
-import net.mamoe.mirai.timpc.network.packet.matchPacketId
+import net.mamoe.mirai.network.packet.PacketId
+import net.mamoe.mirai.network.packet.matchPacketId
 import kotlin.contracts.ExperimentalContracts
 import kotlin.contracts.InvocationKind
 import kotlin.contracts.contract

+ 6 - 2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt

@@ -19,14 +19,18 @@ import kotlin.coroutines.CoroutineContext
  */
 @MiraiInternalAPI
 abstract class BotImpl<N : BotNetworkHandler> constructor(
-    override val account: BotAccount,
-    override val logger: MiraiLogger = DefaultLogger("Bot(" + account.id + ")"),
+    account: BotAccount,
+    logger: MiraiLogger?,
     context: CoroutineContext
 ) : Bot(), CoroutineScope {
     private val supervisorJob = SupervisorJob(context[Job])
     override val coroutineContext: CoroutineContext =
         context + supervisorJob + CoroutineExceptionHandler { _, e -> e.logStacktrace("An exception was thrown under a coroutine of Bot") }
 
+    @Suppress("CanBePrimaryConstructorProperty") // for logger
+    override val account: BotAccount = account
+    override val logger: MiraiLogger = logger ?: DefaultLogger("Bot(" + account.id + ")")
+
     init {
         @Suppress("LeakingThis")
         instances.addLast(this)

+ 3 - 3
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/Annotations.kt → mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/packet/Annotations.kt

@@ -1,6 +1,6 @@
 @file:Suppress("EXPERIMENTAL_API_USAGE", "unused")
 
-package net.mamoe.mirai.timpc.network.packet
+package net.mamoe.mirai.network.packet
 
 /**
  * 包的最后一次修改时间, 和分析时使用的 TIM 版本
@@ -8,11 +8,11 @@ package net.mamoe.mirai.timpc.network.packet
 @MustBeDocumented
 @Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
 @Retention(AnnotationRetention.SOURCE)
-internal annotation class PacketVersion(val date: String, val timVersion: String)
+annotation class PacketVersion(val date: String, val timVersion: String)
 
 /**
  * 带有这个注解的 [Packet] 将不会被记录在 log 中.
  */
 @Target(AnnotationTarget.CLASS)
 @Retention(AnnotationRetention.RUNTIME)
-internal annotation class NoLog
+annotation class NoLog

+ 14 - 16
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/Decrypters.kt → mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/packet/Decrypters.kt

@@ -1,26 +1,23 @@
-package net.mamoe.mirai.timpc.network.packet
+package net.mamoe.mirai.network.packet
 
 import kotlinx.io.core.BytePacketBuilder
 import kotlinx.io.core.ByteReadPacket
 import kotlinx.io.core.IoBuffer
-import kotlinx.io.core.writeFully
 import net.mamoe.mirai.utils.decryptBy
-import net.mamoe.mirai.utils.encryptBy
 import net.mamoe.mirai.utils.io.encryptAndWrite
 
 
 /**
  * 会话密匙
  */
-internal inline class SessionKey(override val value: ByteArray) : DecrypterByteArray {
+inline class SessionKey(override val value: ByteArray) : DecrypterByteArray {
     companion object Type : DecrypterType<SessionKey>
 }
 
 /**
  * [ByteArray] 解密器
  */
-@PublishedApi
-internal interface DecrypterByteArray : Decrypter {
+interface DecrypterByteArray : Decrypter {
     val value: ByteArray
     override fun decrypt(input: ByteReadPacket): ByteReadPacket = input.decryptBy(value)
 }
@@ -28,7 +25,7 @@ internal interface DecrypterByteArray : Decrypter {
 /**
  * [IoBuffer] 解密器
  */
-internal interface DecrypterIoBuffer : Decrypter {
+interface DecrypterIoBuffer : Decrypter {
     val value: IoBuffer
     override fun decrypt(input: ByteReadPacket): ByteReadPacket = input.decryptBy(value)
 }
@@ -36,27 +33,28 @@ internal interface DecrypterIoBuffer : Decrypter {
 /**
  * 连接在一起的解密器
  */
-internal inline class LinkedDecrypter(inline val block: (ByteReadPacket) -> ByteReadPacket) : Decrypter {
+inline class LinkedDecrypter(inline val block: (ByteReadPacket) -> ByteReadPacket) : Decrypter {
     override fun decrypt(input: ByteReadPacket): ByteReadPacket = block(input)
 }
 
-internal object NoDecrypter : Decrypter, DecrypterType<NoDecrypter> {
+object NoDecrypter : Decrypter,
+    DecrypterType<NoDecrypter> {
     override fun decrypt(input: ByteReadPacket): ByteReadPacket = input
 }
 
 /**
  * 解密器
- */
-internal interface Decrypter {
+ */ 
+interface Decrypter {
     fun decrypt(input: ByteReadPacket): ByteReadPacket
     /**
      * 连接后将会先用 this 解密, 再用 [another] 解密
      */
-    operator fun plus(another: Decrypter): Decrypter = LinkedDecrypter { another.decrypt(this.decrypt(it)) }
+    operator fun plus(another: Decrypter): Decrypter =
+        LinkedDecrypter { another.decrypt(this.decrypt(it)) }
 }
+ 
+interface DecrypterType<D : Decrypter>
 
-internal interface DecrypterType<D : Decrypter>
-
-@PublishedApi
-internal inline fun BytePacketBuilder.encryptAndWrite(key: DecrypterByteArray, encoder: BytePacketBuilder.() -> Unit) =
+inline fun BytePacketBuilder.encryptAndWrite(key: DecrypterByteArray, encoder: BytePacketBuilder.() -> Unit) =
     this.encryptAndWrite(key.value, encoder)

+ 53 - 31
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/OutgoingPacket.kt → mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/packet/OutgoingPacket.kt

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

+ 4 - 4
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/Packet.kt → mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/packet/Packet.kt

@@ -1,4 +1,4 @@
-package net.mamoe.mirai.timpc.network.packet
+package net.mamoe.mirai.network.packet
 
 import kotlinx.io.core.ByteReadPacket
 import kotlinx.io.core.readBytes
@@ -8,18 +8,18 @@ import net.mamoe.mirai.utils.io.toUHexString
 /**
  * 被忽略的数据包.
  */
-internal inline class IgnoredPacket(internal val id: PacketId) : Packet
+inline class IgnoredPacket(internal val id: PacketId) : Packet
 
 /**
  * 未知的包.
  */
-internal class UnknownPacket(val id: PacketId, val body: ByteReadPacket) : Packet {
+class UnknownPacket(val id: PacketId, val body: ByteReadPacket) : Packet {
     override fun toString(): String = "UnknownPacket(${id.value.toUHexString()})\nbody=${body.readBytes().toUHexString()}"
 }
 
 /**
  * 仅用于替换类型应为 [Unit] 的情况
  */
-internal object NoPacket : Packet {
+object NoPacket : Packet {
     override fun toString(): String = "NoPacket"
 }

+ 5 - 4
mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/packet/PacketFactory.kt → mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/packet/PacketFactory.kt

@@ -1,6 +1,6 @@
 @file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
 
-package net.mamoe.mirai.timpc.network.packet
+package net.mamoe.mirai.network.packet
 
 import kotlinx.atomicfu.atomic
 import kotlinx.io.core.ByteReadPacket
@@ -11,6 +11,7 @@ import kotlinx.serialization.DeserializationStrategy
 import kotlinx.serialization.protobuf.ProtoBuf
 import net.mamoe.mirai.network.BotNetworkHandler
 import net.mamoe.mirai.data.Packet
+import net.mamoe.mirai.utils.MiraiInternalAPI
 import net.mamoe.mirai.utils.io.ByteArrayPool
 import net.mamoe.mirai.utils.io.debugPrint
 import net.mamoe.mirai.utils.io.read
@@ -24,7 +25,7 @@ import net.mamoe.mirai.utils.readProtoMap
  * @param TPacket 服务器回复包解析结果
  * @param TDecrypter 服务器回复包解密器
  */
-internal abstract class PacketFactory<out TPacket : Packet, TDecrypter : Decrypter>(val decrypterType: DecrypterType<TDecrypter>) {
+abstract class PacketFactory<out TPacket : Packet, TDecrypter : Decrypter>(val decrypterType: DecrypterType<TDecrypter>) {
 
     @Suppress("PropertyName")
     internal var _id: PacketId = NullPacketId
@@ -64,8 +65,8 @@ internal abstract class PacketFactory<out TPacket : Packet, TDecrypter : Decrypt
     companion object {
         private val sequenceIdInternal = atomic(1)
 
-        @PublishedApi
-        internal fun atomicNextSequenceId(): UShort = sequenceIdInternal.getAndIncrement().toUShort()
+        @MiraiInternalAPI
+        fun atomicNextSequenceId(): UShort = sequenceIdInternal.getAndIncrement().toUShort()
     }
 }
 

+ 76 - 0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/packet/PacketId.kt

@@ -0,0 +1,76 @@
+@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
+
+package net.mamoe.mirai.network.packet
+
+import net.mamoe.mirai.utils.io.toUHexString
+
+
+/**
+ * 通过 [value] 匹配一个 [IgnoredPacketId] 或 [KnownPacketId], 无匹配则返回一个 [UnknownPacketId].
+ */
+fun matchPacketId(value: UShort): PacketId =
+    IgnoredPacketIds.firstOrNull { it.value == value }
+        ?: KnownPacketId.entries.firstOrNull { it.value.value == value }?.value
+        ?: UnknownPacketId(value)
+
+/**
+ * 包 ID.
+ */
+interface PacketId {
+    val value: UShort
+    val factory: PacketFactory<*, *>
+}
+
+/**
+ * 用于代表 `null`. 调用任何属性时都将会得到一个 [error]
+ */
+@Suppress("unused")
+object NullPacketId : PacketId {
+    override val factory: PacketFactory<*, *> get() = error("uninitialized")
+    override val value: UShort get() = error("uninitialized")
+    override fun toString(): String = "NullPacketId"
+}
+
+/**
+ * 未知的 [PacketId]
+ */
+inline class UnknownPacketId(override inline val value: UShort) : PacketId {
+    override val factory: PacketFactory<*, *> get() = UnknownPacketFactory
+    override fun toString(): String = "UnknownPacketId(${value.toUHexString()})"
+}
+
+object IgnoredPacketIds : List<IgnoredPacketId> by {
+    listOf<UShort>(
+    ).map { IgnoredPacketId(it.toUShort()) }
+}()
+
+inline class IgnoredPacketId constructor(override val value: UShort) : PacketId {
+    override val factory: PacketFactory<*, *> get() = IgnoredPacketFactory
+    override fun toString(): String = "IgnoredPacketId(${value.toUHexString()})"
+}
+
+class KnownPacketId(override val value: UShort, override val factory: PacketFactory<*, *>) : PacketId {
+    companion object : MutableMap<UShort, KnownPacketId> by mutableMapOf() {
+        operator fun set(key: UShort, factory: PacketFactory<*, *>) {
+            this[key] = KnownPacketId(key, factory)
+        }
+
+        inline fun <reified PF : PacketFactory<*, *>> getOrNull(): KnownPacketId? {
+            val clazz = PF::class
+            this.forEach {
+                if (clazz.isInstance(it.value)) {
+                    return it.value
+                }
+            }
+            return null
+        }
+
+        inline fun <reified PF : PacketFactory<*, *>> get(): KnownPacketId = getOrNull<PF>() ?: throw NoSuchElementException()
+    }
+
+    override fun toString(): String = (factory::class.simpleName ?: factory::class.simpleName) + "(${value.toUHexString()})"
+
+    init {
+        factory._id = this
+    }
+}