1
0
mirror of https://github.com/mamoe/mirai.git synced 2025-04-24 20:43:33 +08:00

Fix deserializing nested struct in map

This commit is contained in:
Him188 2020-01-30 22:41:26 +08:00
parent 9d206d1af9
commit afa2cc700f
3 changed files with 33 additions and 26 deletions
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid
io/serialization
network/protocol/data/jce
mirai-core/src/commonMain/kotlin/net.mamoe.mirai

View File

@ -308,7 +308,10 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
input: JceInput
) : JceDecoder(input) {
override fun endStructure(desc: SerialDescriptor) {
input.readHeadOrNull() // STRUCT_END
while (input.peakHead().type != STRUCT_END) {
input.readHead()
}
input.readHead()
}
}
@ -320,7 +323,7 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
internal val input: JceInput
) : TaggedDecoder<Int>() {
override fun SerialDescriptor.getTag(index: Int): Int {
return getSerialId(this, index) ?: error("cannot find tag")
return getSerialId(this, index) ?: error("cannot find tag with index $index")
}
override fun decodeTaggedByte(tag: Int): Byte = input.readByte(tag)
@ -387,21 +390,6 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
}
}
if (desc.kind == StructureKind.CLASS || desc.kind == UnionKind.OBJECT) {
val tag = currentTagOrNull
if (tag != null) {
@Suppress("SENSELESS_COMPARISON") // 推断 bug
if (input.skipToTagOrNull(tag) {
popTag()
return JceStructReader(input)
} == null && desc.isNullable) {
return NullReader(this.input)
}
}
return this // top-level
}
return super.beginStructure(desc, *typeParams)
}
@ -419,7 +407,7 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
@Suppress("UNCHECKED_CAST")
override fun <T : Any> decodeNullableSerializableValue(deserializer: DeserializationStrategy<T?>): T? {
// println("decodeNullableSerializableValue: ${deserializer.getClassName()}")
println("decodeNullableSerializableValue: ${deserializer::class.qualifiedName}")
if (deserializer is NullReader) {
return null
}
@ -445,7 +433,7 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
return if (isTagOptional(tag)) input.readByteArrayOrNull(tag)?.toMutableList() as? T
else input.readByteArray(tag).toMutableList() as T
}
val tag = popTag()
val tag = currentTag
// println(tag)
@Suppress("SENSELESS_COMPARISON") // false positive
if (input.skipToTagOrNull(tag) {
@ -461,6 +449,7 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
val tag = popTag()
@Suppress("SENSELESS_COMPARISON")
if (input.skipToTagOrNull(tag) {
check(it.type == MAP) { "type mismatch: ${it.type}" }
// 将 mapOf(k1 to v1, k2 to v2, ...) 转换为 listOf(k1, v1, k2, v2, ...) 以便于写入.
val serializer = (deserializer as MapLikeSerializer<Any?, Any?, T, *>)
val mapEntrySerial = MapEntrySerializer(serializer.keySerializer, serializer.valueSerializer)
@ -474,7 +463,24 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
error("UNREACHABLE CODE")
}
}
val tag = currentTagOrNull ?: return deserializer.deserialize(this)
if (deserializer.descriptor.kind == StructureKind.CLASS || deserializer.descriptor.kind == UnionKind.OBJECT) {
val tag = currentTagOrNull
if (tag != null) {
@Suppress("SENSELESS_COMPARISON") // 推断 bug
if (input.skipToTagOrNull(tag) {
check(it.type == STRUCT_BEGIN) { "type mismatch: ${it.type}" }
//popTag()
return deserializer.deserialize(JceStructReader(input))
} == null && isTagOptional(tag)) {
return null
} else error("cannot find tag $tag")
}
return deserializer.deserialize(JceDecoder(this.input))
}
val tag = currentTagOrNull ?: return deserializer.deserialize(JceDecoder(this.input))
return if (this.decodeTaggedNotNullMark(tag)) {
deserializer.deserialize(this)
} else {
@ -486,7 +492,7 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
@Suppress("UNCHECKED_CAST")
override fun <T> decodeSerializableValue(deserializer: DeserializationStrategy<T>): T {
return decodeNullableSerializableValue(deserializer as DeserializationStrategy<Any?>) as? T
?: error("value with tag $currentTagOrNull is not optional but cannot find")
?: error("value with tag $currentTagOrNull(by ${deserializer.getClassName()}) is not optional but cannot find")
}
}
@ -738,7 +744,8 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
internal const val STRUCT_END: Byte = 11
internal const val ZERO_TYPE: Byte = 12
private fun Any?.getClassName(): String = (if (this == null) Unit::class else this::class).simpleName ?: "<unnamed class>"
private fun Any?.getClassName(): String =
(if (this == null) Unit::class else this::class).qualifiedName?.split(".")?.takeLast(2)?.joinToString(".") ?: "<unnamed class>"
}
fun <T> dumpAsPacket(serializer: SerializationStrategy<T>, obj: T): ByteReadPacket {

View File

@ -37,7 +37,7 @@ internal class GetFriendListResp(
@SerialId(4) val getfriendCount: Short,
@SerialId(5) val totoalFriendCount: Short,
@SerialId(6) val friendCount: Short,
@SerialId(7) val vecFriendInfo: List<FriendInfo>,
@SerialId(7) val vecFriendInfo: List<FriendInfo>? = null,
@SerialId(8) val groupid: Byte? = null,
@SerialId(9) val ifGetGroupInfo: Byte,
@SerialId(10) val groupstartIndex: Byte? = null,
@ -67,7 +67,7 @@ internal class FriendListSubSrvRspCode(
@Serializable
internal class FriendInfo(
@SerialId(0) val friendUin: Long,
@SerialId(0) val friendUin: Long? = 0,
@SerialId(1) val groupId: Byte,
@SerialId(2) val faceId: Short,
@SerialId(3) val remark: String = "",

View File

@ -102,10 +102,10 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
try {
return _network.login()
} catch (e: Exception){
e.logStacktrace("Exception when login")
_network.dispose(e)
}
delay(3000)
logger.warning("Login failed. Retrying in 3s...")
delay(3000)
}
}