Commit d1c56633 authored by jiahua.liu's avatar jiahua.liu

Merge remote-tracking branch 'origin/master'

parents c9d40341 d845413b
package net.mamoe.mirai.qqandroid
import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.data.FriendNameRemark
import net.mamoe.mirai.data.GroupInfo
import net.mamoe.mirai.data.PreviousNameList
import net.mamoe.mirai.data.Profile
import net.mamoe.mirai.message.data.ImageId
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.utils.*
import kotlin.coroutines.CoroutineContext
internal abstract class ContactImpl : Contact
internal class QQImpl(bot: Bot, override val coroutineContext: CoroutineContext, override val id: Long) : ContactImpl(), QQ {
override val bot: Bot by bot.unsafeWeakRef()
override suspend fun sendMessage(message: MessageChain) {
TODO("not implemented")
}
override suspend fun uploadImage(image: ExternalImage): ImageId {
TODO("not implemented")
}
override suspend fun queryProfile(): Profile {
TODO("not implemented")
}
override suspend fun queryPreviousNameList(): PreviousNameList {
TODO("not implemented")
}
override suspend fun queryRemark(): FriendNameRemark {
TODO("not implemented")
}
}
internal class MemberImpl(bot: Bot, group: Group, override val coroutineContext: CoroutineContext, override val id: Long) : ContactImpl(), Member {
override val group: Group by group.unsafeWeakRef()
override val permission: MemberPermission
get() = TODO("not implemented")
override val bot: Bot by bot.unsafeWeakRef()
override suspend fun mute(durationSeconds: Int): Boolean {
TODO("not implemented")
}
override suspend fun unmute() {
TODO("not implemented")
}
override suspend fun queryProfile(): Profile {
TODO("not implemented")
}
override suspend fun queryPreviousNameList(): PreviousNameList {
TODO("not implemented")
}
override suspend fun queryRemark(): FriendNameRemark {
TODO("not implemented")
}
override suspend fun sendMessage(message: MessageChain) {
TODO("not implemented")
}
override suspend fun uploadImage(image: ExternalImage): ImageId {
TODO("not implemented")
}
}
@UseExperimental(MiraiInternalAPI::class)
internal class GroupImpl(bot: Bot, override val coroutineContext: CoroutineContext, override val id: Long) : ContactImpl(), Group {
override val internalId: GroupInternalId = GroupId(id).toInternalId()
override val owner: Member
get() = TODO("not implemented")
override val name: String
get() = TODO("not implemented")
override val announcement: String
get() = TODO("not implemented")
override val members: ContactList<Member> = ContactList(LockFreeLinkedList())
override fun getMember(id: Long): Member = members.delegate.filteringGetOrAdd({ it.id == id }, { MemberImpl(bot, this, coroutineContext, id) })
override suspend fun updateGroupInfo(): GroupInfo {
TODO("not implemented")
}
override suspend fun quit(): Boolean {
TODO("not implemented")
}
override val bot: Bot by bot.unsafeWeakRef()
override suspend fun sendMessage(message: MessageChain) {
TODO("not implemented")
}
override suspend fun uploadImage(image: ExternalImage): ImageId {
TODO("not implemented")
}
}
\ No newline at end of file
...@@ -8,8 +8,10 @@ import net.mamoe.mirai.data.ImageLink ...@@ -8,8 +8,10 @@ import net.mamoe.mirai.data.ImageLink
import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.qqandroid.network.QQAndroidBotNetworkHandler import net.mamoe.mirai.qqandroid.network.QQAndroidBotNetworkHandler
import net.mamoe.mirai.qqandroid.network.QQAndroidClient import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.ImageIdQQA
import net.mamoe.mirai.qqandroid.utils.Context import net.mamoe.mirai.qqandroid.utils.Context
import net.mamoe.mirai.utils.BotConfiguration import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.LockFreeLinkedList
import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.MiraiInternalAPI
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
...@@ -27,34 +29,35 @@ internal abstract class QQAndroidBotBase constructor( ...@@ -27,34 +29,35 @@ internal abstract class QQAndroidBotBase constructor(
) : BotImpl<QQAndroidBotNetworkHandler>(account, configuration) { ) : BotImpl<QQAndroidBotNetworkHandler>(account, configuration) {
val client: QQAndroidClient = QQAndroidClient(context, account, bot = @Suppress("LeakingThis") this as QQAndroidBot) val client: QQAndroidClient = QQAndroidClient(context, account, bot = @Suppress("LeakingThis") this as QQAndroidBot)
override val qqs: ContactList<QQ> override val qqs: ContactList<QQ> = ContactList(LockFreeLinkedList())
get() = TODO("not implemented")
override fun getQQ(id: Long): QQ { override fun getQQ(id: Long): QQ {
TODO("not implemented") return qqs.delegate.filteringGetOrAdd({ it.id == id }, { QQImpl(this, coroutineContext, id) })
} }
override fun createNetworkHandler(coroutineContext: CoroutineContext): QQAndroidBotNetworkHandler { override fun createNetworkHandler(coroutineContext: CoroutineContext): QQAndroidBotNetworkHandler {
return QQAndroidBotNetworkHandler(this as QQAndroidBot) return QQAndroidBotNetworkHandler(this as QQAndroidBot)
} }
override val groups: ContactList<Group> override val groups: ContactList<Group> = ContactList(LockFreeLinkedList())
get() = TODO("not implemented")
override suspend fun getGroup(id: GroupId): Group { override suspend fun getGroup(id: GroupId): Group {
TODO("not implemented") return groups.delegate.filteringGetOrAdd({ it.id == id.value }, { GroupImpl(this, coroutineContext, id.value) })
} }
override suspend fun getGroup(internalId: GroupInternalId): Group { override suspend fun getGroup(internalId: GroupInternalId): Group {
TODO("not implemented") internalId.toId().value.let { id ->
return groups.delegate.filteringGetOrAdd({ it.id == id }, { GroupImpl(this, coroutineContext, id) })
}
} }
override suspend fun getGroup(id: Long): Group { override suspend fun getGroup(id: Long): Group {
TODO("not implemented") return groups.delegate.filteringGetOrAdd({ it.id == id }, { GroupImpl(this, coroutineContext, id) })
} }
override suspend fun Image.getLink(): ImageLink { override suspend fun Image.getLink(): ImageLink {
TODO("not implemented") require(this.id is ImageIdQQA) { "image.id must be ImageIdQQA" }
return (this.id as ImageIdQQA).link
} }
override suspend fun addFriend(id: Long, message: String?, remark: String?): AddFriendResult { override suspend fun addFriend(id: Long, message: String?, remark: String?): AddFriendResult {
......
...@@ -4,6 +4,9 @@ import kotlinx.coroutines.* ...@@ -4,6 +4,9 @@ import kotlinx.coroutines.*
import kotlinx.io.core.* import kotlinx.io.core.*
import kotlinx.io.pool.ObjectPool import kotlinx.io.pool.ObjectPool
import net.mamoe.mirai.data.Packet 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.broadcast
import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.QQAndroidBot
...@@ -12,7 +15,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.KnownPacketFactories ...@@ -12,7 +15,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.KnownPacketFactories
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket.LoginPacketResponse.* import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket.LoginPacketResponse.*
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.SvcReqRegisterPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.login.StatSvc
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.io.* import net.mamoe.mirai.utils.io.*
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
...@@ -48,7 +51,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -48,7 +51,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
} }
println("d2key=${bot.client.wLoginSigInfo.d2Key.toUHexString()}") println("d2key=${bot.client.wLoginSigInfo.d2Key.toUHexString()}")
SvcReqRegisterPacket(bot.client).sendAndExpect<SvcReqRegisterPacket.Response>() StatSvc.Register(bot.client).sendAndExpect<StatSvc.Register.Response>()
} }
/** /**
...@@ -113,11 +116,26 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -113,11 +116,26 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
if (PacketReceivedEvent(packet).broadcast().cancelled) { if (PacketReceivedEvent(packet).broadcast().cancelled) {
return@parseIncomingPacket return@parseIncomingPacket
} }
// pass to listeners (attached by sendAndExpect).
packetListeners.forEach { listener -> packetListeners.forEach { listener ->
if (listener.filter(commandName, sequenceId) && packetListeners.remove(listener)) { if (listener.filter(commandName, sequenceId) && packetListeners.remove(listener)) {
listener.complete(packet) listener.complete(packet)
} }
} }
// broadcast
if (packet is Subscribable) {
if (packet is BroadcastControllable) {
if (packet.shouldBroadcast) packet.broadcast()
} else {
packet.broadcast()
}
if (packet is Cancellable && packet.cancelled) return@parseIncomingPacket
}
bot.logger.info(packet)
} }
} finally { } finally {
println() println()
......
...@@ -6,6 +6,7 @@ import net.mamoe.mirai.data.Packet ...@@ -6,6 +6,7 @@ import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.network.io.JceInput import net.mamoe.mirai.qqandroid.network.io.JceInput
import net.mamoe.mirai.qqandroid.network.protocol.jce.RequestPacket import net.mamoe.mirai.qqandroid.network.protocol.jce.RequestPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.OnlinePush
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.SvcReqRegisterPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.login.SvcReqRegisterPacket
import net.mamoe.mirai.utils.DefaultLogger import net.mamoe.mirai.utils.DefaultLogger
...@@ -49,7 +50,8 @@ internal val PacketLogger: MiraiLogger = DefaultLogger("Packet") ...@@ -49,7 +50,8 @@ internal val PacketLogger: MiraiLogger = DefaultLogger("Packet")
@UseExperimental(ExperimentalUnsignedTypes::class) @UseExperimental(ExperimentalUnsignedTypes::class)
internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf( internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
LoginPacket, LoginPacket,
SvcReqRegisterPacket SvcReqRegisterPacket,
OnlinePush.PbPushGroupMsg
) { ) {
fun findPacketFactory(commandName: String): PacketFactory<*>? = this.firstOrNull { it.commandName == commandName } fun findPacketFactory(commandName: String): PacketFactory<*>? = this.firstOrNull { it.commandName == commandName }
...@@ -117,7 +119,14 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf( ...@@ -117,7 +119,14 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
} }
when (flag2) { when (flag2) {
1 -> it.data.parseUniResponse(bot, it.packetFactory, it.sequenceId, consumer) 1 ->//it.data.parseUniResponse(bot, it.packetFactory, it.sequenceId, consumer)
{
consumer(
it.packetFactory.run { decode(bot, it.data) },
it.packetFactory.commandName,
it.sequenceId
)
}
2 -> it.data.parseOicqResponse(bot, it.packetFactory, it.sequenceId, consumer) 2 -> it.data.parseOicqResponse(bot, it.packetFactory, it.sequenceId, consumer)
else -> error("unknown flag2: $flag2. Body to be parsed for inner packet=${it.data.readBytes().toUHexString()}") else -> error("unknown flag2: $flag2. Body to be parsed for inner packet=${it.data.readBytes().toUHexString()}")
} }
......
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data
import kotlinx.serialization.SerialId import kotlinx.serialization.SerialId
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
......
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data
import kotlinx.serialization.SerialId import kotlinx.serialization.SerialId
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
......
@file:Suppress("ArrayInDataClass")
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data
import kotlinx.serialization.SerialId
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumberType
import kotlinx.serialization.protobuf.ProtoType
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
class MessageCommon {
/**
* 1 -> varint
* 2 -> delimi
* 3 -> varint
* 4 -> varint
* 5 -> varint
* 6 -> varint
* 7 -> delimi
* 8 -> delimi
* 9 -> delimi
* 10 -> delimi
* 11 -> delimi
*/
@Serializable
data class PluginInfo(
@SerialId(1) val resId: Int = 0,
@SerialId(2) val packageName: String = "",
@SerialId(3) val newVer: Int = 0,
@SerialId(4) val resType: Int = 0,
@SerialId(5) val lanType: Int = 0,
@SerialId(6) val priority: Int = 0,
@SerialId(7) val resName: String = "",
@SerialId(8) val resDesc: String = "",
@SerialId(9) val resUrlBig: String = "",
@SerialId(10) val resUrlSmall: String = "",
@SerialId(11) val resConf: String = ""
)
@Serializable
data class AppShareInfo(
@ProtoType(ProtoNumberType.FIXED) @SerialId(1) val id: Int = 0,
@SerialId(2) val cookie: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(3) val resource: PluginInfo = PluginInfo()
)
@Serializable
data class ContentHead(
@SerialId(1) val pkgNum: Int = 0,
@SerialId(2) val pkgIndex: Int = 0,
@SerialId(3) val divSeq: Int = 0,
@SerialId(4) val autoReply: Int = 0
)
@Serializable
data class Msg(
val s: String
)
}
\ No newline at end of file
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data
import kotlinx.serialization.SerialId
import kotlinx.serialization.Serializable
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
/**
* msf.msgcomm.msg_comm
*/
@Serializable
class MsgComm {
@Serializable
class AppShareInfo(
@SerialId(1) val appshareId: Int = 0,
@SerialId(2) val appshareCookie: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(3) val appshareResource: PluginInfo? = null
)
@Serializable
class C2CTmpMsgHead(
@SerialId(1) val c2cType: Int = 0,
@SerialId(2) val serviceType: Int = 0,
@SerialId(3) val groupUin: Long = 0L,
@SerialId(4) val groupCode: Long = 0L,
@SerialId(5) val sig: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(6) val sigType: Int = 0,
@SerialId(7) val fromPhone: String = "",
@SerialId(8) val toPhone: String = "",
@SerialId(9) val lockDisplay: Int = 0,
@SerialId(10) val directionFlag: Int = 0,
@SerialId(11) val reserved: ByteArray = EMPTY_BYTE_ARRAY
)
@Serializable
class ContentHead(
@SerialId(1) val pkgNum: Int = 0,
@SerialId(2) val pkgIndex: Int = 0,
@SerialId(3) val divSeq: Int = 0,
@SerialId(4) val autoReply: Int = 0
)
@Serializable
class DiscussInfo(
@SerialId(1) val discussUin: Long = 0L,
@SerialId(2) val discussType: Int = 0,
@SerialId(3) val discussInfoSeq: Long = 0L,
@SerialId(4) val discussRemark: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(5) val discussName: ByteArray = EMPTY_BYTE_ARRAY
)
@Serializable
class ExtGroupKeyInfo(
@SerialId(1) val curMaxSeq: Int = 0,
@SerialId(2) val curTime: Long = 0L
)
@Serializable
class GroupInfo(
@SerialId(1) val groupCode: Long = 0L,
@SerialId(2) val groupType: Int = 0,
@SerialId(3) val groupInfoSeq: Long = 0L,
@SerialId(4) val groupCard: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(5) val groupRank: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(6) val groupLevel: Int = 0,
@SerialId(7) val groupCardType: Int = 0,
@SerialId(8) val groupName: ByteArray = EMPTY_BYTE_ARRAY
)
@Serializable
class Msg(
@SerialId(1) val msgHead: MsgHead? = null,
@SerialId(2) val contentHead: ContentHead? = null,
@SerialId(3) val msgBody: ImMsgBody.MsgBody? = null,
@SerialId(4) val appshareInfo: AppShareInfo? = null
)
@Serializable
class MsgHead(
@SerialId(1) val fromUin: Long = 0L,
@SerialId(2) val toUin: Long = 0L,
@SerialId(3) val msgType: Int = 0,
@SerialId(4) val c2cCmd: Int = 0,
@SerialId(5) val msgSeq: Int = 0,
@SerialId(6) val msgTime: Int = 0,
@SerialId(7) val msgUid: Long = 0L,
@SerialId(8) val c2cTmpMsgHead: C2CTmpMsgHead? = null,
@SerialId(9) val groupInfo: GroupInfo? = null,
@SerialId(10) val fromAppid: Int = 0,
@SerialId(11) val fromInstid: Int = 0,
@SerialId(12) val userActive: Int = 0,
@SerialId(13) val discussInfo: DiscussInfo? = null,
@SerialId(14) val fromNick: String = "",
@SerialId(15) val authUin: Long = 0L,
@SerialId(16) val authNick: String = "",
@SerialId(17) val msgFlag: Int = 0,
@SerialId(18) val authRemark: String = "",
@SerialId(19) val groupName: String = "",
@SerialId(20) val mutiltransHead: MutilTransHead? = null,
@SerialId(21) val msgInstCtrl: ImMsgHead.InstCtrl? = null,
@SerialId(22) val publicAccountGroupSendFlag: Int = 0,
@SerialId(23) val wseqInC2cMsghead: Int = 0,
@SerialId(24) val cpid: Long = 0L,
@SerialId(25) val extGroupKeyInfo: ExtGroupKeyInfo? = null,
@SerialId(26) val multiCompatibleText: String = "",
@SerialId(27) val authSex: Int = 0,
@SerialId(28) val isSrcMsg: Boolean = false
)
@Serializable
class MsgType0x210(
@SerialId(1) val subMsgType: Int = 0,
@SerialId(2) val msgContent: ByteArray = EMPTY_BYTE_ARRAY
)
@Serializable
class MutilTransHead(
@SerialId(1) val status: Int = 0,
@SerialId(2) val msgId: Int = 0
)
@Serializable
class PluginInfo(
@SerialId(1) val resId: Int = 0,
@SerialId(2) val pkgName: String = "",
@SerialId(3) val newVer: Int = 0,
@SerialId(4) val resType: Int = 0,
@SerialId(5) val lanType: Int = 0,
@SerialId(6) val priority: Int = 0,
@SerialId(7) val resName: String = "",
@SerialId(8) val resDesc: String = "",
@SerialId(9) val resUrlBig: String = "",
@SerialId(10) val resUrlSmall: String = "",
@SerialId(11) val resConf: String = ""
)
@Serializable
class Uin2Nick(
@SerialId(1) val uin: Long = 0L,
@SerialId(2) val nick: String = ""
)
@Serializable
class UinPairMsg(
@SerialId(1) val lastReadTime: Int = 0,
@SerialId(2) val peerUin: Long = 0L,
@SerialId(3) val msgCompleted: Int = 0,
@SerialId(4) val msg: List<Msg>? = null,
@SerialId(5) val unreadMsgNum: Int = 0,
@SerialId(8) val c2cType: Int = 0,
@SerialId(9) val serviceType: Int = 0,
@SerialId(10) val pbReserve: ByteArray = EMPTY_BYTE_ARRAY
)
}
\ No newline at end of file
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data
import kotlinx.serialization.SerialId
import kotlinx.serialization.Serializable
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
@Serializable
class MsgOnlinePush {
@Serializable
data class PbPushMsg(
@SerialId(1) val msg: MsgComm.Msg? = null,
@SerialId(2) val svrip: Int = 0,
@SerialId(3) val pushToken: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(4) val pingFlag: Int = 0,
@SerialId(9) val generalFlag: Int = 0
)
}
\ No newline at end of file
...@@ -9,6 +9,8 @@ import net.mamoe.mirai.qqandroid.network.QQAndroidClient ...@@ -9,6 +9,8 @@ import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.Cmd0x352Packet
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.GetImgUrlReq
import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket
internal object ImageDownPacket : PacketFactory<ImageDownPacket.ImageDownPacketResponse>("LongConn.OffPicDown") { internal object ImageDownPacket : PacketFactory<ImageDownPacket.ImageDownPacketResponse>("LongConn.OffPicDown") {
......
...@@ -10,6 +10,8 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.* ...@@ -10,6 +10,8 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.*
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.Cmd0x352Packet
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.UploadImgReq
internal object ImageUpPacket : PacketFactory<ImageUpPacket.ImageUpPacketResponse>("LongConn.OffPicUp") { internal object ImageUpPacket : PacketFactory<ImageUpPacket.ImageUpPacketResponse>("LongConn.OffPicUp") {
......
@file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS")
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact
import kotlinx.io.core.readBytes
import kotlinx.serialization.protobuf.ProtoBuf
import net.mamoe.mirai.contact.MemberPermission
import net.mamoe.mirai.data.ImageLink
import net.mamoe.mirai.message.GroupMessage import net.mamoe.mirai.message.GroupMessage
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.data.ImageId
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.toMessage
import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.ImMsgBody
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.MsgOnlinePush
import net.mamoe.mirai.utils.io.encodeToString
internal class ImageIdQQA(
override val value: String,
originalLink: String
) : ImageId {
val link: ImageLink = ImageLinkQQA("http://gchat.qpic.cn$originalLink")
}
internal inline class ImageLinkQQA(override val original: String) : ImageLink
internal class OnlinePush { internal class OnlinePush {
internal object PbPushGroupMsg : PacketFactory<GroupMessage>("OnlinePush.PbPushGroupMsg") { internal object PbPushGroupMsg : PacketFactory<GroupMessage>("OnlinePush.PbPushGroupMsg") {
@UseExperimental(ExperimentalStdlibApi::class)
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GroupMessage { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GroupMessage {
TODO() // 00 00 02 E4 0A D5 05 0A 4F 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 18 52 20 00 28 BC 3D 30 8C 82 AB F1 05 38 D2 80 E0 8C 80 80 80 80 02 4A 21 08 E7 C1 AD B8 02 10 01 18 BA 05 22 09 48 69 6D 31 38 38 6D 6F 65 30 06 38 02 42 05 4D 69 72 61 69 50 01 58 01 60 00 88 01 08 12 06 08 01 10 00 18 00 1A F9 04 0A F6 04 0A 26 08 00 10 87 82 AB F1 05 18 B7 B4 BF 30 20 00 28 0C 30 00 38 86 01 40 22 4A 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 12 E6 03 42 E3 03 12 2A 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 22 00 2A 04 03 00 00 00 32 60 15 36 20 39 36 6B 45 31 41 38 35 32 32 39 64 63 36 39 38 34 37 39 37 37 62 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 31 32 31 32 41 38 C6 BB 8A A9 08 40 FB AE 9E C2 09 48 50 50 41 5A 00 60 01 6A 10 4E 18 58 22 0E 7B F8 0F C5 B1 34 48 83 74 D3 9C 72 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 31 39 38 3F 74 65 72 6D 3D 32 82 01 57 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 30 3F 74 65 72 6D 3D 32 B0 01 4D B8 01 2E C8 01 FF 05 D8 01 4D E0 01 2E FA 01 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 34 30 30 3F 74 65 72 6D 3D 32 80 02 4D 88 02 2E 12 45 AA 02 42 50 03 60 00 68 00 9A 01 39 08 09 20 BF 50 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00 8A 04 04 08 02 08 01 90 04 80 80 80 10 B8 04 00 C0 04 00 12 06 4A 04 08 00 40 01 12 14 82 01 11 0A 09 48 69 6D 31 38 38 6D 6F 65 18 06 20 08 28 03 10 8A CA 9D A1 07 1A 00
discardExact(4)
val pbPushMsg = ProtoBuf.load(MsgOnlinePush.PbPushMsg.serializer(), readBytes())
val message = MessageChain(initialCapacity = pbPushMsg.msg!!.msgBody!!.richText!!.elems!!.size)
var extraInfo: ImMsgBody.ExtraInfo? = null
pbPushMsg.msg.msgBody!!.richText!!.elems!!.forEach {
when {
it.customFace != null -> message.add(Image(ImageIdQQA(it.customFace.filePath, it.customFace.origUrl)))
it.text != null -> message.add(it.text.str.encodeToString().toMessage())
it.extraInfo != null -> extraInfo = it.extraInfo
}
}
val group = bot.getGroup(pbPushMsg.msg.msgHead!!.groupInfo!!.groupCode)
val flags = extraInfo?.flags ?: 0
return GroupMessage(
bot = bot,
group = group,
senderName = pbPushMsg.msg.msgHead.groupInfo!!.groupCard.encodeToString(),
sender = group.getMember(pbPushMsg.msg.msgHead.fromUin),
message = message,
permission = when {
flags and 16 != 0 -> MemberPermission.ADMINISTRATOR
flags and 8 != 0 -> MemberPermission.OWNER
flags and 0 != 0 -> MemberPermission.MEMBER
else -> {
bot.logger.warning("判断群员权限失败")
MemberPermission.MEMBER
}
}
)
} }
} }
} }
\ No newline at end of file
package net.mamoe.mirai.qqandroid.network.protocol.packet.login
import kotlinx.io.core.ByteReadPacket
import kotlinx.serialization.protobuf.ProtoBuf
import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.io.jceMap
import net.mamoe.mirai.qqandroid.network.io.jceStruct
import net.mamoe.mirai.qqandroid.network.protocol.jce.SvcReqRegister
import net.mamoe.mirai.qqandroid.network.protocol.jce.writeUniRequestPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.oidb.oidb0x769.Oidb0x769
import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket
import net.mamoe.mirai.qqandroid.utils.NetworkType
import net.mamoe.mirai.utils.io.debugPrint
import net.mamoe.mirai.utils.io.encodeToString
import net.mamoe.mirai.utils.io.toReadPacket
import net.mamoe.mirai.utils.localIpAddress
@Suppress("EnumEntryName")
enum class RegPushReason {
appRegister,
createDefaultRegInfo,
fillRegProxy,
msfBoot,
msfByNetChange,
msfHeartTimeTooLong,
serverPush,
setOnlineStatus,
unknown
}
class StatSvc {
internal object Register : PacketFactory<Register.Response>("StatSvc.register") {
internal object Response : Packet {
override fun toString(): String = "Response(StatSvc.register)"
}
private const val subAppId = 537062845L
operator fun invoke(
client: QQAndroidClient,
regPushReason: RegPushReason = RegPushReason.appRegister
): OutgoingPacket = buildLoginOutgoingPacket(
client,
bodyType = 1,
extraData = client.wLoginSigInfo.d2.data,
key = client.wLoginSigInfo.d2Key
) { sequenceId ->
writeSsoPacket(
client, subAppId = subAppId, commandName = commandName,
extraData = client.wLoginSigInfo.tgt.toReadPacket(), sequenceId = sequenceId
) {
writeUniRequestPacket {
sServantName = "PushService"
sFuncName = "SvcReqRegister"
sBuffer = jceMap(
0,
"SvcReqRegister" to jceStruct(
0,
SvcReqRegister().apply {
cConnType = 0
lBid = 1 or 2 or 4
lUin = client.uin
iStatus = client.onlineStatus.id
bKikPC = 0 // 是否把 PC 踢下线
bKikWeak = 0
timeStamp = 0
// timeStamp = currentTimeSeconds // millis or seconds??
iLargeSeq = 1551 // ?
bOpenPush = 1
iLocaleID = 2052
bRegType =
(if (regPushReason == RegPushReason.appRegister ||
regPushReason == RegPushReason.fillRegProxy ||
regPushReason == RegPushReason.createDefaultRegInfo ||
regPushReason == RegPushReason.setOnlineStatus
) 0 else 1).toByte()
bIsSetStatus = if (regPushReason == RegPushReason.setOnlineStatus) 1 else 0
iOSVersion = client.device.version.sdk.toLong()
cNetType = if (client.networkType == NetworkType.WIFI) 1 else 0
vecGuid = client.device.guid
strDevName = client.device.model.encodeToString()
strDevType = client.device.model.encodeToString()
strOSVer = client.device.version.release.encodeToString()
uOldSSOIp = 0
uNewSSOIp = localIpAddress().split(".").foldIndexed(0L) { index: Int, acc: Long, s: String ->
acc or ((s.toLong() shl (index * 16)))
}
strVendorName = "MIUI"
strVendorOSName = "?ONEPLUS A5000_23_17"
// register 时还需要
/*
var44.uNewSSOIp = field_127445;
var44.uOldSSOIp = field_127444;
var44.strVendorName = ROMUtil.getRomName();
var44.strVendorOSName = ROMUtil.getRomVersion(20);
*/
bytes_0x769_reqbody = ProtoBuf.dump(
Oidb0x769.RequestBody.serializer(), Oidb0x769.RequestBody(
rpt_config_list = listOf(
Oidb0x769.ConfigSeq(
type = 46,
version = 0
),
Oidb0x769.ConfigSeq(
type = 283,
version = 0
)
)
)
)
bSetMute = 0
}
)
)
}
this.writePacket(this.build().debugPrint("sso body"))
}
}
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
return Response
}
}
}
package net.mamoe.mirai.qqandroid.network.protocol.packet.login
import kotlinx.io.core.ByteReadPacket
import kotlinx.serialization.protobuf.ProtoBuf
import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.io.jceMap
import net.mamoe.mirai.qqandroid.network.io.jceStruct
import net.mamoe.mirai.qqandroid.network.protocol.jce.SvcReqRegister
import net.mamoe.mirai.qqandroid.network.protocol.jce.writeUniRequestPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.oidb.oidb0x769.Oidb0x769
import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket
import net.mamoe.mirai.qqandroid.utils.NetworkType
import net.mamoe.mirai.utils.io.debugPrint
import net.mamoe.mirai.utils.io.encodeToString
import net.mamoe.mirai.utils.io.toReadPacket
import net.mamoe.mirai.utils.localIpAddress
@Suppress("EnumEntryName")
enum class RegPushReason {
appRegister,
createDefaultRegInfo,
fillRegProxy,
msfBoot,
msfByNetChange,
msfHeartTimeTooLong,
serverPush,
setOnlineStatus,
unknown
}
internal object SvcReqRegisterPacket : PacketFactory<SvcReqRegisterPacket.Response>("StatSvc.register") {
internal object Response : Packet
private const val subAppId = 537062845L
operator fun invoke(
client: QQAndroidClient,
regPushReason: RegPushReason = RegPushReason.appRegister
): OutgoingPacket = buildLoginOutgoingPacket(
client,
bodyType = 1,
extraData = client.wLoginSigInfo.d2.data,
key = client.wLoginSigInfo.d2Key
) { sequenceId ->
writeSsoPacket(
client, subAppId = subAppId, commandName = commandName,
extraData = client.wLoginSigInfo.tgt.toReadPacket(), sequenceId = sequenceId
) {
writeUniRequestPacket {
sServantName = "PushService"
sFuncName = "SvcReqRegister"
sBuffer = jceMap(
0,
"SvcReqRegister" to jceStruct(
0,
SvcReqRegister().apply {
cConnType = 0
lBid = 1 or 2 or 4
lUin = client.uin
iStatus = client.onlineStatus.id
bKikPC = 0 // 是否把 PC 踢下线
bKikWeak = 0
timeStamp = 0
// timeStamp = currentTimeSeconds // millis or seconds??
iLargeSeq = 1551 // ?
bOpenPush = 1
iLocaleID = 2052
bRegType =
(if (regPushReason == RegPushReason.appRegister ||
regPushReason == RegPushReason.fillRegProxy ||
regPushReason == RegPushReason.createDefaultRegInfo ||
regPushReason == RegPushReason.setOnlineStatus
) 0 else 1).toByte()
bIsSetStatus = if (regPushReason == RegPushReason.setOnlineStatus) 1 else 0
iOSVersion = client.device.version.sdk.toLong()
cNetType = if (client.networkType == NetworkType.WIFI) 1 else 0
vecGuid = client.device.guid
strDevName = client.device.model.encodeToString()
strDevType = client.device.model.encodeToString()
strOSVer = client.device.version.release.encodeToString()
uOldSSOIp = 0
uNewSSOIp = localIpAddress().split(".").foldIndexed(0L) { index: Int, acc: Long, s: String ->
acc or ((s.toLong() shl (index * 16)))
}
strVendorName = "MIUI"
strVendorOSName = "?ONEPLUS A5000_23_17"
// register 时还需要
/*
var44.uNewSSOIp = field_127445;
var44.uOldSSOIp = field_127444;
var44.strVendorName = ROMUtil.getRomName();
var44.strVendorOSName = ROMUtil.getRomVersion(20);
*/
bytes_0x769_reqbody = ProtoBuf.dump(
Oidb0x769.RequestBody.serializer(), Oidb0x769.RequestBody(
rpt_config_list = listOf(
Oidb0x769.ConfigSeq(
type = 46,
version = 0
),
Oidb0x769.ConfigSeq(
type = 283,
version = 0
)
)
)
)
bSetMute = 0
}
)
)
}
this.writePacket(this.build().debugPrint("sso body"))
}
}
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
return Response
}
}
\ No newline at end of file
...@@ -5,6 +5,8 @@ package test ...@@ -5,6 +5,8 @@ package test
import net.mamoe.mirai.utils.cryptor.protoFieldNumber import net.mamoe.mirai.utils.cryptor.protoFieldNumber
import net.mamoe.mirai.utils.cryptor.protoType import net.mamoe.mirai.utils.cryptor.protoType
intArrayOf(8, 18, 26, 34, 80).forEach { intArrayOf(
8, 16, 24, 32, 40, 48, 56, 64, 74, 82
).forEach {
println(protoFieldNumber(it.toUInt()).toString() + " -> " + protoType(it.toUInt())) println(protoFieldNumber(it.toUInt()).toString() + " -> " + protoType(it.toUInt()))
} }
\ No newline at end of file
...@@ -4,7 +4,7 @@ import java.lang.reflect.Field ...@@ -4,7 +4,7 @@ import java.lang.reflect.Field
import kotlin.reflect.full.allSuperclasses import kotlin.reflect.full.allSuperclasses
actual fun Any.contentToStringReflectively(prefix: String): String { actual fun Any.contentToStringReflectively(prefix: String, filter: ((name: String, value: Any?) -> Boolean)?): String {
val newPrefix = prefix val newPrefix = prefix
return (this::class.simpleName ?: "<UnnamedClass>") + "#" + this::class.hashCode() + " {\n" + return (this::class.simpleName ?: "<UnnamedClass>") + "#" + this::class.hashCode() + " {\n" +
this.allFieldsFromSuperClassesMatching { it.name.startsWith("net.mamoe.mirai") } this.allFieldsFromSuperClassesMatching { it.name.startsWith("net.mamoe.mirai") }
...@@ -14,6 +14,11 @@ actual fun Any.contentToStringReflectively(prefix: String): String { ...@@ -14,6 +14,11 @@ actual fun Any.contentToStringReflectively(prefix: String): String {
prefix = newPrefix prefix = newPrefix
) { ) {
it.isAccessible = true it.isAccessible = true
if (filter != null) {
kotlin.runCatching {
if (!filter(it.name, it.get(this))) return@joinToStringPrefixed ""
}
}
it.name + "=" + kotlin.runCatching { it.name + "=" + kotlin.runCatching {
val value = it.get(this) val value = it.get(this)
if (value == this) "<this>" if (value == this) "<this>"
......
...@@ -14,6 +14,5 @@ interface ImageLink { ...@@ -14,6 +14,5 @@ interface ImageLink {
suspend fun downloadAsByteArray(): ByteArray = download().readBytes() suspend fun downloadAsByteArray(): ByteArray = download().readBytes()
@UseExperimental(KtorExperimentalAPI::class)
suspend fun download(): ByteReadPacket = Http.get(original) suspend fun download(): ByteReadPacket = Http.get(original)
} }
\ No newline at end of file
...@@ -242,7 +242,7 @@ object NullMessageChain : MessageChain { ...@@ -242,7 +242,7 @@ object NullMessageChain : MessageChain {
override fun contains(sub: String): Boolean = error("accessing NullMessageChain") override fun contains(sub: String): Boolean = error("accessing NullMessageChain")
override fun contains(element: Message): Boolean = error("accessing NullMessageChain") override fun contains(element: Message): Boolean = error("accessing NullMessageChain")
override fun followedBy(tail: Message): MessageChain = error("accessing NullMessageChain") override fun followedBy(tail: Message): MessageChain = tail.toChain()
override val size: Int get() = error("accessing NullMessageChain") override val size: Int get() = error("accessing NullMessageChain")
override fun containsAll(elements: Collection<Message>): Boolean = error("accessing NullMessageChain") override fun containsAll(elements: Collection<Message>): Boolean = error("accessing NullMessageChain")
......
...@@ -222,7 +222,7 @@ fun Any?.contentToString(prefix: String = ""): String = when (this) { ...@@ -222,7 +222,7 @@ fun Any?.contentToString(prefix: String = ""): String = when (this) {
} }
} }
expect fun Any.contentToStringReflectively(prefix: String = ""): String expect fun Any.contentToStringReflectively(prefix: String = "", filter: ((String, Any?) -> Boolean)? = null): String
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun ByteReadPacket.readProtoMap(length: Long = this.remaining): ProtoMap { fun ByteReadPacket.readProtoMap(length: Long = this.remaining): ProtoMap {
......
...@@ -6,19 +6,28 @@ import kotlin.reflect.full.allSuperclasses ...@@ -6,19 +6,28 @@ import kotlin.reflect.full.allSuperclasses
val FIELD_TRY_SET_ACCESSIBLE = Field::class.java.declaredMethods.firstOrNull { it.name == "trySetAccessible" } val FIELD_TRY_SET_ACCESSIBLE = Field::class.java.declaredMethods.firstOrNull { it.name == "trySetAccessible" }
actual fun Any.contentToStringReflectively(prefix: String): String { actual fun Any.contentToStringReflectively(prefix: String, filter: ((name: String, value: Any?) -> Boolean)?): String {
val newPrefix = prefix + ProtoMap.indent val newPrefix = prefix + ProtoMap.indent
return (this::class.simpleName ?: "<UnnamedClass>") + "#" + this::class.hashCode() + " {\n" + return (this::class.simpleName ?: "<UnnamedClass>") + "#" + this::class.hashCode() + " {\n" +
this.allFieldsFromSuperClassesMatching { it.name.startsWith("net.mamoe.mirai") } this.allFieldsFromSuperClassesMatching { it.name.startsWith("net.mamoe.mirai") }
.distinctBy { it.name } .distinctBy { it.name }
.filterNot { it.name.contains("$") || it.name == "Companion" || it.isSynthetic || it.name == "serialVersionUID" } .filterNot { it.name.contains("$") || it.name == "Companion" || it.isSynthetic || it.name == "serialVersionUID" }
.filterNot { it.isEnumConstant } .filterNot { it.isEnumConstant }
.joinToStringPrefixed( .map {
prefix = newPrefix
) {
FIELD_TRY_SET_ACCESSIBLE?.invoke(it, true) ?: kotlin.run { it.isAccessible = true } FIELD_TRY_SET_ACCESSIBLE?.invoke(it, true) ?: kotlin.run { it.isAccessible = true }
it.name + "=" + kotlin.runCatching {
val value = it.get(this) val value = it.get(this)
if (filter != null) {
kotlin.runCatching {
if (!filter(it.name, value)) return@map it.name to FIELD_TRY_SET_ACCESSIBLE
}
}
it.name to value
}
.filterNot { it.second === FIELD_TRY_SET_ACCESSIBLE }
.joinToStringPrefixed(
prefix = newPrefix
) { (name, value) ->
"$name=" + kotlin.runCatching {
if (value == this) "<this>" if (value == this) "<this>"
else value.contentToString(newPrefix) else value.contentToString(newPrefix)
}.getOrElse { "<!>" } }.getOrElse { "<!>" }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment