From bfd185fc4905ccb86d00079136913b1947f37acd Mon Sep 17 00:00:00 2001
From: "jiahua.liu" <n@mamoe.net>
Date: Mon, 27 Jan 2020 21:22:37 +0800
Subject: [PATCH 1/3] Push Notify Update

---
 .../net/mamoe/mirai/qqandroid/io/JceStruct.kt |   7 +-
 .../packet/chat/data/PushNotifyPack.kt        | 207 +++++-------------
 2 files changed, 57 insertions(+), 157 deletions(-)

diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceStruct.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceStruct.kt
index 452731941..ffff1fbe9 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceStruct.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceStruct.kt
@@ -1,10 +1,5 @@
 package net.mamoe.mirai.qqandroid.io
 
-abstract class JceStruct {
-    abstract fun writeTo(builder: JceOutput)
+interface JceStruct {
 
-    interface Factory<out T : JceStruct> {
-        fun newInstanceFrom(input: JceInput): T
-
-    }
 }
\ No newline at end of file
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/PushNotifyPack.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/PushNotifyPack.kt
index 0f706f0a7..1465ac651 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/PushNotifyPack.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/PushNotifyPack.kt
@@ -1,164 +1,69 @@
 package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data
 
-import net.mamoe.mirai.data.Packet
-import net.mamoe.mirai.qqandroid.io.JceInput
-import net.mamoe.mirai.qqandroid.io.JceOutput
+import kotlinx.serialization.SerialId
+import kotlinx.serialization.Serializable
 import net.mamoe.mirai.qqandroid.io.JceStruct
 import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
 
-class RequestPushNotify(
-    val uin: Long,
-    val ctype: Byte,
-    val strService: String,
-    val strCmd: String,
-    val vNotifyCookie: ByteArray,
-    val usMsgType: Int,
-    val wUserActive: Int,
-    val wGeneralFlag: Int,
-    val bindedUin: Long,
-    val stMsgInfo: MsgInfo,
-    val msgCtrlBuf: String,
-    val serverBuf: ByteArray,
-    val pingFlag: Long,
-    val svrip: Int
-) : Packet, JceStruct() {
-    override fun writeTo(builder: JceOutput) {
-        //not needed
-    }
+@Serializable
+internal class RequestPushNotify(
+    @SerialId(0) val uin: Long = 0L,
+    @SerialId(1) val ctype: Byte = 0,
+    @SerialId(2) val strService: String?,
+    @SerialId(3) val strCmd: String?,
+    @SerialId(4) val vNotifyCookie: ByteArray = EMPTY_BYTE_ARRAY,
+    @SerialId(5) val usMsgType: Int?,
+    @SerialId(6) val wUserActive: Int?,
+    @SerialId(7) val wGeneralFlag: Int?,
+    @SerialId(8) val bindedUin: Long?,
+    @SerialId(9) val stMsgInfo: MsgInfo?,
+    @SerialId(10) val msgCtrlBuf: String?,
+    @SerialId(11) val serverBuf: ByteArray?,
+    @SerialId(12) val pingFlag: Long?,
+    @SerialId(13) val svrip: Int?
+) : JceStruct
 
-    companion object : Factory<RequestPushNotify> {
-        override fun newInstanceFrom(input: JceInput): RequestPushNotify {
-            return RequestPushNotify(
-                input.read(0L, 0),
-                input.read(0.toByte(), 1),
-                input.readString(2),
-                input.readString(3),
-                input.read(EMPTY_BYTE_ARRAY, 4),
-                input.read(0, 5),
-                input.read(0, 6),
-                input.read(0, 7),
-                input.read(0L, 8),
-                input.readJceStruct(MsgInfo, 9),
-                input.readString(10),
-                input.readByteArray(11),
-                input.readLong(12),
-                input.readInt(13)
-            )
-        }
-    }
+@Serializable
+internal class MsgInfo(
+    @SerialId(0) val lFromUin: Long = 0L,
+    @SerialId(1) val uMsgTime: Long = 0L,
+    @SerialId(2) val shMsgType: Short?,
+    @SerialId(3) val shMsgSeq: Short?,
+    @SerialId(4) val strMsg: String?,
+    @SerialId(5) val uRealMsgTime: Int?,
+    @SerialId(6) val vMsg: ByteArray?,
+    @SerialId(7) val uAppShareID: Long?,
+    @SerialId(8) val vMsgCookies: ByteArray = EMPTY_BYTE_ARRAY,
+    @SerialId(9) val vAppShareCookie: ByteArray = EMPTY_BYTE_ARRAY,
+    @SerialId(10) val lMsgUid: Long?,
+    @SerialId(11) val lLastChangeTime: Long?,
+    @SerialId(12) val vCPicInfo: List<CPicInfo>?,
+    @SerialId(13) val stShareData: ShareData?,
+    @SerialId(14) val lFromInstId: Long?,
+    @SerialId(15) val vRemarkOfSender: ByteArray?,
+    @SerialId(16) val strFromMobile: String?,
+    @SerialId(17) val strFromName: String?,
+    @SerialId(18) val vNickName: List<String>?,
+    @SerialId(19) val stC2CTmpMsgHead: TempMsgHead?
+) : JceStruct
 
-}
-
-class MsgInfo(
-    val lFromUin: Long,
-    val uMsgTime: Long,
-    val shMsgType: Short,
-    val shMsgSeq: Short,
-    val strMsg: String,
-    val uRealMsgTime: Int,
-    val vMsg: ByteArray,
-    val uAppShareID: Long,
-    val vMsgCookies: ByteArray,
-    val vAppShareCookie: ByteArray,
-    val lMsgUid: Long,
-    val lLastChangeTime: Long,
-    val vCPicInfo: List<CPicInfo>,
-    val stShareData: ShareData,
-    val lFromInstId: Long,
-    val vRemarkOfSender: ByteArray,
-    val strFromMobile: String,
-    val strFromName: String,
-    val vNickName: List<String>,
-    val stC2CTmpMsgHead: TempMsgHead?
-) : JceStruct() {
-    companion object : Factory<MsgInfo> {
-        override fun newInstanceFrom(input: JceInput): MsgInfo = with(input) {
-            return MsgInfo(
-                readLong(0),
-                readLong(1),
-                readShort(2),
-                readShort(3),
-                readString(4),
-                readInt(5),
-                readByteArray(6),
-                readLong(7),
-                readByteArray(8),
-                readByteArray(9),
-                readLong(10),
-                readLong(11),
-                readJceStructList(CPicInfo, 12),
-                readJceStruct(ShareData, 13),
-                readLong(14),
-                readByteArray(15),
-                readString(16),
-                readString(17),
-                readList(18),
-                readJceStructOrNull(TempMsgHead, 19)
-            )
-        }
-
-    }
-
-    override fun writeTo(builder: JceOutput) {
-        // not needed
-    }
-}
 
+@Serializable
 class ShareData(
-    val pkgname: String = "",
-    val msgtail: String = "",
-    val picurl: String = "",
-    val url: String = ""
-) : JceStruct() {
-    companion object : Factory<ShareData> {
-        override fun newInstanceFrom(input: JceInput): ShareData {
-            return ShareData(
-                input.readString(0),
-                input.readString(1),
-                input.readString(2),
-                input.readString(3)
-            )
-        }
-    }
-
-    override fun writeTo(builder: JceOutput) {
-        // not needed
-    }
-}
+    @SerialId(0) val pkgname: String = "",
+    @SerialId(1) val msgtail: String = "",
+    @SerialId(2) val picurl: String = "",
+    @SerialId(3) val url: String = ""
+) : JceStruct
 
