mirror of
https://github.com/mamoe/mirai.git
synced 2025-05-06 05:45:19 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
d1c56633b8
mirai-core-qqandroid/src
commonMain/kotlin/net/mamoe/mirai/qqandroid
jvmTest/kotlin/test
mirai-core/src
androidMain/kotlin/net/mamoe/mirai/utils/cryptor
commonMain/kotlin/net.mamoe.mirai
jvmMain/kotlin/net/mamoe/mirai/utils/cryptor
@ -0,0 +1,108 @@
|
||||
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")
|
||||
}
|
||||
}
|
@ -8,8 +8,10 @@ import net.mamoe.mirai.data.ImageLink
|
||||
import net.mamoe.mirai.message.data.Image
|
||||
import net.mamoe.mirai.qqandroid.network.QQAndroidBotNetworkHandler
|
||||
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.utils.BotConfiguration
|
||||
import net.mamoe.mirai.utils.LockFreeLinkedList
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
@ -27,34 +29,35 @@ internal abstract class QQAndroidBotBase constructor(
|
||||
) : BotImpl<QQAndroidBotNetworkHandler>(account, configuration) {
|
||||
val client: QQAndroidClient = QQAndroidClient(context, account, bot = @Suppress("LeakingThis") this as QQAndroidBot)
|
||||
|
||||
override val qqs: ContactList<QQ>
|
||||
get() = TODO("not implemented")
|
||||
override val qqs: ContactList<QQ> = ContactList(LockFreeLinkedList())
|
||||
|
||||
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 {
|
||||
return QQAndroidBotNetworkHandler(this as QQAndroidBot)
|
||||
}
|
||||
|
||||
override val groups: ContactList<Group>
|
||||
get() = TODO("not implemented")
|
||||
override val groups: ContactList<Group> = ContactList(LockFreeLinkedList())
|
||||
|
||||
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 {
|
||||
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 {
|
||||
TODO("not implemented")
|
||||
return groups.delegate.filteringGetOrAdd({ it.id == id }, { GroupImpl(this, coroutineContext, id) })
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -4,6 +4,9 @@ import kotlinx.coroutines.*
|
||||
import kotlinx.io.core.*
|
||||
import kotlinx.io.pool.ObjectPool
|
||||
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.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
@ -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.login.LoginPacket
|
||||
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.io.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
@ -48,7 +51,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
}
|
||||
|
||||
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
|
||||
if (PacketReceivedEvent(packet).broadcast().cancelled) {
|
||||
return@parseIncomingPacket
|
||||
}
|
||||
|
||||
// pass to listeners (attached by sendAndExpect).
|
||||
packetListeners.forEach { listener ->
|
||||
if (listener.filter(commandName, sequenceId) && packetListeners.remove(listener)) {
|
||||
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 {
|
||||
println()
|
||||
|
@ -6,6 +6,7 @@ import net.mamoe.mirai.data.Packet
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.network.io.JceInput
|
||||
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.SvcReqRegisterPacket
|
||||
import net.mamoe.mirai.utils.DefaultLogger
|
||||
@ -49,7 +50,8 @@ internal val PacketLogger: MiraiLogger = DefaultLogger("Packet")
|
||||
@UseExperimental(ExperimentalUnsignedTypes::class)
|
||||
internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
|
||||
LoginPacket,
|
||||
SvcReqRegisterPacket
|
||||
SvcReqRegisterPacket,
|
||||
OnlinePush.PbPushGroupMsg
|
||||
) {
|
||||
|
||||
fun findPacketFactory(commandName: String): PacketFactory<*>? = this.firstOrNull { it.commandName == commandName }
|
||||
@ -117,7 +119,14 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
|
||||
}
|
||||
|
||||
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)
|
||||
else -> error("unknown flag2: $flag2. Body to be parsed for inner packet=${it.data.readBytes().toUHexString()}")
|
||||
}
|
||||
|
@ -1,2 +0,0 @@
|
||||
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat
|
||||
|
@ -1,4 +1,4 @@
|
||||
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.Serializable
|
@ -1,4 +1,4 @@
|
||||
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.Serializable
|
@ -0,0 +1,60 @@
|
||||
@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
|
||||
)
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,153 @@
|
||||
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
|
||||
)
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
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
|
||||
)
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.groupimage
|
||||
|
@ -0,0 +1,2 @@
|
||||
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image
|
||||
|
@ -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.PacketFactory
|
||||
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
|
||||
|
||||
internal object ImageDownPacket : PacketFactory<ImageDownPacket.ImageDownPacketResponse>("LongConn.OffPicDown") {
|
||||
|
@ -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.PacketFactory
|
||||
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") {
|
||||
|
||||
|
@ -1,14 +1,71 @@
|
||||
@file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS")
|
||||
|
||||
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
|
||||
|
||||
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.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.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 object PbPushGroupMsg : PacketFactory<GroupMessage>("OnlinePush.PbPushGroupMsg") {
|
||||
@UseExperimental(ExperimentalStdlibApi::class)
|
||||
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
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
@ -5,6 +5,8 @@ package test
|
||||
import net.mamoe.mirai.utils.cryptor.protoFieldNumber
|
||||
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()))
|
||||
}
|
@ -4,7 +4,7 @@ import java.lang.reflect.Field
|
||||
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
|
||||
return (this::class.simpleName ?: "<UnnamedClass>") + "#" + this::class.hashCode() + " {\n" +
|
||||
this.allFieldsFromSuperClassesMatching { it.name.startsWith("net.mamoe.mirai") }
|
||||
@ -14,6 +14,11 @@ actual fun Any.contentToStringReflectively(prefix: String): String {
|
||||
prefix = newPrefix
|
||||
) {
|
||||
it.isAccessible = true
|
||||
if (filter != null) {
|
||||
kotlin.runCatching {
|
||||
if (!filter(it.name, it.get(this))) return@joinToStringPrefixed ""
|
||||
}
|
||||
}
|
||||
it.name + "=" + kotlin.runCatching {
|
||||
val value = it.get(this)
|
||||
if (value == this) "<this>"
|
||||
|
@ -14,6 +14,5 @@ interface ImageLink {
|
||||
|
||||
suspend fun downloadAsByteArray(): ByteArray = download().readBytes()
|
||||
|
||||
@UseExperimental(KtorExperimentalAPI::class)
|
||||
suspend fun download(): ByteReadPacket = Http.get(original)
|
||||
}
|
@ -242,7 +242,7 @@ object NullMessageChain : MessageChain {
|
||||
|
||||
override fun contains(sub: String): 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 fun containsAll(elements: Collection<Message>): Boolean = error("accessing NullMessageChain")
|
||||
|
@ -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")
|
||||
fun ByteReadPacket.readProtoMap(length: Long = this.remaining): ProtoMap {
|
||||
|
@ -6,19 +6,28 @@ import kotlin.reflect.full.allSuperclasses
|
||||
|
||||
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
|
||||
return (this::class.simpleName ?: "<UnnamedClass>") + "#" + this::class.hashCode() + " {\n" +
|
||||
this.allFieldsFromSuperClassesMatching { it.name.startsWith("net.mamoe.mirai") }
|
||||
.distinctBy { it.name }
|
||||
.filterNot { it.name.contains("$") || it.name == "Companion" || it.isSynthetic || it.name == "serialVersionUID" }
|
||||
.filterNot { it.isEnumConstant }
|
||||
.map {
|
||||
FIELD_TRY_SET_ACCESSIBLE?.invoke(it, true) ?: kotlin.run { it.isAccessible = true }
|
||||
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
|
||||
) {
|
||||
FIELD_TRY_SET_ACCESSIBLE?.invoke(it, true) ?: kotlin.run { it.isAccessible = true }
|
||||
it.name + "=" + kotlin.runCatching {
|
||||
val value = it.get(this)
|
||||
) { (name, value) ->
|
||||
"$name=" + kotlin.runCatching {
|
||||
if (value == this) "<this>"
|
||||
else value.contentToString(newPrefix)
|
||||
}.getOrElse { "<!>" }
|
||||
|
Loading…
Reference in New Issue
Block a user