mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-25 06:50:09 +08:00
Improve performance of hexToBytes
and simplify similar extensions
This commit is contained in:
parent
eaa8f20208
commit
dd606c3022
mirai-core-api/src/commonMain/kotlin/message/data
mirai-core-utils/src
mirai-core/src
commonMain/kotlin
jvmTest/kotlin/message/data
@ -52,7 +52,7 @@ public interface UnsupportedMessage : MessageContent {
|
||||
|
||||
public object Serializer : KSerializer<UnsupportedMessage> by Surrogate.serializer().map(
|
||||
resultantDescriptor = Surrogate.serializer().descriptor.copy(SERIAL_NAME),
|
||||
deserialize = { Mirai.createUnsupportedMessage(struct.chunkedHexToBytes()) },
|
||||
deserialize = { Mirai.createUnsupportedMessage(struct.hexToBytes()) },
|
||||
serialize = { Surrogate(struct.toUHexString("")) }
|
||||
) {
|
||||
@Suppress("RemoveRedundantQualifierName")
|
||||
|
@ -115,41 +115,6 @@ public fun Byte.fixToUHex(): String = this.toUByte().fixToUHex()
|
||||
public fun UByte.fixToUHex(): String =
|
||||
if (this.toInt() in 0..15) "0${this.toString(16).uppercase()}" else this.toString(16).uppercase()
|
||||
|
||||
public fun String.hexToBytes(): ByteArray =
|
||||
this.split(" ")
|
||||
.asSequence()
|
||||
.filterNot { it.isEmpty() }
|
||||
.map { s -> s.toUByte(16).toByte() }
|
||||
.toList()
|
||||
.toByteArray()
|
||||
|
||||
/**
|
||||
* 每 2 char 为一组, 转换 Hex 为 [ByteArray]
|
||||
*
|
||||
* 这个方法很累, 不建议经常使用.
|
||||
*/
|
||||
public fun String.chunkedHexToBytes(): ByteArray =
|
||||
this.asSequence().chunked(2).map { (it[0].toString() + it[1]).toUByte(16).toByte() }.toList().toByteArray()
|
||||
|
||||
/**
|
||||
* 删掉全部空格和换行后每 2 char 为一组, 转换 Hex 为 [ByteArray].
|
||||
*/
|
||||
public fun String.autoHexToBytes(): ByteArray =
|
||||
this.replace("\n", "").replace(" ", "").asSequence().chunked(2).map {
|
||||
(it[0].toString() + it[1]).toUByte(16).toByte()
|
||||
}.toList().toByteArray()
|
||||
|
||||
/**
|
||||
* 将无符号 Hex 转为 [UByteArray], 有根据 hex 的 [hashCode] 建立的缓存.
|
||||
*/
|
||||
public fun String.hexToUBytes(): UByteArray =
|
||||
this.split(" ")
|
||||
.asSequence()
|
||||
.filterNot { it.isEmpty() }
|
||||
.map { s -> s.toUByte(16) }
|
||||
.toList()
|
||||
.toUByteArray()
|
||||
|
||||
/**
|
||||
* 将 [this] 前 4 个 [Byte] 的 bits 合并为一个 [Int]
|
||||
*
|
||||
@ -171,4 +136,101 @@ public fun ByteArray.toInt(): Int =
|
||||
(this[0].toInt().and(255) shl 24) + (this[1].toInt().and(255) shl 16) + (this[2].toInt()
|
||||
.and(255) shl 8) + (this[3].toInt().and(
|
||||
255
|
||||
) shl 0)
|
||||
) shl 0)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// hexToBytes
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
private val byteStringCandidates = arrayOf('a'..'f', 'A'..'F', '0'..'9', ' '..' ')
|
||||
private const val CHUNK_SPACE = -1
|
||||
|
||||
public fun String.hexToBytes(): ByteArray {
|
||||
val array = ByteArray(countHexBytes())
|
||||
forEachHexChunkIndexed { index, char1, char2 ->
|
||||
array[index] = Byte.parseFromHexChunk(char1, char2)
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
public fun String.hexToUBytes(): UByteArray {
|
||||
val array = UByteArray(countHexBytes())
|
||||
forEachHexChunkIndexed { index, char1, char2 ->
|
||||
array[index] = Byte.parseFromHexChunk(char1, char2).toUByte()
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
public fun Byte.Companion.parseFromHexChunk(char1: Char, char2: Char): Byte {
|
||||
return (char1.digitToInt(16).shl(SIZE_BITS / 2) or char2.digitToInt(16)).toByte()
|
||||
}
|
||||
|
||||
private inline fun String.forEachHexChunkIndexed(block: (index: Int, char1: Char, char2: Char) -> Unit) {
|
||||
var index = 0
|
||||
forEachHexChunk { char1: Char, char2: Char ->
|
||||
block(index++, char1, char2)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun String.forEachHexChunk(block: (char1: Char, char2: Char) -> Unit) {
|
||||
var chunkSize = 0
|
||||
var char1: Char = 0.toChar()
|
||||
for ((index, c) in this.withIndex()) { // compiler optimization
|
||||
if (c == ' ') {
|
||||
if (chunkSize != 0) {
|
||||
throw IllegalArgumentException("Invalid size of chunk at index ${index.minus(1)}")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if (c in 'a'..'f' || c in 'A'..'F' || c in '0'..'9') { // compiler optimization
|
||||
when (chunkSize) {
|
||||
0 -> {
|
||||
chunkSize = 1
|
||||
char1 = c
|
||||
}
|
||||
1 -> {
|
||||
block(char1, c)
|
||||
chunkSize = 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw IllegalArgumentException("Invalid char '$c' at index $index")
|
||||
}
|
||||
}
|
||||
if (chunkSize != 0) {
|
||||
throw IllegalArgumentException("Invalid size of chunk at end of string")
|
||||
}
|
||||
}
|
||||
|
||||
public fun String.countHexBytes(): Int {
|
||||
var chunkSize = 0
|
||||
var count = 0
|
||||
for ((index, c) in this.withIndex()) {
|
||||
if (c == ' ') {
|
||||
if (chunkSize != 0) {
|
||||
throw IllegalArgumentException("Invalid size of chunk at index ${index.minus(1)}")
|
||||
}
|
||||
continue
|
||||
}
|
||||
c.isDigit()
|
||||
if (c in 'a'..'f' || c in 'A'..'F' || c in '0'..'9') {
|
||||
when (chunkSize) {
|
||||
0 -> {
|
||||
chunkSize = 1
|
||||
}
|
||||
1 -> {
|
||||
count++
|
||||
chunkSize = 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw IllegalArgumentException("Invalid char '$c' at index $index")
|
||||
}
|
||||
}
|
||||
if (chunkSize != 0) {
|
||||
throw IllegalArgumentException("Invalid size of chunk at end of string")
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertContentEquals
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
class HexToBytesTest {
|
||||
private fun Byte.Companion.parseFromHexChunk(char1: String): Byte = parseFromHexChunk(char1[0], char1[1])
|
||||
|
||||
@Test
|
||||
fun `Byte parseFromHexChunk`() {
|
||||
assertEquals(0xff.toByte(), Byte.parseFromHexChunk("FF"))
|
||||
assertEquals(0xff.toByte(), Byte.parseFromHexChunk("ff"))
|
||||
assertEquals(0xff.toByte(), Byte.parseFromHexChunk("fF"))
|
||||
assertEquals(0xff.toByte(), Byte.parseFromHexChunk("Ff"))
|
||||
|
||||
assertEquals(0x00.toByte(), Byte.parseFromHexChunk("00"))
|
||||
assertEquals(0x0f.toByte(), Byte.parseFromHexChunk("0f"))
|
||||
assertEquals(0x34.toByte(), Byte.parseFromHexChunk("34"))
|
||||
assertEquals(0x7f.toByte(), Byte.parseFromHexChunk("7f"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test countHexBytes`() {
|
||||
assertEquals(0, "".countHexBytes())
|
||||
|
||||
assertEquals(1, "01".countHexBytes())
|
||||
assertEquals(1, "FF".countHexBytes())
|
||||
assertEquals(1, "ff".countHexBytes())
|
||||
assertEquals(1, "Ff".countHexBytes())
|
||||
assertEquals(1, "fF".countHexBytes())
|
||||
assertEquals(1, "0F".countHexBytes())
|
||||
assertEquals(1, "F0".countHexBytes())
|
||||
assertEquals(1, "0f".countHexBytes())
|
||||
assertEquals(1, "f0".countHexBytes())
|
||||
|
||||
assertEquals(1, "01 ".countHexBytes())
|
||||
assertEquals(1, "FF ".countHexBytes())
|
||||
assertEquals(1, "ff ".countHexBytes())
|
||||
assertEquals(1, "Ff ".countHexBytes())
|
||||
assertEquals(1, "fF ".countHexBytes())
|
||||
assertEquals(1, "0F ".countHexBytes())
|
||||
assertEquals(1, "F0 ".countHexBytes())
|
||||
assertEquals(1, "0f ".countHexBytes())
|
||||
assertEquals(1, "f0 ".countHexBytes())
|
||||
|
||||
assertEquals(1, " 01 ".countHexBytes())
|
||||
assertEquals(1, " FF ".countHexBytes())
|
||||
assertEquals(1, " ff ".countHexBytes())
|
||||
assertEquals(1, " Ff ".countHexBytes())
|
||||
assertEquals(1, " fF ".countHexBytes())
|
||||
assertEquals(1, " 0F ".countHexBytes())
|
||||
assertEquals(1, " F0 ".countHexBytes())
|
||||
assertEquals(1, " 0f ".countHexBytes())
|
||||
assertEquals(1, " f0 ".countHexBytes())
|
||||
|
||||
assertEquals(1, " 01 ".countHexBytes())
|
||||
assertEquals(1, " FF ".countHexBytes())
|
||||
assertEquals(1, " ff ".countHexBytes())
|
||||
assertEquals(1, " Ff ".countHexBytes())
|
||||
assertEquals(1, " fF ".countHexBytes())
|
||||
assertEquals(1, " 0F ".countHexBytes())
|
||||
assertEquals(1, " F0 ".countHexBytes())
|
||||
assertEquals(1, " 0f ".countHexBytes())
|
||||
assertEquals(1, " f0 ".countHexBytes())
|
||||
|
||||
assertEquals(2, " 01 01 ".countHexBytes())
|
||||
assertEquals(2, " FF FF ".countHexBytes())
|
||||
assertEquals(2, " ff ff ".countHexBytes())
|
||||
assertEquals(2, " Ff Ff ".countHexBytes())
|
||||
assertEquals(2, " fF fF ".countHexBytes())
|
||||
assertEquals(2, " 0F 0F ".countHexBytes())
|
||||
assertEquals(2, " F0 F0 ".countHexBytes())
|
||||
assertEquals(2, " 0f 0f ".countHexBytes())
|
||||
assertEquals(2, " f0 f0 ".countHexBytes())
|
||||
|
||||
assertEquals(2, " 0101 ".countHexBytes())
|
||||
assertEquals(2, " FFFF ".countHexBytes())
|
||||
assertEquals(2, " ffff ".countHexBytes())
|
||||
assertEquals(2, " FfFf ".countHexBytes())
|
||||
assertEquals(2, " fFfF ".countHexBytes())
|
||||
assertEquals(2, " 0F0F ".countHexBytes())
|
||||
assertEquals(2, " F0F0 ".countHexBytes())
|
||||
assertEquals(2, " 0f0f ".countHexBytes())
|
||||
assertEquals(2, " f0f0 ".countHexBytes())
|
||||
|
||||
assertFailsWith<IllegalArgumentException> { "1".countHexBytes() }
|
||||
assertFailsWith<IllegalArgumentException> { "0_1".countHexBytes() }
|
||||
assertFailsWith<IllegalArgumentException> { "0 1".countHexBytes() }
|
||||
assertFailsWith<IllegalArgumentException> { "g".countHexBytes() }
|
||||
assertFailsWith<IllegalArgumentException> { "_".countHexBytes() }
|
||||
assertFailsWith<IllegalArgumentException> { "123".countHexBytes() }
|
||||
assertFailsWith<IllegalArgumentException> { "0x12".countHexBytes() }
|
||||
assertFailsWith<IllegalArgumentException> { "12 3".countHexBytes() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test hexToBytes`() {
|
||||
assertContentEquals(byteArrayOf(0xff.toByte()), "FF".hexToBytes())
|
||||
assertContentEquals(byteArrayOf(0xff.toByte()), "ff".hexToBytes())
|
||||
assertContentEquals(byteArrayOf(0xff.toByte()), "fF".hexToBytes())
|
||||
assertContentEquals(byteArrayOf(0xff.toByte()), "Ff".hexToBytes())
|
||||
|
||||
assertContentEquals(byteArrayOf(0x00.toByte()), "00".hexToBytes())
|
||||
assertContentEquals(byteArrayOf(0x0f.toByte()), "0f".hexToBytes())
|
||||
assertContentEquals(byteArrayOf(0x34.toByte()), "34".hexToBytes())
|
||||
assertContentEquals(byteArrayOf(0x7f.toByte()), "7f".hexToBytes())
|
||||
|
||||
assertContentEquals(byteArrayOf(0xff.toByte(), 0xff.toByte()), " FF FF ".hexToBytes())
|
||||
assertContentEquals(byteArrayOf(0xff.toByte(), 0xff.toByte()), " ff ff ".hexToBytes())
|
||||
assertContentEquals(byteArrayOf(0xff.toByte(), 0xff.toByte()), " fF fF ".hexToBytes())
|
||||
assertContentEquals(byteArrayOf(0xff.toByte(), 0xff.toByte()), " Ff Ff ".hexToBytes())
|
||||
|
||||
assertContentEquals(byteArrayOf(0x00.toByte(), 0x00.toByte()), " 00 00 ".hexToBytes())
|
||||
assertContentEquals(byteArrayOf(0x0f.toByte(), 0x0f.toByte()), " 0f 0f ".hexToBytes())
|
||||
assertContentEquals(byteArrayOf(0x34.toByte(), 0x34.toByte()), " 34 34 ".hexToBytes())
|
||||
assertContentEquals(byteArrayOf(0x7f.toByte(), 0x7f.toByte()), " 7f 7f ".hexToBytes())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test hexToUBytes`() {
|
||||
// implementations of hexToBytes and hexToUBytes are very similar.
|
||||
|
||||
assertContentEquals(ubyteArrayOf(0x7f.toUByte(), 0x7f.toUByte()), " 7f 7f ".hexToUBytes())
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ import net.mamoe.mirai.message.data.Dice
|
||||
import net.mamoe.mirai.message.data.MarketFace
|
||||
import net.mamoe.mirai.message.data.Message
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.utils.chunkedHexToBytes
|
||||
import net.mamoe.mirai.utils.hexToBytes
|
||||
|
||||
@SerialName(MarketFace.SERIAL_NAME)
|
||||
@Serializable
|
||||
@ -89,12 +89,12 @@ internal fun Dice.toJceStruct(): ImMsgBody.MarketFace {
|
||||
*/
|
||||
@Suppress("SpellCheckingInspection")
|
||||
private val DICE_PC_FACE_IDS = mapOf(
|
||||
1 to "E6EEDE15CDFBEB4DF0242448535354F1".chunkedHexToBytes(),
|
||||
2 to "C5A95816FB5AFE34A58AF0E837A3B5A0".chunkedHexToBytes(),
|
||||
3 to "382131D722EEA4624F087C5B8035AF5F".chunkedHexToBytes(),
|
||||
4 to "FA90E956DCAD76742F2DB87723D3B669".chunkedHexToBytes(),
|
||||
5 to "D51FA892017647431BB243920EC9FB8E".chunkedHexToBytes(),
|
||||
6 to "7A2303AD80755FCB6BBFAC38327E0C01".chunkedHexToBytes(),
|
||||
1 to "E6EEDE15CDFBEB4DF0242448535354F1".hexToBytes(),
|
||||
2 to "C5A95816FB5AFE34A58AF0E837A3B5A0".hexToBytes(),
|
||||
3 to "382131D722EEA4624F087C5B8035AF5F".hexToBytes(),
|
||||
4 to "FA90E956DCAD76742F2DB87723D3B669".hexToBytes(),
|
||||
5 to "D51FA892017647431BB243920EC9FB8E".hexToBytes(),
|
||||
6 to "7A2303AD80755FCB6BBFAC38327E0C01".hexToBytes(),
|
||||
)
|
||||
|
||||
private fun ImMsgBody.MarketFace.toDiceOrNull(): Dice? {
|
||||
|
@ -11,8 +11,8 @@ package net.mamoe.mirai.internal.utils.crypto
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import net.mamoe.mirai.utils.chunkedHexToBytes
|
||||
import net.mamoe.mirai.utils.decodeBase64
|
||||
import net.mamoe.mirai.utils.hexToBytes
|
||||
import java.security.KeyFactory
|
||||
import java.security.spec.X509EncodedKeySpec
|
||||
|
||||
@ -40,8 +40,8 @@ internal interface ECDHKeyPair {
|
||||
|
||||
object DefaultStub : ECDHKeyPair {
|
||||
val defaultPublicKey =
|
||||
"04edb8906046f5bfbe9abbc5a88b37d70a6006bfbabc1f0cd49dfb33505e63efc5d78ee4e0a4595033b93d02096dcd3190279211f7b4f6785079e19004aa0e03bc".chunkedHexToBytes()
|
||||
val defaultShareKey = "c129edba736f4909ecc4ab8e010f46a3".chunkedHexToBytes()
|
||||
"04edb8906046f5bfbe9abbc5a88b37d70a6006bfbabc1f0cd49dfb33505e63efc5d78ee4e0a4595033b93d02096dcd3190279211f7b4f6785079e19004aa0e03bc".hexToBytes()
|
||||
val defaultShareKey = "c129edba736f4909ecc4ab8e010f46a3".hexToBytes()
|
||||
|
||||
override val privateKey: Nothing get() = error("stub!")
|
||||
override val publicKey: Nothing get() = error("stub!")
|
||||
@ -130,10 +130,10 @@ internal val publicKeyForVerify by lazy {
|
||||
.generatePublic(X509EncodedKeySpec("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuJTW4abQJXeVdAODw1CamZH4QJZChyT08ribet1Gp0wpSabIgyKFZAOxeArcCbknKyBrRY3FFI9HgY1AyItH8DOUe6ajDEb6c+vrgjgeCiOiCVyum4lI5Fmp38iHKH14xap6xGaXcBccdOZNzGT82sPDM2Oc6QYSZpfs8EO7TYT7KSB2gaHz99RQ4A/Lel1Vw0krk+DescN6TgRCaXjSGn268jD7lOO23x5JS1mavsUJtOZpXkK9GqCGSTCTbCwZhI33CpwdQ2EHLhiP5RaXZCio6lksu+d8sKTWU1eEiEb3cQ7nuZXLYH7leeYFoPtbFV4RicIWp0/YG+RP7rLPCwIDAQAB".decodeBase64()))
|
||||
}
|
||||
internal val defaultInitialPublicKey: ECDHInitialPublicKey by lazy { ECDHInitialPublicKey(keyStr = "04EBCA94D733E399B2DB96EACDD3F69A8BB0F74224E2B44E3357812211D2E62EFBC91BB553098E25E33A799ADC7F76FEB208DA7C6522CDB0719A305180CC54A82E") }
|
||||
private val signHead = "3059301306072a8648ce3d020106082a8648ce3d030107034200".chunkedHexToBytes()
|
||||
private val signHead = "3059301306072a8648ce3d020106082a8648ce3d030107034200".hexToBytes()
|
||||
|
||||
internal fun String.adjustToPublicKey(): ECDHPublicKey {
|
||||
return this.chunkedHexToBytes().adjustToPublicKey()
|
||||
return this.hexToBytes().adjustToPublicKey()
|
||||
}
|
||||
|
||||
internal fun ByteArray.adjustToPublicKey(): ECDHPublicKey {
|
||||
|
@ -14,7 +14,6 @@ import kotlinx.serialization.decodeFromHexString
|
||||
import kotlinx.serialization.protobuf.ProtoBuf
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.internal.AbstractTestWithMiraiImpl
|
||||
import net.mamoe.mirai.internal.MiraiImpl
|
||||
import net.mamoe.mirai.internal.MockBot
|
||||
import net.mamoe.mirai.internal.getMiraiImpl
|
||||
import net.mamoe.mirai.internal.message.DeepMessageRefiner.refineDeep
|
||||
@ -31,7 +30,7 @@ import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.message.data.MessageChain.Companion.serializeToJsonString
|
||||
import net.mamoe.mirai.utils.PlatformLogger
|
||||
import net.mamoe.mirai.utils.autoHexToBytes
|
||||
import net.mamoe.mirai.utils.hexToBytes
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.random.Random
|
||||
import kotlin.test.assertEquals
|
||||
@ -177,7 +176,7 @@ internal class MessageRefineTest : AbstractTestWithMiraiImpl() {
|
||||
|
||||
val nestedForward =
|
||||
"0a790a3008d285d8cc041852200028f9263084f99c83064a1608d285d8cc04220ee69eabe790b3c2b7e99ba8e88eb9a2010210011a450a430a0618d5f0fbdf0412390a370a315be59088e5b9b6e8bdace58f915de8afb7e4bdbfe794a8e6898be69cba5151e69c80e696b0e78988e69cace69fa5e79c8b1a005a000a620a3f08d285d8cc041852200028fb2630f5f99c83064a2508d285d8cc04221de7bea4e59e83e59cbeefbc8ce697b6e4b88de697b6e69da5e8a2ab6763a2010210011a1f0a1d0a0618df98a9a10d12090a070a01351a005a0012084a060890e60260000a97010a3f08d285d8cc0418522000288a2730ef999d83064a2508d285d8cc04221de7bea4e59e83e59cbeefbc8ce697b6e4b88de697b6e69da5e8a2ab6763a2010210011a540a520a0618a19bc4fe09122fea022c08fb2610d285d8cc0418f5f99c830620012a050a030a01353001420a188fefa5ae8a8080800150d285d8cc04120d0a0b0a0561736566661a005a0012084a060890e602600012fe060a084d756c74694d736712f1060af0040a3008d285d8cc041852200028f9263084f99c83064a1608d285d8cc04220ee69eabe790b3c2b7e99ba8e88eb9a2010210011abb040ab8040a0618d5f0fbdf0412ad0462aa040aa30401789cbd535d6f1241147df7574cc6676497a5c036bb3408bbb608550a02d234cdb2ccc2da1db6ccccb2edbe359af8fdf5604c6cad8969134d8d9a98544d2c0ffe1617f0c9bfe080561b5f7c30f14e723373ef9c73ef99dc51e636b003fa8850dbedaa503c234080baa6dbb2bb6d157acc8aa4e05cfa14e0a660da064d62234b85cbe3ad5be1decbf1ebb7e1d1a31508f0aa653b68d1c0488545cf617691b6571389999ca8c96224a38952249ee43b5917e488248852327936abcb991c0486c9a6a5fb36f28fa110b0b287551883c0720cde88040145a46f9b6821c74f33c715cb76c02b8a02ef1aa48162338481636cba1ee351c823cc660e02a6ebb84485a785a971ae294c8a430e1a0df6b898d1936b272501253a45fe85219698300c770f460fde7d7eff75fbc5f8dec75950a15cc23f3164caf99a96af674dcbcad44c400d622d87db83d1cdeb2bffb933fe3ae1eed57067f0edd39de1e3c32f1fee723f7cba3f7e7ed0366741f55c3568cc2fe1a5b546bd12d3a592b0982b89eb976b58971af54ea715bbe417af14e58b55d6aaf17ca3baae558235bfd835850b755d0a7a3d9f90423320fd3c08923579a3d9d419958c8542b613b082ee5332df4f56b4780a8bbee9457b74be10b43cdfa71ea3e7b576aee4aabf0501a543d24a943ba0500f63836cfe52971226eb8ff779b63fdab93d3e7a15de7f383cbc31dc7ac329a23f919c233a19a8b4425d8f980874a7e37d724c202ff62339b9ccff47fa3b18253b9f10231a000a620a3f08d285d8cc041852200028fb2630f5f99c83064a2508d285d8cc04221de7bea4e59e83e59cbeefbc8ce697b6e4b88de697b6e69da5e8a2ab6763a2010210011a1f0a1d0a0618df98a9a10d12090a070a01351a005a0012084a060890e60260000a97010a3f08d285d8cc0418522000288a2730ef999d83064a2508d285d8cc04221de7bea4e59e83e59cbeefbc8ce697b6e4b88de697b6e69da5e8a2ab6763a2010210011a540a520a0618a19bc4fe09122fea022c08fb2610d285d8cc0418f5f99c830620012a050a030a01353001420a188fefa5ae8a8080800150d285d8cc04120d0a0b0a0561736566661a005a0012084a060890e602600012f3040a2d4d756c74694d73675f36363544314539312d414531332d343739312d394630392d33303133373742434639414412c1040a4e0a3108d285d8cc041852200028ffb20130fef89c83064a1608d285d8cc04220ee69eabe790b3c2b7e99ba8e88eb9a2010210011a190a170a061881f9d1ae02120d0a0b0a0554734d73671a005a000ab9010a3108d285d8cc041852200028ffb20130fff89c83064a1608d285d8cc04220ee69eabe790b3c2b7e99ba8e88eb9a2010210011a83010a80010a0618e3fde8a20b121b0a190a1341534a57454a58436366664157630a736172661a005a00125942571220463042383130354243463033374133323733413644343133453941333043393338b0bd858e0940b787ace70b485050005a0060006a10f0b8105bcf037a3273a6d413e9a30c93a00100b001ac02b8018302c801b85c0a4e0a3108d285d8cc041852200028ffb2013080f99c83064a1608d285d8cc04220ee69eabe790b3c2b7e99ba8e88eb9a2010210011a190a170a0618d1afffda02120d0a0b0a0554734d73671a005a000ae2010a4008d285d8cc041852200028ffb2013081f99c83064a2508d285d8cc04221de7bea4e59e83e59cbeefbc8ce697b6e4b88de697b6e69da5e8a2ab6763a2010210011a9d010a9a010a0618bfb1ebfb0f128f010a8c010a85015647567a5a48526d526b5a585432463351304e4451317059576d46335a586868643255774d6a4d3950567464573246335a567045547a6b774d6e63304f5846337a71717772724c627a72764a0a7a3757397862624674733361494c43687a744c46777372487637544534386d317763752f7173484c7a64757777737574734b456744516f3d1a005a00"
|
||||
.autoHexToBytes().loadAs(MsgTransmit.PbMultiMsgTransmit.serializer())
|
||||
.hexToBytes().loadAs(MsgTransmit.PbMultiMsgTransmit.serializer())
|
||||
|
||||
private fun decodeProto(p: String) = ProtoBuf.decodeFromHexString<List<ImMsgBody.Elem>>(p)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user