+@Serializable
 class TempMsgHead(
-    val c2c_type: Int,
-    val serviceType: Int
-) : JceStruct() {
-    override fun writeTo(builder: JceOutput) {
-
-    }
-
-    companion object : Factory<TempMsgHead> {
-        override fun newInstanceFrom(input: JceInput): TempMsgHead {
-            return TempMsgHead(
-                input.readInt(0),
-                input.readInt(1)
-            )
-        }
-    }
-}
+    @SerialId(0) val c2c_type: Int = 0,
+    @SerialId(1) val serviceType: Int = 0
+) : JceStruct
 
+@Serializable
 class CPicInfo(
-    val vPath: ByteArray,
-    val vHost: ByteArray?
-) : JceStruct() {
-    override fun writeTo(builder: JceOutput) {
-
-    }
-
-    companion object : Factory<CPicInfo> {
-        override fun newInstanceFrom(input: JceInput): CPicInfo {
-            return CPicInfo(
-                input.readByteArray(0),
-                input.readByteArray(1)
-            )
-        }
-    }
-
-}
+    @SerialId(0) val vPath: ByteArray = EMPTY_BYTE_ARRAY,
+    @SerialId(1) val vHost: ByteArray = EMPTY_BYTE_ARRAY
+) : JceStruct
\ No newline at end of file

From 85d1b6134bf3e801b2e3b227b1644e95ab270c68 Mon Sep 17 00:00:00 2001
From: "jiahua.liu" <n@mamoe.net>
Date: Mon, 27 Jan 2020 22:38:30 +0800
Subject: [PATCH 2/3] push notify

