mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-05 23:50:08 +08:00
Move _contentToString
outside mirai-core main sourceSets, and rename it to structureToString
This commit is contained in:
parent
575225874c
commit
bf98ab7858
@ -31,7 +31,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.chat.image.LongConn
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
|
||||
import net.mamoe.mirai.internal.utils.AtomicIntSeq
|
||||
import net.mamoe.mirai.internal.utils.C2CPkgMsgParsingCache
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.structureToString
|
||||
import net.mamoe.mirai.message.MessageReceipt
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.utils.*
|
||||
@ -112,7 +112,7 @@ internal sealed class AbstractUser(
|
||||
} else {
|
||||
throw contextualBugReportException(
|
||||
"Failed to compute friend image image from resourceId: ${resp.resourceId}",
|
||||
resp._miraiContentToString(),
|
||||
resp.structureToString(),
|
||||
additional = "并附加此时正在上传的文件"
|
||||
)
|
||||
}
|
||||
|
@ -21,9 +21,9 @@ import net.mamoe.mirai.contact.ContactOrBot
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.User
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.*
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
||||
import net.mamoe.mirai.internal.utils.structureToString
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.message.data.Image.Key.IMAGE_ID_REGEX
|
||||
import net.mamoe.mirai.utils.*
|
||||
@ -109,7 +109,7 @@ OnlineFriendImage() {
|
||||
Image.logger.warning(
|
||||
contextualBugReportException(
|
||||
"Failed to compute friend imageId: resId=${delegate.resId}",
|
||||
delegate._miraiContentToString(),
|
||||
delegate.structureToString(),
|
||||
additional = "并描述此时 Bot 是否正在从好友或群接受消息, 尽量附加该图片原文件"
|
||||
)
|
||||
)
|
||||
|
@ -25,8 +25,8 @@ import net.mamoe.mirai.internal.getGroupByUinOrCodeOrFail
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.SourceMsg
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
||||
import net.mamoe.mirai.internal.utils.structureToString
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.MessageSourceKind
|
||||
import net.mamoe.mirai.message.data.OnlineMessageSource
|
||||
@ -177,10 +177,10 @@ internal class OnlineMessageSourceFromGroupImpl(
|
||||
|
||||
override val subject: GroupImpl by lazy {
|
||||
val groupCode = msg.first().msgHead.groupInfo?.groupCode
|
||||
?: error("cannot find groupCode for OnlineMessageSourceFromGroupImpl. msg=${msg._miraiContentToString()}")
|
||||
?: error("cannot find groupCode for OnlineMessageSourceFromGroupImpl. msg=${msg.structureToString()}")
|
||||
|
||||
val group = bot.getGroup(groupCode)?.checkIsGroupImpl()
|
||||
?: error("cannot find group for OnlineMessageSourceFromGroupImpl. msg=${msg._miraiContentToString()}")
|
||||
?: error("cannot find group for OnlineMessageSourceFromGroupImpl. msg=${msg.structureToString()}")
|
||||
|
||||
group
|
||||
}
|
||||
@ -192,7 +192,7 @@ internal class OnlineMessageSourceFromGroupImpl(
|
||||
if (member != null) return@lazy member
|
||||
|
||||
val anonymousInfo = msg.first().msgBody.richText.elems.firstOrNull { it.anonGroupMsg != null }
|
||||
?: error("cannot find member for OnlineMessageSourceFromGroupImpl. msg=${msg._miraiContentToString()}")
|
||||
?: error("cannot find member for OnlineMessageSourceFromGroupImpl. msg=${msg.structureToString()}")
|
||||
|
||||
anonymousInfo.run {
|
||||
group.newAnonymous(anonGroupMsg!!.anonNick.decodeToString(), anonGroupMsg.anonId.encodeBase64())
|
||||
|
@ -20,7 +20,7 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.MsgOnlinePush
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.OnlinePushTrans
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.NewContact
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.structureToString
|
||||
import net.mamoe.mirai.utils.*
|
||||
|
||||
internal class UnconsumedNoticesAlerter(
|
||||
@ -81,7 +81,7 @@ internal class UnconsumedNoticesAlerter(
|
||||
logger.debug(
|
||||
contextualBugReportException(
|
||||
"解析 OnlinePush.PbPushTransMsg, msgType=${data.msgType}",
|
||||
data._miraiContentToString(),
|
||||
data.structureToString(),
|
||||
null,
|
||||
"并描述此时机器人是否被踢出, 或是否有成员列表变更等动作.",
|
||||
)
|
||||
@ -127,7 +127,7 @@ internal class UnconsumedNoticesAlerter(
|
||||
data.msg?.context {
|
||||
throw contextualBugReportException(
|
||||
"解析 NewContact.SystemMsgNewGroup, subType=$subType, groupMsgType=$groupMsgType",
|
||||
forDebug = this._miraiContentToString(),
|
||||
forDebug = this.structureToString(),
|
||||
additional = "并尽量描述此时机器人是否正被邀请加入群, 或者是有有新群员加入此群",
|
||||
)
|
||||
}
|
||||
@ -139,7 +139,7 @@ internal class UnconsumedNoticesAlerter(
|
||||
if (logger.isEnabled && logger.isDebugEnabled) {
|
||||
throw contextualBugReportException(
|
||||
"decode SvcRequestPushStatus (PC Client status change)",
|
||||
data._miraiContentToString(),
|
||||
data.structureToString(),
|
||||
additional = "unknown status=${data.status}",
|
||||
)
|
||||
}
|
||||
|
@ -28,9 +28,9 @@ import net.mamoe.mirai.internal.network.protocol.data.jce.MsgType0x210
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x122
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x27
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.TroopTips0x857
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.internal.utils.parseToMessageDataList
|
||||
import net.mamoe.mirai.internal.utils.structureToString
|
||||
import net.mamoe.mirai.utils.*
|
||||
|
||||
internal class GroupNotificationProcessor(
|
||||
@ -362,7 +362,7 @@ internal class GroupNotificationProcessor(
|
||||
else -> {
|
||||
markNotConsumed()
|
||||
logger.debug {
|
||||
"Unknown Transformers528 0x14 template\ntemplId=${grayTip?.templId}\nPermList=${grayTip?.msgTemplParam?._miraiContentToString()}"
|
||||
"Unknown Transformers528 0x14 template\ntemplId=${grayTip?.templId}\nPermList=${grayTip?.msgTemplParam?.structureToString()}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,9 +33,9 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.OnlinePushTrans
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x44
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.internal.utils.parseToMessageDataList
|
||||
import net.mamoe.mirai.internal.utils.structureToString
|
||||
import net.mamoe.mirai.internal.utils.toMemberInfo
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.context
|
||||
@ -212,7 +212,7 @@ internal class GroupOrMemberListNoticeProcessor(
|
||||
} else {
|
||||
throw contextualBugReportException(
|
||||
"解析 NewContact.SystemMsgNewGroup, subType=5, groupMsgType=$groupMsgType",
|
||||
data._miraiContentToString(),
|
||||
data.structureToString(),
|
||||
null,
|
||||
"并描述此时机器人是否被邀请加入群等其他",
|
||||
)
|
||||
@ -244,7 +244,7 @@ internal class GroupOrMemberListNoticeProcessor(
|
||||
}
|
||||
else -> throw contextualBugReportException(
|
||||
"parse SystemMsgNewGroup, subType=1",
|
||||
this._miraiContentToString(),
|
||||
this.structureToString(),
|
||||
additional = "并尽量描述此时机器人是否正被邀请加入群, 或者是有有新群员加入此群"
|
||||
)
|
||||
}
|
||||
@ -287,7 +287,7 @@ internal class GroupOrMemberListNoticeProcessor(
|
||||
else -> {
|
||||
throw contextualBugReportException(
|
||||
"解析 NewContact.SystemMsgNewGroup, subType=5, groupMsgType=$groupMsgType",
|
||||
this._miraiContentToString(),
|
||||
this.structureToString(),
|
||||
null,
|
||||
"并描述此时机器人是否被踢出群等",
|
||||
)
|
||||
|
@ -36,9 +36,9 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0xb3.SubMs
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.NewContact
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList.GetFriendGroupList
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.io.ProtoBuf
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.internal.utils.structureToString
|
||||
import net.mamoe.mirai.utils.*
|
||||
|
||||
/**
|
||||
@ -216,7 +216,7 @@ internal class FriendNoticeProcessor(
|
||||
}
|
||||
}
|
||||
if (body.msgProfileInfos.isEmpty() || containsUnknown) {
|
||||
logger.debug { "Transformers528 0x27L: ProfileChanged new data: ${body._miraiContentToString()}" }
|
||||
logger.debug { "Transformers528 0x27L: ProfileChanged new data: ${body.structureToString()}" }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,8 +31,8 @@ import net.mamoe.mirai.internal.network.handler.logger
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.RequestPushStatus
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.SubMsgType0x7
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.internal.utils.structureToString
|
||||
import net.mamoe.mirai.message.data.PlainText
|
||||
import net.mamoe.mirai.message.data.buildMessageChain
|
||||
import net.mamoe.mirai.utils.context
|
||||
@ -70,9 +70,9 @@ internal class OtherClientNoticeProcessor : MixedNoticeProcessor() {
|
||||
bot.network.logger.warning(
|
||||
contextualBugReportException(
|
||||
"SvcRequestPushStatus (OtherClient online)",
|
||||
"packet: \n" + data._miraiContentToString() +
|
||||
"packet: \n" + data.structureToString() +
|
||||
"\n\nquery: \n" +
|
||||
Mirai.getOnlineOtherClientsList(bot)._miraiContentToString(),
|
||||
Mirai.getOnlineOtherClientsList(bot).structureToString(),
|
||||
additional = "Failed to find corresponding instanceInfo.",
|
||||
),
|
||||
)
|
||||
|
@ -26,10 +26,10 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.MsgTransmit
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MultiMsg
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketFactory
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.buildOutgoingUniPacket
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.readProtoBuf
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.writeProtoBuf
|
||||
import net.mamoe.mirai.internal.utils.structureToString
|
||||
import net.mamoe.mirai.message.data.ForwardMessage
|
||||
import net.mamoe.mirai.message.data.MessageSource
|
||||
import net.mamoe.mirai.message.data.toMessageChain
|
||||
@ -120,7 +120,7 @@ internal class MultiMsg {
|
||||
) : Response() {
|
||||
override fun toString(): String {
|
||||
if (PacketCodec.PacketLogger.isEnabled) {
|
||||
return _miraiContentToString()
|
||||
return structureToString()
|
||||
}
|
||||
return "MultiMsg.ApplyUp.Response.RequireUpload"
|
||||
}
|
||||
@ -168,7 +168,7 @@ internal class MultiMsg {
|
||||
//1 -> Response.OK(resId = response.msgResid)
|
||||
else -> {
|
||||
error(kotlin.run {
|
||||
println(response._miraiContentToString())
|
||||
println(response.structureToString())
|
||||
}.let { "Protocol error: MultiMsg.ApplyUp failed with result ${response.result}" })
|
||||
}
|
||||
}
|
||||
@ -221,7 +221,7 @@ internal class MultiMsg {
|
||||
//1 -> Response.OK(resId = response.msgResid)
|
||||
else -> throw contextualBugReportException(
|
||||
"MultiMsg.ApplyDown",
|
||||
response._miraiContentToString(),
|
||||
response.structureToString(),
|
||||
additional = "Decode failure result=${response.result}"
|
||||
)
|
||||
}
|
||||
|
@ -41,8 +41,8 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.StatSvcGetOnline
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.StatSvcSimpleGet
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.*
|
||||
import net.mamoe.mirai.internal.utils.NetworkType
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.*
|
||||
import net.mamoe.mirai.internal.utils.structureToString
|
||||
import net.mamoe.mirai.internal.utils.toIpV4Long
|
||||
import net.mamoe.mirai.utils.*
|
||||
|
||||
@ -369,7 +369,7 @@ internal class StatSvc {
|
||||
|
||||
else -> throw contextualBugReportException(
|
||||
"decode SvcReqMSFLoginNotify (OtherClient status change)",
|
||||
notify._miraiContentToString(),
|
||||
notify.structureToString(),
|
||||
additional = "unknown notify.status=${notify.status}"
|
||||
)
|
||||
}
|
||||
|
@ -22,9 +22,9 @@ import net.mamoe.mirai.internal.network.protocol.packet.*
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin.WtLoginExt
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin.analysisTlv0x531
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin.orEmpty
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.crypto.TEA
|
||||
import net.mamoe.mirai.internal.utils.soutv
|
||||
import net.mamoe.mirai.internal.utils.printStructurally
|
||||
import net.mamoe.mirai.internal.utils.structureToString
|
||||
import net.mamoe.mirai.utils.*
|
||||
|
||||
internal class WtLogin {
|
||||
@ -163,7 +163,7 @@ internal class WtLogin {
|
||||
val tlvMap: TlvMap = this._readTLVMap()
|
||||
|
||||
if (SHOW_TLV_MAP_ON_LOGIN_SUCCESS) {
|
||||
tlvMap.smartToString().soutv("tlvMap outer")
|
||||
tlvMap.smartToString().printStructurally("tlvMap outer")
|
||||
}
|
||||
|
||||
// tlvMap.printTLVMap()
|
||||
@ -185,7 +185,7 @@ internal class WtLogin {
|
||||
// 1, 15 -> onErrorMessage(tlvMap) ?: error("Cannot find error message")
|
||||
else -> {
|
||||
onErrorMessage(type.toInt(), tlvMap, bot)
|
||||
?: error("Cannot find error message, unknown login result type: $type, TLVMap = ${tlvMap._miraiContentToString()}")
|
||||
?: error("Cannot find error message, unknown login result type: $type, TLVMap = ${tlvMap.structureToString()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -242,7 +242,7 @@ internal class WtLogin {
|
||||
// } else error("UNKNOWN CAPTCHA QUESTION: ${question.toUHexString()}, tlvMap=" + tlvMap.contentToString())
|
||||
}
|
||||
|
||||
error("UNKNOWN CAPTCHA, tlvMap=" + tlvMap._miraiContentToString())
|
||||
error("UNKNOWN CAPTCHA, tlvMap=" + tlvMap.structureToString())
|
||||
}
|
||||
|
||||
fun onLoginSuccess(subCommand: Int, tlvMap: TlvMap, bot: QQAndroidBot): LoginPacketResponse.Success {
|
||||
@ -266,7 +266,7 @@ internal class WtLogin {
|
||||
val tlvMap119 = this._readTLVMap()
|
||||
|
||||
if (SHOW_TLV_MAP_ON_LOGIN_SUCCESS) {
|
||||
tlvMap119.smartToString().soutv("TlvMap119")
|
||||
tlvMap119.smartToString().printStructurally("TlvMap119")
|
||||
}
|
||||
|
||||
tlvMap119[0x106]?.let { client.analyzeTlv106(it) }
|
||||
@ -366,7 +366,7 @@ internal class WtLogin {
|
||||
} ?: emptyMap()
|
||||
|
||||
if (SHOW_TLV_MAP_ON_LOGIN_SUCCESS) {
|
||||
changeTokenTimeMap._miraiContentToString().soutv("tokenChangeTime")
|
||||
changeTokenTimeMap.structureToString().printStructurally("tokenChangeTime")
|
||||
}
|
||||
|
||||
val outPSKeyMap: PSKeyMap?
|
||||
|
@ -11,205 +11,53 @@
|
||||
|
||||
package net.mamoe.mirai.internal.utils
|
||||
|
||||
import kotlinx.serialization.Transient
|
||||
import net.mamoe.mirai.IMirai
|
||||
import net.mamoe.mirai.utils.DeprecatedSinceMirai
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.debug
|
||||
import net.mamoe.mirai.utils.toUHexString
|
||||
import java.lang.reflect.Modifier
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.full.hasAnnotation
|
||||
import kotlin.reflect.jvm.javaField
|
||||
import net.mamoe.mirai.utils.loadService
|
||||
|
||||
|
||||
private val indent: String = " ".repeat(4)
|
||||
internal fun Any?.structureToString(): String = StructureToStringTransformer.instance.transform(this)
|
||||
|
||||
/**
|
||||
* 将所有元素加入转换为多行的字符串表示.
|
||||
*/
|
||||
private fun <T> Sequence<T>.joinToStringPrefixed(prefix: String, transform: (T) -> CharSequence): String {
|
||||
return this.joinToString(prefix = "$prefix$indent", separator = "\n$prefix$indent", transform = transform)
|
||||
@Suppress("FunctionName")
|
||||
@Deprecated(
|
||||
"",
|
||||
ReplaceWith("this.structureToString()", "net.mamoe.mirai.internal.utils.structureToString"),
|
||||
level = DeprecationLevel.ERROR
|
||||
) // kept for local developers for some time
|
||||
@DeprecatedSinceMirai(errorSince = "2.10")
|
||||
internal fun Any?._miraiContentToString(): String = this.structureToString()
|
||||
|
||||
private val SoutvLogger: MiraiLogger by lazy {
|
||||
MiraiLogger.Factory.create(
|
||||
StructureToStringTransformer::class,
|
||||
"printStructurally"
|
||||
)
|
||||
}
|
||||
|
||||
private val SoutvLogger: MiraiLogger by lazy { MiraiLogger.Factory.create(IMirai::class, "soutv") }
|
||||
internal fun Any?.soutv(name: String = "unnamed") {
|
||||
@Suppress("DEPRECATION")
|
||||
SoutvLogger.debug { "$name = ${this._miraiContentToString()}" }
|
||||
@Deprecated(
|
||||
"",
|
||||
ReplaceWith("this.printStructurally(name)", "net.mamoe.mirai.internal.utils.printStructurally"),
|
||||
level = DeprecationLevel.ERROR
|
||||
)
|
||||
@DeprecatedSinceMirai(errorSince = "2.10")
|
||||
internal fun Any?.soutv(name: String = "unnamed") = this.printStructurally(name)
|
||||
|
||||
internal fun Any?.printStructurally(name: String = "unnamed") {
|
||||
return SoutvLogger.debug { "$name = ${this.structureToString()}" }
|
||||
}
|
||||
|
||||
/**
|
||||
* 将内容格式化为较可读的字符串输出.
|
||||
*
|
||||
* 各数字类型及其无符号类型: 十六进制表示 + 十进制表示. e.g. `0x1000(4096)`
|
||||
* [ByteArray] 和 [UByteArray]: 十六进制表示, 通过 [ByteArray.toUHexString]
|
||||
* [Iterable], [Iterator], [Sequence]: 调用各自的 joinToString.
|
||||
* [Map]: 多行输出. 每行显示一个值. 递归调用 [_miraiContentToString]. 嵌套结构将会以缩进表示
|
||||
* `data class`: 调用其 [toString]
|
||||
* 其他类型: 反射获取它和它的所有来自 Mirai 的 super 类型的所有自有属性并递归调用 [_miraiContentToString]. 嵌套结构将会以缩进表示
|
||||
*/
|
||||
@Suppress("FunctionName") // 这样就不容易被 IDE 提示
|
||||
internal fun Any?._miraiContentToString(prefix: String = ""): String = when (this) {
|
||||
is Unit -> "Unit"
|
||||
is UInt -> "0x" + this.toUHexString("") + "($this)"
|
||||
is UByte -> "0x" + this.toUHexString() + "($this)"
|
||||
is UShort -> "0x" + this.toUHexString("") + "($this)"
|
||||
is ULong -> "0x" + this.toUHexString("") + "($this)"
|
||||
is Int -> "0x" + this.toUHexString("") + "($this)"
|
||||
is Byte -> "0x" + this.toUHexString() + "($this)"
|
||||
is Short -> "0x" + this.toUHexString("") + "($this)"
|
||||
is Long -> "0x" + this.toUHexString("") + "($this)"
|
||||
internal fun interface StructureToStringTransformer {
|
||||
fun transform(any: Any?): String
|
||||
|
||||
is Boolean -> if (this) "true" else "false"
|
||||
companion object {
|
||||
private class ObjectToStringStructureToStringTransformer : StructureToStringTransformer {
|
||||
override fun transform(any: Any?): String = any.toString()
|
||||
}
|
||||
|
||||
is ByteArray -> {
|
||||
if (this.size == 0) "<Empty ByteArray>"
|
||||
else this.toUHexString()
|
||||
}
|
||||
is UByteArray -> {
|
||||
if (this.size == 0) "<Empty UByteArray>"
|
||||
else this.toUHexString()
|
||||
}
|
||||
is ShortArray -> {
|
||||
if (this.size == 0) "<Empty ShortArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is IntArray -> {
|
||||
if (this.size == 0) "<Empty IntArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is LongArray -> {
|
||||
if (this.size == 0) "<Empty LongArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is FloatArray -> {
|
||||
if (this.size == 0) "<Empty FloatArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is DoubleArray -> {
|
||||
if (this.size == 0) "<Empty DoubleArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is UShortArray -> {
|
||||
if (this.size == 0) "<Empty ShortArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is UIntArray -> {
|
||||
if (this.size == 0) "<Empty IntArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is ULongArray -> {
|
||||
if (this.size == 0) "<Empty LongArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is Array<*> -> {
|
||||
if (this.size == 0) "<Empty Array>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is BooleanArray -> {
|
||||
if (this.size == 0) "<Empty BooleanArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
|
||||
is Iterable<*> -> this.joinToString(prefix = "[", postfix = "]") { it._miraiContentToString(prefix) }
|
||||
is Iterator<*> -> this.asSequence().joinToString(prefix = "[", postfix = "]") { it._miraiContentToString(prefix) }
|
||||
is Sequence<*> -> this.joinToString(prefix = "[", postfix = "]") { it._miraiContentToString(prefix) }
|
||||
is Map<*, *> -> this.entries.joinToString(
|
||||
prefix = "{",
|
||||
postfix = "}"
|
||||
) { it.key._miraiContentToString(prefix) + "=" + it.value._miraiContentToString(prefix) }
|
||||
else -> {
|
||||
if (this == null) "null"
|
||||
else if (this::class.isData) this.toString()
|
||||
else {
|
||||
if (this::class.qualifiedName?.startsWith("net.mamoe.mirai.") == true) {
|
||||
this.contentToStringReflectively(prefix + indent)
|
||||
} else this.toString()
|
||||
/*
|
||||
(this::class.simpleName ?: "<UnnamedClass>") + "#" + this::class.hashCode() + "{\n" +
|
||||
this::class.members.asSequence().filterIsInstance<KProperty<*>>().filter { !it.isSuspend && it.visibility == KVisibility.PUBLIC }
|
||||
.joinToStringPrefixed(
|
||||
prefix = indent
|
||||
) { it.name + "=" + kotlin.runCatching { it.call(it).contentToString(indent) }.getOrElse { "<!>" } }
|
||||
*/
|
||||
val instance by lazy {
|
||||
loadService(StructureToStringTransformer::class) { ObjectToStringStructureToStringTransformer() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun KProperty1<*, *>.getValueAgainstPermission(receiver: Any): Any? {
|
||||
return this.javaField?.apply { isAccessible = true }?.get(receiver)
|
||||
}
|
||||
|
||||
private fun Any.canBeIgnored(): Boolean {
|
||||
return when (this) {
|
||||
is String -> this.isEmpty()
|
||||
is ByteArray -> this.isEmpty()
|
||||
is Array<*> -> this.isEmpty()
|
||||
is Number -> this == 0
|
||||
is Int -> this == 0
|
||||
is Float -> this == 0
|
||||
is Double -> this == 0
|
||||
is Byte -> this == 0
|
||||
is Short -> this == 0
|
||||
is Long -> this == 0
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun Any.contentToStringReflectively(
|
||||
prefix: String,
|
||||
filter: ((name: String, value: Any?) -> Boolean)? = null,
|
||||
): String {
|
||||
val newPrefix = "$prefix "
|
||||
return (this::class.simpleName ?: "<UnnamedClass>") + "#" + this::class.hashCode() + " {\n" +
|
||||
this.allMembersFromSuperClassesMatching { it.qualifiedName?.startsWith("net.mamoe.mirai") == true }
|
||||
.distinctBy { it.name }
|
||||
.filterNot { it.name.contains("$") || it.name == "Companion" || it.isConst || it.name == "serialVersionUID" }
|
||||
.mapNotNull {
|
||||
val value = it.getValueAgainstPermission(this) ?: return@mapNotNull null
|
||||
if (filter != null) {
|
||||
if (!filter(it.name, value))
|
||||
return@mapNotNull it.name to value
|
||||
else {
|
||||
return@mapNotNull null
|
||||
}
|
||||
}
|
||||
it.name to value
|
||||
}
|
||||
.joinToStringPrefixed(
|
||||
prefix = newPrefix
|
||||
) { (name: String, value: Any?) ->
|
||||
if (value.canBeIgnored()) ""
|
||||
else {
|
||||
"$name=" + kotlin.runCatching {
|
||||
if (value == this) "<this>"
|
||||
else value._miraiContentToString(newPrefix)
|
||||
}.getOrElse { "<!>" }
|
||||
}
|
||||
}.lines().filterNot { it.isBlank() }.joinToString("\n") + "\n$prefix}"
|
||||
}
|
||||
|
||||
private fun KClass<out Any>.thisClassAndSuperclassSequence(): Sequence<KClass<out Any>> {
|
||||
return sequenceOf(this) +
|
||||
this.supertypes.asSequence()
|
||||
.mapNotNull { type ->
|
||||
type.classifier?.takeIf { it is KClass<*> }?.takeIf { it != Any::class } as? KClass<out Any>
|
||||
}.flatMap { it.thisClassAndSuperclassSequence() }
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun Any.allMembersFromSuperClassesMatching(classFilter: (KClass<out Any>) -> Boolean): Sequence<KProperty1<Any, *>> {
|
||||
return this::class.thisClassAndSuperclassSequence()
|
||||
.filter { classFilter(it) }
|
||||
.map { it.members }
|
||||
.flatMap { it.asSequence() }
|
||||
.filterIsInstance<KProperty1<*, *>>()
|
||||
.filterNot { it.hasAnnotation<Transient>() }
|
||||
.filterNot { it.isTransient() }
|
||||
.mapNotNull { it as KProperty1<Any, *> }
|
||||
}
|
||||
|
||||
internal fun KProperty<*>.isTransient(): Boolean =
|
||||
javaField?.modifiers?.and(Modifier.TRANSIENT) != 0
|
||||
|
||||
|
@ -24,7 +24,7 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.OidbSso
|
||||
import net.mamoe.mirai.internal.utils.io.JceStruct
|
||||
import net.mamoe.mirai.internal.utils.io.ProtoBuf
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.tars.Tars
|
||||
import net.mamoe.mirai.internal.utils.soutv
|
||||
import net.mamoe.mirai.internal.utils.printStructurally
|
||||
import net.mamoe.mirai.utils.read
|
||||
import net.mamoe.mirai.utils.readPacketExact
|
||||
import kotlin.contracts.InvocationKind
|
||||
@ -171,7 +171,7 @@ internal fun <T : ProtoBuf> ByteArray.loadAs(deserializer: DeserializationStrate
|
||||
internal fun <T : ProtoBuf> ByteArray.loadOidb(deserializer: DeserializationStrategy<T>, log: Boolean = false): T {
|
||||
val oidb = loadAs(OidbSso.OIDBSSOPkg.serializer())
|
||||
if (log) {
|
||||
oidb.soutv("OIDB")
|
||||
oidb.printStructurally("OIDB")
|
||||
}
|
||||
return oidb.bodybuffer.loadAs(deserializer)
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import net.mamoe.mirai.internal.message.DeepMessageRefiner.refineDeep
|
||||
import net.mamoe.mirai.internal.message.ForwardMessageInternal
|
||||
import net.mamoe.mirai.internal.message.SimpleRefineContext
|
||||
import net.mamoe.mirai.internal.test.runBlockingUnit
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.structureToString
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
@ -49,7 +49,7 @@ internal class ForwardRefineTest : AbstractTestWithMiraiImpl() {
|
||||
})
|
||||
println(refine.size)
|
||||
println(refine.first()::class)
|
||||
println(refine._miraiContentToString())
|
||||
println(refine.structureToString())
|
||||
assertTrue { refine.first() is MessageOrigin }
|
||||
assertTrue { refine.drop(1).first() is ForwardMessage }
|
||||
assertEquals(
|
||||
|
@ -20,7 +20,7 @@ import net.mamoe.mirai.internal.message.MarketFaceImpl
|
||||
import net.mamoe.mirai.internal.message.OnlineAudioImpl
|
||||
import net.mamoe.mirai.internal.message.UnsupportedMessageImpl
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.structureToString
|
||||
import net.mamoe.mirai.message.MessageSerializers
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.utils.cast
|
||||
@ -201,7 +201,7 @@ internal class MessageSerializationTest {
|
||||
ignoreUnknownKeys = true
|
||||
}
|
||||
val source = j.decodeFromString(MessageSource.Serializer, a)
|
||||
println(source._miraiContentToString())
|
||||
println(source.structureToString())
|
||||
assertEquals(
|
||||
expected = Mirai.buildMessageSource(692928873, MessageSourceKind.GROUP) {
|
||||
id(44)
|
||||
|
212
mirai-core/src/jvmTest/kotlin/utils/StructureToStringLegacy.kt
Normal file
212
mirai-core/src/jvmTest/kotlin/utils/StructureToStringLegacy.kt
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* 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.internal.utils
|
||||
|
||||
import kotlinx.serialization.Transient
|
||||
import net.mamoe.mirai.IMirai
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.debug
|
||||
import net.mamoe.mirai.utils.toUHexString
|
||||
import java.lang.reflect.Modifier
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.full.hasAnnotation
|
||||
import kotlin.reflect.jvm.javaField
|
||||
|
||||
// Kept for souvenir. Not used.
|
||||
internal class StructureToStringLegacy : StructureToStringTransformer {
|
||||
override fun transform(any: Any?): String = any._miraiContentToString()
|
||||
|
||||
private val indent: String = " ".repeat(4)
|
||||
|
||||
/**
|
||||
* 将所有元素加入转换为多行的字符串表示.
|
||||
*/
|
||||
private fun <T> Sequence<T>.joinToStringPrefixed(prefix: String, transform: (T) -> CharSequence): String {
|
||||
return this.joinToString(prefix = "$prefix$indent", separator = "\n$prefix$indent", transform = transform)
|
||||
}
|
||||
|
||||
/**
|
||||
* 将内容格式化为较可读的字符串输出.
|
||||
*
|
||||
* 各数字类型及其无符号类型: 十六进制表示 + 十进制表示. e.g. `0x1000(4096)`
|
||||
* [ByteArray] 和 [UByteArray]: 十六进制表示, 通过 [ByteArray.toUHexString]
|
||||
* [Iterable], [Iterator], [Sequence]: 调用各自的 joinToString.
|
||||
* [Map]: 多行输出. 每行显示一个值. 递归调用 [_miraiContentToString]. 嵌套结构将会以缩进表示
|
||||
* `data class`: 调用其 [toString]
|
||||
* 其他类型: 反射获取它和它的所有来自 Mirai 的 super 类型的所有自有属性并递归调用 [_miraiContentToString]. 嵌套结构将会以缩进表示
|
||||
*/
|
||||
@Suppress("FunctionName") // 这样就不容易被 IDE 提示
|
||||
internal fun Any?._miraiContentToString(prefix: String = ""): String = when (this) {
|
||||
is Unit -> "Unit"
|
||||
is UInt -> "0x" + this.toUHexString("") + "($this)"
|
||||
is UByte -> "0x" + this.toUHexString() + "($this)"
|
||||
is UShort -> "0x" + this.toUHexString("") + "($this)"
|
||||
is ULong -> "0x" + this.toUHexString("") + "($this)"
|
||||
is Int -> "0x" + this.toUHexString("") + "($this)"
|
||||
is Byte -> "0x" + this.toUHexString() + "($this)"
|
||||
is Short -> "0x" + this.toUHexString("") + "($this)"
|
||||
is Long -> "0x" + this.toUHexString("") + "($this)"
|
||||
|
||||
is Boolean -> if (this) "true" else "false"
|
||||
|
||||
is ByteArray -> {
|
||||
if (this.size == 0) "<Empty ByteArray>"
|
||||
else this.toUHexString()
|
||||
}
|
||||
is UByteArray -> {
|
||||
if (this.size == 0) "<Empty UByteArray>"
|
||||
else this.toUHexString()
|
||||
}
|
||||
is ShortArray -> {
|
||||
if (this.size == 0) "<Empty ShortArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is IntArray -> {
|
||||
if (this.size == 0) "<Empty IntArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is LongArray -> {
|
||||
if (this.size == 0) "<Empty LongArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is FloatArray -> {
|
||||
if (this.size == 0) "<Empty FloatArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is DoubleArray -> {
|
||||
if (this.size == 0) "<Empty DoubleArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is UShortArray -> {
|
||||
if (this.size == 0) "<Empty ShortArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is UIntArray -> {
|
||||
if (this.size == 0) "<Empty IntArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is ULongArray -> {
|
||||
if (this.size == 0) "<Empty LongArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is Array<*> -> {
|
||||
if (this.size == 0) "<Empty Array>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
is BooleanArray -> {
|
||||
if (this.size == 0) "<Empty BooleanArray>"
|
||||
else this.iterator()._miraiContentToString()
|
||||
}
|
||||
|
||||
is Iterable<*> -> this.joinToString(prefix = "[", postfix = "]") { it._miraiContentToString(prefix) }
|
||||
is Iterator<*> -> this.asSequence()
|
||||
.joinToString(prefix = "[", postfix = "]") { it._miraiContentToString(prefix) }
|
||||
is Sequence<*> -> this.joinToString(prefix = "[", postfix = "]") { it._miraiContentToString(prefix) }
|
||||
is Map<*, *> -> this.entries.joinToString(
|
||||
prefix = "{",
|
||||
postfix = "}"
|
||||
) { it.key._miraiContentToString(prefix) + "=" + it.value._miraiContentToString(prefix) }
|
||||
else -> {
|
||||
if (this == null) "null"
|
||||
else if (this::class.isData) this.toString()
|
||||
else {
|
||||
if (this::class.qualifiedName?.startsWith("net.mamoe.mirai.") == true) {
|
||||
this.contentToStringReflectively(prefix + indent)
|
||||
} else this.toString()
|
||||
/*
|
||||
(this::class.simpleName ?: "<UnnamedClass>") + "#" + this::class.hashCode() + "{\n" +
|
||||
this::class.members.asSequence().filterIsInstance<KProperty<*>>().filter { !it.isSuspend && it.visibility == KVisibility.PUBLIC }
|
||||
.joinToStringPrefixed(
|
||||
prefix = indent
|
||||
) { it.name + "=" + kotlin.runCatching { it.call(it).contentToString(indent) }.getOrElse { "<!>" } }
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun KProperty1<*, *>.getValueAgainstPermission(receiver: Any): Any? {
|
||||
return this.javaField?.apply { isAccessible = true }?.get(receiver)
|
||||
}
|
||||
|
||||
private fun Any.canBeIgnored(): Boolean {
|
||||
return when (this) {
|
||||
is String -> this.isEmpty()
|
||||
is ByteArray -> this.isEmpty()
|
||||
is Array<*> -> this.isEmpty()
|
||||
is Int -> this == 0
|
||||
is Float -> this == 0f
|
||||
is Double -> this == 0.0
|
||||
is Byte -> this == 0.toByte()
|
||||
is Short -> this == 0.toShort()
|
||||
is Long -> this == 0.toLong()
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun Any.contentToStringReflectively(
|
||||
prefix: String,
|
||||
filter: ((name: String, value: Any?) -> Boolean)? = null,
|
||||
): String {
|
||||
val newPrefix = "$prefix "
|
||||
return (this::class.simpleName ?: "<UnnamedClass>") + "#" + this::class.hashCode() + " {\n" +
|
||||
this.allMembersFromSuperClassesMatching { it.qualifiedName?.startsWith("net.mamoe.mirai") == true }
|
||||
.distinctBy { it.name }
|
||||
.filterNot { it.name.contains("$") || it.name == "Companion" || it.isConst || it.name == "serialVersionUID" }
|
||||
.mapNotNull {
|
||||
val value = it.getValueAgainstPermission(this) ?: return@mapNotNull null
|
||||
if (filter != null) {
|
||||
if (!filter(it.name, value))
|
||||
return@mapNotNull it.name to value
|
||||
else {
|
||||
return@mapNotNull null
|
||||
}
|
||||
}
|
||||
it.name to value
|
||||
}
|
||||
.joinToStringPrefixed(
|
||||
prefix = newPrefix
|
||||
) { (name: String, value: Any?) ->
|
||||
if (value.canBeIgnored()) ""
|
||||
else {
|
||||
"$name=" + kotlin.runCatching {
|
||||
if (value == this) "<this>"
|
||||
else value._miraiContentToString(newPrefix)
|
||||
}.getOrElse { "<!>" }
|
||||
}
|
||||
}.lines().filterNot { it.isBlank() }.joinToString("\n") + "\n$prefix}"
|
||||
}
|
||||
|
||||
private fun KClass<out Any>.thisClassAndSuperclassSequence(): Sequence<KClass<out Any>> {
|
||||
return sequenceOf(this) +
|
||||
this.supertypes.asSequence()
|
||||
.mapNotNull { type ->
|
||||
type.classifier?.takeIf { it is KClass<*> }?.takeIf { it != Any::class } as? KClass<out Any>
|
||||
}.flatMap { it.thisClassAndSuperclassSequence() }
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun Any.allMembersFromSuperClassesMatching(classFilter: (KClass<out Any>) -> Boolean): Sequence<KProperty1<Any, *>> {
|
||||
return this::class.thisClassAndSuperclassSequence()
|
||||
.filter { classFilter(it) }
|
||||
.map { it.members }
|
||||
.flatMap { it.asSequence() }
|
||||
.filterIsInstance<KProperty1<*, *>>()
|
||||
.filterNot { it.hasAnnotation<Transient>() }
|
||||
.filterNot { it.isTransient() }
|
||||
.map { it as KProperty1<Any, *> }
|
||||
}
|
||||
|
||||
internal fun KProperty<*>.isTransient(): Boolean =
|
||||
javaField?.modifiers?.and(Modifier.TRANSIENT) != 0
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user