---
 .../net/mamoe/mirai/qqandroid/io/JceInput.kt  |  5 +-
 .../network/protocol/jce/RequestPacket.kt     | 88 ++++---------------
 .../packet/chat/data/PushNotifyPack.kt        |  3 +-
 3 files changed, 22 insertions(+), 74 deletions(-)

diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceInput.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceInput.kt
index 2910b341d..9ed165582 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceInput.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceInput.kt
@@ -55,7 +55,10 @@ fun <J : JceStruct> ByteReadPacket.readJceRequestBufferMapVersion3ToJceStruct(fa
 fun ByteReadPacket.readJceRequestBufferMapVersion2(charset: Charset = CharsetUTF8): Map<String, ByteArray> {
     this.use {
         discardExact(8)
-        val request = this.asJceInput(charset).use { RequestPacket.newInstanceFrom(it) }
+        val request = this.asJceInput(charset).use {
+            Jce
+            RequestPacket.serializer()
+        }
         val map = request.sBuffer.asJceInput(charset).withUse {
             readNestedMap<String, String, ByteArray>(0)
         }
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/jce/RequestPacket.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/jce/RequestPacket.kt
index 20cbc50fb..8c3717588 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/jce/RequestPacket.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/jce/RequestPacket.kt
@@ -1,78 +1,22 @@
 package net.mamoe.mirai.qqandroid.network.protocol.jce
 
-import net.mamoe.mirai.qqandroid.io.JceInput
-import net.mamoe.mirai.qqandroid.io.JceOutput
+import kotlinx.serialization.SerialId
+import kotlinx.serialization.Serializable
 import net.mamoe.mirai.qqandroid.io.JceStruct
-import net.mamoe.mirai.utils.cryptor.contentToString
+import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
 
 private val EMPTY_MAP = mapOf<String, String>()
 
-class RequestPacket() : JceStruct() {
-    lateinit var sBuffer: ByteArray
-    var cPacketType: Byte = 0
-    var iMessageType: Int = 0
-    var iRequestId: Int = 0
-    var iTimeout: Int = 0
-    var iVersion: Short = 3
-    var context: Map<String, String> = EMPTY_MAP
-    var sFuncName: String = ""
-    var sServantName: String = ""
-    var status: Map<String, String> = EMPTY_MAP
-
-    constructor(
-        sBuffer: ByteArray,
-        cPacketType: Byte = 0,
-        iMessageType: Int = 0,
-        iRequestId: Int = 0,
-        iTimeout: Int = 0,
-        iVersion: Short = 3,
-        context: Map<String, String> = EMPTY_MAP,
-        sFuncName: String = "",
-        sServantName: String = "",
-        status: Map<String, String> = EMPTY_MAP
-    ) : this() {
-        this.sBuffer = sBuffer
-        this.cPacketType = cPacketType
-        this.iMessageType = iMessageType
-        this.iRequestId = iRequestId
-        this.iTimeout = iTimeout
-        this.iVersion = iVersion
-        this.context = context
-        this.sFuncName = sFuncName
-        this.sServantName = sServantName
-        this.status = status
-    }
-
-    companion object : Factory<RequestPacket> {
-        override fun newInstanceFrom(input: JceInput): RequestPacket {
-            val iVersion = input.readShort(1)
-            val cPacketType = input.readByte(2)
-            val iMessageType = input.readInt(3)
-            val iRequestId = input.readInt(4)
-            val sServantName = input.readString(5)
-            val sFuncName = input.readString(6)
-            val sBuffer = input.readByteArray(7)
-            val iTimeout = input.readInt(8)
-            val context = input.readMap("", "", 9)
-            val status = input.readMap("", "", 10)
-            return RequestPacket(sBuffer, cPacketType, iMessageType, iRequestId, iTimeout, iVersion, context, sFuncName, sServantName, status)
-        }
-    }
-
-    override fun writeTo(builder: JceOutput) {
-        builder.write(this.iVersion, 1)
-        builder.write(this.cPacketType, 2)
-        builder.write(this.iMessageType, 3)
-        builder.write(this.iRequestId, 4)
-        builder.write(this.sServantName, 5)
-        builder.write(this.sFuncName, 6)
-        builder.write(this.sBuffer, 7)
-        builder.write(this.iTimeout, 8)
-        builder.write(this.context, 9)
-        builder.write(this.status, 10)
-    }
-
-    override fun toString(): String {
-        return this.contentToString()
-    }
-}
\ No newline at end of file
+@Serializable
+class RequestPacket(
+    @SerialId(1) val iVersion: Short = 3,
+    @SerialId(2) val cPacketType: Byte = 0,
+    @SerialId(3) val iMessageType: Int = 0,
+    @SerialId(4) val iRequestId: Int = 0,
+    @SerialId(5) val sServantName: String = "",
+    @SerialId(6) val sFuncName: String = "",
+    @SerialId(7) val sBuffer: ByteArray = EMPTY_BYTE_ARRAY,
+    @SerialId(8) val iTimeout: Int = 0,
+    @SerialId(9) val context: Map<String, String> = EMPTY_MAP,
+    @SerialId(10) val status: Map<String, String> = EMPTY_MAP
+) : JceStruct
\ No newline at end of file
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/PushNotifyPack.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/PushNotifyPack.kt
index 1465ac651..88c6a5d03 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/PushNotifyPack.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/PushNotifyPack.kt
@@ -2,6 +2,7 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data
 
 import kotlinx.serialization.SerialId
 import kotlinx.serialization.Serializable
+import net.mamoe.mirai.data.Packet
 import net.mamoe.mirai.qqandroid.io.JceStruct
 import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
 
@@ -21,7 +22,7 @@ internal class RequestPushNotify(
     @SerialId(11) val serverBuf: ByteArray?,
     @SerialId(12) val pingFlag: Long?,
     @SerialId(13) val svrip: Int?
-) : JceStruct
+) : JceStruct, Packet
 
 @Serializable
 internal class MsgInfo(

From 5b8dbf590cf8fa14d039fb7e344cbe2ace04a293 Mon Sep 17 00:00:00 2001
From: "jiahua.liu" <n@mamoe.net>
Date: Mon, 27 Jan 2020 22:53:57 +0800
Subject: [PATCH 3/3] nothing

---
 .../kotlin/net/mamoe/mirai/qqandroid/io/JceInput.kt  | 12 +++++++++---
 .../mirai/qqandroid/io/serialization/JceEncoder.kt   |  9 +++++++++
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceInput.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceInput.kt
index 9ed165582..a2bcd2a0b 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceInput.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceInput.kt
@@ -3,6 +3,8 @@ package net.mamoe.mirai.qqandroid.io
 import kotlinx.io.charsets.Charset
 import kotlinx.io.core.*
 import kotlinx.io.pool.ObjectPool
+import kotlinx.serialization.DeserializationStrategy
+import net.mamoe.mirai.qqandroid.io.serialization.Jce
 import net.mamoe.mirai.qqandroid.network.protocol.jce.RequestPacket
 import net.mamoe.mirai.utils.io.DebugLogger
 import net.mamoe.mirai.utils.io.readIoBuffer
@@ -18,12 +20,16 @@ inline class JceHead(private val value: Long) {
 
     override fun toString(): String {
         return "JceHead(tag=$tag, type=$type)"
-    }
+    }Z
 }
 
-fun <J : JceStruct> ByteArray.readJceStruct(factory: JceStruct.Factory<J>, tag: Int = 0, charset: Charset = CharsetUTF8): J {
+fun <J : JceStruct> ByteArray.readJceStruct(
+    deserializer: DeserializationStrategy<J>,
+    tag: Int = 0,
+    charset: Charset = CharsetUTF8
+): J {
     this.asJceInput(charset).use {
-        return it.readJceStruct(factory, tag)
+        return Jce.byCharSet(charset).load(deserializer, this.)
     }
 }
 
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/JceEncoder.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/JceEncoder.kt
index e74e34355..4f24a0a11 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/JceEncoder.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/JceEncoder.kt
@@ -10,6 +10,7 @@ import kotlinx.serialization.*
 import kotlinx.serialization.internal.*
 import kotlinx.serialization.modules.EmptyModule
 import kotlinx.serialization.modules.SerialModule
+import net.mamoe.mirai.qqandroid.io.CharsetUTF8
 import net.mamoe.mirai.qqandroid.io.JceEncodeException
 import net.mamoe.mirai.qqandroid.io.JceOutput
 import net.mamoe.mirai.utils.io.toUHexString
@@ -310,6 +311,14 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
         val UTF8 = Jce(JceCharset.UTF8)
         val GBK = Jce(JceCharset.GBK)
 
+        public fun byCharSet(c: Charset): Jce {
+            return if (c === CharsetUTF8) {
+                UTF8
+            } else {
+                GBK
+            }
+        }
+
         internal const val BYTE: Int = 0
         internal const val DOUBLE: Int = 5
         internal const val FLOAT: Int = 4