From b9a3675dad6a3a9b00cc769c5d80602a63ed5087 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 11 Apr 2020 20:15:23 +0800 Subject: [PATCH] Support `Group.quit`, add `BotLeaveEvent.Active` --- .../mirai/qqandroid/contact/GroupImpl.kt | 20 +++++- .../network/protocol/data/jce/GroupMngReq.kt | 42 ++++++++++++ .../protocol/data/jce/RequestPacket.kt | 2 +- .../protocol/packet/OutgoingPacketAndroid.kt | 4 +- .../network/protocol/packet/PacketFactory.kt | 4 +- .../packet/chat/receive/MessageSvc.kt | 6 +- .../packet/chat/receive/OnlinePush.kt | 4 +- .../protocol/packet/list/FriendList.kt | 8 +-- .../protocol/packet/list/ProfileService.kt | 66 +++++++++++++++++++ .../network/protocol/packet/login/StatSvc.kt | 2 +- .../utils/io/serialization/jce/JceDecoder.kt | 6 +- .../qqandroid/utils/io/serialization/utils.kt | 61 +++++++++-------- .../kotlin/net.mamoe.mirai/contact/Group.kt | 6 +- .../net.mamoe.mirai/event/events/BotEvents.kt | 18 ++++- .../kotlin/net/mamoe/mirai/contact/Group.kt | 2 +- 15 files changed, 196 insertions(+), 55 deletions(-) create mode 100644 mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/GroupMngReq.kt create mode 100644 mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/ProfileService.kt diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt index 9686ab8ce..232be9f71 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt @@ -32,6 +32,7 @@ import net.mamoe.mirai.qqandroid.network.highway.HighwayHelper import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc +import net.mamoe.mirai.qqandroid.network.protocol.packet.list.ProfileService import net.mamoe.mirai.qqandroid.utils.estimateLength import net.mamoe.mirai.qqandroid.utils.toIpV4AddressString import net.mamoe.mirai.utils.* @@ -220,10 +221,25 @@ internal class GroupImpl( } } - @MiraiExperimentalAPI override suspend fun quit(): Boolean { check(botPermission != MemberPermission.OWNER) { "An owner cannot quit from a owning group" } - TODO("not implemented") + + if (!bot.groups.delegate.remove(this)) { + return false + } + bot.network.run { + val response: ProfileService.GroupMngReq.GroupMngReqResponse = ProfileService.GroupMngReq( + bot.client, + this@GroupImpl.id + ).sendAndExpect() + check(response.errorCode == 0) { + "Group.quit failed: $response".also { + bot.groups.delegate.addLast(this@GroupImpl) + } + } + } + BotLeaveEvent.Active(this).broadcast() + return true } @OptIn(MiraiExperimentalAPI::class) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/GroupMngReq.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/GroupMngReq.kt new file mode 100644 index 000000000..aedf7f349 --- /dev/null +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/GroupMngReq.kt @@ -0,0 +1,42 @@ +package net.mamoe.mirai.qqandroid.network.protocol.data.jce + +import kotlinx.serialization.Serializable +import net.mamoe.mirai.qqandroid.utils.io.JceStruct +import net.mamoe.mirai.qqandroid.utils.io.serialization.jce.JceId + +@Serializable +internal class GroupMngReqJce( + @JceId(0) val reqtype: Int, + @JceId(1) val uin: Long, + @JceId(2) val vecBody: ByteArray, + @JceId(3) val checkInGroup: Byte? = null, + @JceId(4) val sGroupLocation: String? = "", + @JceId(5) val statOption: Byte? = null, + @JceId(6) val wSourceID: Int? = null, + @JceId(7) val wSourceSubID: Int? = null, + @JceId(8) val isSupportAuthQuestionJoin: Byte? = null, + @JceId(9) val ifGetAuthInfo: Byte? = null, + @JceId(10) val dwDiscussUin: Long? = null, + @JceId(11) val sJoinGroupKey: String? = "", + @JceId(12) val sJoinGroupPicUrl: String? = "", + @JceId(13) val vecJoinGroupRichMsg: ByteArray? = null, + @JceId(14) val sJoinGroupAuth: String? = "", + @JceId(15) val sJoinGroupVerifyToken: String? = "", + @JceId(16) val dwJoinVerifyType: Long? = null +) : JceStruct + +@Serializable +internal class GroupMngRes( + @JceId(0) val reqtype: Int, + @JceId(1) val result: Byte, + @JceId(2) val vecBody: ByteArray, + @JceId(3) val errorString: String = "", + @JceId(4) val errorCode: Short = 0, + @JceId(5) val isInGroup: Byte? = null, + @JceId(6) val sGroupLocation: String? = "", + @JceId(7) val isMemInvite: Byte? = null, + @JceId(8) val sAuthGrpInfo: String? = "", + @JceId(9) val sJoinQuestion: String? = "", + @JceId(10) val sJoinAnswer: String? = "", + @JceId(11) val dwDis2GrpLimitType: Long? = null +) : JceStruct diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/RequestPacket.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/RequestPacket.kt index 4ee203ddf..6be4d5a04 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/RequestPacket.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/RequestPacket.kt @@ -21,7 +21,7 @@ internal class RequestPacket( @JceId(1) val iVersion: Short? = 3, @JceId(2) val cPacketType: Byte = 0, @JceId(3) val iMessageType: Int = 0, - @JceId(4) val iRequestId: Int, + @JceId(4) val iRequestId: Int = 0, @JceId(5) val sServantName: String = "", @JceId(6) val sFuncName: String = "", @JceId(7) val sBuffer: ByteArray = EMPTY_BYTE_ARRAY, diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt index 1ae7d3289..d635a21e0 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt @@ -15,10 +15,10 @@ import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.buildPacket import kotlinx.io.core.writeFully import net.mamoe.mirai.qqandroid.network.QQAndroidClient -import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.qqandroid.utils.io.encryptAndWrite import net.mamoe.mirai.qqandroid.utils.io.writeHex import net.mamoe.mirai.qqandroid.utils.io.writeIntLVPacket +import net.mamoe.mirai.utils.MiraiInternalAPI internal class OutgoingPacket constructor( name: String?, @@ -99,7 +99,7 @@ internal inline fun IncomingPacketFactory<*>.buildResponseUniPacket( } @OptIn(MiraiInternalAPI::class) -internal inline fun BytePacketBuilder.writeUniPacket( +private inline fun BytePacketBuilder.writeUniPacket( commandName: String, unknownData: ByteArray, extraData: ByteReadPacket = BRP_STUB, diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt index d8e34df2b..ca07ab64c 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt @@ -22,6 +22,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.OnlinePush import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList +import net.mamoe.mirai.qqandroid.network.protocol.packet.list.ProfileService import net.mamoe.mirai.qqandroid.network.protocol.packet.login.ConfigPushSvc import net.mamoe.mirai.qqandroid.network.protocol.packet.login.Heartbeat import net.mamoe.mirai.qqandroid.network.protocol.packet.login.StatSvc @@ -149,7 +150,8 @@ internal object KnownPacketFactories { MultiMsg.ApplyUp, NewContact.SystemMsgNewFriend, NewContact.SystemMsgNewGroup, - NewContact.Del + NewContact.Del, + ProfileService.GroupMngReq ) object IncomingFactories : List> by mutableListOf( diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt index 55037f7dc..132da8aa9 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt @@ -49,8 +49,8 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.* import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.GroupInfoImpl import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.NewContact import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList -import net.mamoe.mirai.qqandroid.utils.io.serialization.decodeUniPacket import net.mamoe.mirai.qqandroid.utils.io.serialization.readProtoBuf +import net.mamoe.mirai.qqandroid.utils.io.serialization.readUniPacket import net.mamoe.mirai.qqandroid.utils.io.serialization.toByteArray import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf import net.mamoe.mirai.utils.MiraiExperimentalAPI @@ -67,7 +67,7 @@ internal class MessageSvc { internal object PushNotify : IncomingPacketFactory("MessageSvc.PushNotify") { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): RequestPushNotify { discardExact(4) // don't remove - return decodeUniPacket(RequestPushNotify.serializer()) + return readUniPacket(RequestPushNotify.serializer()) } override suspend fun QQAndroidBot.handle(packet: RequestPushNotify, sequenceId: Int): OutgoingPacket? { @@ -343,7 +343,7 @@ internal class MessageSvc { */ internal object PushForceOffline : OutgoingPacketFactory("MessageSvc.PushForceOffline") { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): BotOfflineEvent.Force { - val struct = this.decodeUniPacket(RequestPushForceOffline.serializer()) + val struct = this.readUniPacket(RequestPushForceOffline.serializer()) return BotOfflineEvent.Force(bot, title = struct.title ?: "", message = struct.tips ?: "") } } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt index 388373db9..77d7f7462 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt @@ -440,7 +440,7 @@ internal class OnlinePush { val uin = vProtobuf.loadAs(SubD4.serializer()).uin val group = bot.getGroupByUinOrNull(uin) ?: bot.getGroupOrNull(uin) return@lambda528 if (group != null && bot.groups.delegate.remove(group)) { - sequenceOf(BotLeaveEvent(group)) + sequenceOf(BotLeaveEvent.Active(group)) } else emptySequence() }, // ModFriendRemark, DelFriend @@ -482,7 +482,7 @@ internal class OnlinePush { @ExperimentalUnsignedTypes @OptIn(ExperimentalStdlibApi::class) override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): Response { - val reqPushMsg = decodeUniPacket(OnlinePushPack.SvcReqPushMsg.serializer(), "req") + val reqPushMsg = readUniPacket(OnlinePushPack.SvcReqPushMsg.serializer(), "req") val packets: Sequence = reqPushMsg.vMsgInfos.deco(bot.client) { msgInfo -> when (msgInfo.shMsgType.toInt()) { diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendList.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendList.kt index 810264d7b..94647b49c 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendList.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendList.kt @@ -19,8 +19,8 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket -import net.mamoe.mirai.qqandroid.utils.io.serialization.decodeUniPacket import net.mamoe.mirai.qqandroid.utils.io.serialization.jceRequestSBuffer +import net.mamoe.mirai.qqandroid.utils.io.serialization.readUniPacket import net.mamoe.mirai.qqandroid.utils.io.serialization.toByteArray import net.mamoe.mirai.qqandroid.utils.io.serialization.writeJceStruct @@ -30,7 +30,7 @@ internal class FriendList { internal object GetTroopMemberList : OutgoingPacketFactory("friendlist.GetTroopMemberListReq") { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response { - val res = this.decodeUniPacket(GetTroopMemberListResp.serializer()) + val res = this.readUniPacket(GetTroopMemberListResp.serializer()) return Response( res.vecTroopMember, res.nextUin @@ -80,7 +80,7 @@ internal class FriendList { internal object GetTroopListSimplify : OutgoingPacketFactory("friendlist.GetTroopListReqV2") { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response { - val res = this.decodeUniPacket(GetTroopListRespV2.serializer()) + val res = this.readUniPacket(GetTroopListRespV2.serializer()) return Response(res.vecTroopList.orEmpty()) } @@ -134,7 +134,7 @@ internal class FriendList { } override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response { - val res = this.decodeUniPacket(GetFriendListResp.serializer()) + val res = this.readUniPacket(GetFriendListResp.serializer()) return Response( res.stSelfInfo, res.totoalFriendCount, diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/ProfileService.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/ProfileService.kt new file mode 100644 index 000000000..b4ec39361 --- /dev/null +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/ProfileService.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2020 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/master/LICENSE + */ + +package net.mamoe.mirai.qqandroid.network.protocol.packet.list + +import kotlinx.io.core.ByteReadPacket +import net.mamoe.mirai.contact.Group +import net.mamoe.mirai.qqandroid.QQAndroidBot +import net.mamoe.mirai.qqandroid.network.Packet +import net.mamoe.mirai.qqandroid.network.QQAndroidClient +import net.mamoe.mirai.qqandroid.network.protocol.data.jce.GroupMngReqJce +import net.mamoe.mirai.qqandroid.network.protocol.data.jce.GroupMngRes +import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPacket +import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket +import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory +import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket +import net.mamoe.mirai.qqandroid.utils.io.serialization.jceRequestSBuffer +import net.mamoe.mirai.qqandroid.utils.io.serialization.readUniPacket +import net.mamoe.mirai.qqandroid.utils.io.serialization.writeJceStruct +import net.mamoe.mirai.qqandroid.utils.toByteArray +import net.mamoe.mirai.utils.SinceMirai + +internal class ProfileService { + + @SinceMirai("0.37.0") + object GroupMngReq : OutgoingPacketFactory("ProfileService.GroupMngReq") { + data class GroupMngReqResponse(val errorCode: Int, val errorMessage: String) : Packet + + override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GroupMngReqResponse { + val resp = readUniPacket(GroupMngRes.serializer()) + return GroupMngReqResponse(resp.errorCode.toInt(), resp.errorString) + } + + operator fun invoke( + client: QQAndroidClient, + groupCode: Long + ): OutgoingPacket = buildOutgoingUniPacket(client) { + writeJceStruct( + RequestPacket.serializer(), + RequestPacket( + sServantName = "KQQ.ProfileService.ProfileServantObj", + sFuncName = "GroupMngReq", + iRequestId = client.nextRequestPacketRequestId(), + sBuffer = jceRequestSBuffer( + "GroupMngReq", + GroupMngReqJce.serializer(), + GroupMngReqJce( + reqtype = 2, + uin = client.uin, + vecBody = client.uin.shl(32).or(Group.calculateGroupUinByGroupCode(groupCode)) + .toByteArray() // 这里可能是 code + ) + ) + ) + ) + } + + + } +} \ No newline at end of file diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/StatSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/StatSvc.kt index 86104647a..3b5ed64f4 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/StatSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/StatSvc.kt @@ -190,7 +190,7 @@ internal class StatSvc { ) : Packet, RuntimeException("dropped by StatSvc.ReqMSFOffline") override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): BotOfflineEvent.Dropped { - val decodeUniPacket = decodeUniPacket(RequestMSFForceOffline.serializer()) + val decodeUniPacket = readUniPacket(RequestMSFForceOffline.serializer()) return BotOfflineEvent.Dropped(bot, MsfOfflineToken(decodeUniPacket.uin, decodeUniPacket.iSeqno, 0)) } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/io/serialization/jce/JceDecoder.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/io/serialization/jce/JceDecoder.kt index 19aeed7c0..e0b80baed 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/io/serialization/jce/JceDecoder.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/io/serialization/jce/JceDecoder.kt @@ -36,8 +36,10 @@ internal class JceDecoder( private fun SerialDescriptor.getJceTagId(index: Int): Int { // higher performance, don't use filterIsInstance - return (getElementAnnotations(index).first { it is JceId } as? JceId)?.id + val annotation = getElementAnnotations(index).firstOrNull { it is JceId } ?: error("missing @JceId for ${getElementName(index)} in ${this.serialName}") + return (annotation as JceId).id + } private val SimpleByteArrayReader: SimpleByteArrayReaderImpl = SimpleByteArrayReaderImpl() @@ -295,7 +297,7 @@ internal class JceDecoder( } override fun decodeTaggedInt(tag: JceTag): Int = - kotlin.runCatching { jce.skipToHeadAndUseIfPossibleOrFail(tag.id) { jce.readJceIntValue(it) } }.getOrElse { + kotlin.runCatching { jce.skipToHeadAndUseIfPossibleOrFail(tag.id) { jce.readJceIntValue(it) } }.getOrElse { throw IllegalStateException("$tag", it) } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/io/serialization/utils.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/io/serialization/utils.kt index 8ddd48880..ad04fd662 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/io/serialization/utils.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/io/serialization/utils.kt @@ -24,15 +24,19 @@ import net.mamoe.mirai.qqandroid.utils.io.ProtoBuf import net.mamoe.mirai.qqandroid.utils.io.readPacketExact import net.mamoe.mirai.qqandroid.utils.io.serialization.jce.Jce import net.mamoe.mirai.qqandroid.utils.read -import net.mamoe.mirai.qqandroid.utils.toReadPacket import net.mamoe.mirai.utils.MiraiInternalAPI import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmName +internal fun ByteArray.loadWithUniPacket( + deserializer: DeserializationStrategy, + name: String? = null +): T = this.read { readUniPacket(deserializer, name) } -internal fun ByteArray.loadAs(deserializer: DeserializationStrategy, c: JceCharset = JceCharset.UTF8): T { - return Jce.byCharSet(c).load(deserializer, this.toReadPacket()) -} +internal fun ByteArray.loadAs( + deserializer: DeserializationStrategy, + c: JceCharset = JceCharset.UTF8 +): T = this.read { Jce.byCharSet(c).load(deserializer, this) } internal fun BytePacketBuilder.writeJceStruct( serializer: SerializationStrategy, @@ -54,7 +58,10 @@ internal fun ByteReadPacket.readJceStruct( /** * 先解析为 [RequestPacket], 即 `UniRequest`, 再按版本解析 map, 再找出指定数据并反序列化 */ -internal fun ByteReadPacket.decodeUniPacket(deserializer: DeserializationStrategy, name: String? = null): T { +internal fun ByteReadPacket.readUniPacket( + deserializer: DeserializationStrategy, + name: String? = null +): T { return decodeUniRequestPacketAndDeserialize(name) { it.read { discardExact(1) @@ -66,7 +73,10 @@ internal fun ByteReadPacket.decodeUniPacket(deserializer: Deseri /** * 先解析为 [RequestPacket], 即 `UniRequest`, 再按版本解析 map, 再找出指定数据并反序列化 */ -internal fun ByteReadPacket.decodeUniPacket(deserializer: DeserializationStrategy, name: String? = null): T { +internal fun ByteReadPacket.readUniPacket( + deserializer: DeserializationStrategy, + name: String? = null +): T { return decodeUniRequestPacketAndDeserialize(name) { it.read { discardExact(1) @@ -74,9 +84,10 @@ internal fun ByteReadPacket.decodeUniPacket(deserializer: Deseria } } } + private fun Map.firstValue(): V = this.entries.first().value -internal fun ByteReadPacket.decodeUniRequestPacketAndDeserialize(name: String? = null, block: (ByteArray) -> R): R { +private fun ByteReadPacket.decodeUniRequestPacketAndDeserialize(name: String? = null, block: (ByteArray) -> R): R { val request = this.readJceStruct(RequestPacket.serializer()) return block(if (name == null) when (request.iVersion?.toInt() ?: 3) { @@ -91,8 +102,10 @@ internal fun ByteReadPacket.decodeUniRequestPacketAndDeserialize(name: Strin }) } -internal fun T.toByteArray(serializer: SerializationStrategy, c: JceCharset = JceCharset.UTF8): ByteArray = - Jce.byCharSet(c).dump(serializer, this) +internal fun T.toByteArray( + serializer: SerializationStrategy, + c: JceCharset = JceCharset.UTF8 +): ByteArray = Jce.byCharSet(c).dump(serializer, this) internal fun BytePacketBuilder.writeProtoBuf(serializer: SerializationStrategy, v: T) { this.writeFully(v.toByteArray(serializer)) @@ -102,20 +115,14 @@ internal fun BytePacketBuilder.writeProtoBuf(serializer: Serializ * dump */ internal fun T.toByteArray(serializer: SerializationStrategy): ByteArray { - return ProtoBufWithNullableSupport.dump( - serializer, - this - ) + return ProtoBufWithNullableSupport.dump(serializer, this) } /** * load */ internal fun ByteArray.loadAs(deserializer: DeserializationStrategy): T { - return ProtoBufWithNullableSupport.load( - deserializer, - this - ) + return ProtoBufWithNullableSupport.load(deserializer, this) } /** @@ -124,24 +131,16 @@ internal fun ByteArray.loadAs(deserializer: DeserializationStrate internal fun ByteReadPacket.readProtoBuf( serializer: DeserializationStrategy, length: Int = this.remaining.toInt() -): T { - return ProtoBufWithNullableSupport.load( - serializer, - this.readBytes(length) - ) -} +): T = ProtoBufWithNullableSupport.load(serializer, this.readBytes(length)) /** * 构造 [RequestPacket] 的 [RequestPacket.sBuffer] */ -internal fun jceRequestSBuffer(name: String, serializer: SerializationStrategy, jceStruct: T): ByteArray { - return jceRequestSBuffer( - name, - serializer, - jceStruct, - JceCharset.UTF8 - ) -} +internal fun jceRequestSBuffer( + name: String, + serializer: SerializationStrategy, + jceStruct: T +): ByteArray = jceRequestSBuffer(name, serializer, jceStruct, JceCharset.UTF8) internal fun jceRequestSBuffer( name: String, diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt index fae99f800..872e21bac 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt @@ -115,10 +115,12 @@ expect abstract class Group() : Contact, CoroutineScope { /** - * 让机器人退出这个群. 机器人必须为非群主才能退出. 否则将会失败 + * 让机器人退出这个群. + * @throws IllegalStateException 当机器人为群主时 + * @return 退出成功时 true; 已经退出时 false */ @JvmSynthetic - @MiraiExperimentalAPI("还未支持") + @SinceMirai("0.37.0") abstract suspend fun quit(): Boolean /** diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt index 8039c7cd2..05ecb26ae 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt @@ -213,9 +213,21 @@ sealed class ImageUploadEvent : BotEvent, BotActiveEvent, AbstractCancellableEve * 机器人被踢出群或在其他客户端主动退出一个群. 在事件广播前 [Bot.groups] 就已删除这个群. */ @SinceMirai("0.36.0") -data class BotLeaveEvent( - val group: Group -) : BotEvent, Packet { +sealed class BotLeaveEvent : BotEvent, Packet { + abstract val group: Group + + /** + * 机器人主动退出一个群. + */ + @SinceMirai("0.37.0") + data class Active(override val group: Group) : BotLeaveEvent() + + /** + * 机器人被管理员或群主踢出群. 暂不支持获取操作人 + */ + @SinceMirai("0.37.0") + data class Kick(override val group: Group) : BotLeaveEvent() + override val bot: Bot get() = group.bot } diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt index a194a20ab..1cdc3f780 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt @@ -116,7 +116,7 @@ actual abstract class Group : Contact(), CoroutineScope { /** * 让机器人退出这个群. 机器人必须为非群主才能退出. 否则将会失败 */ - @MiraiExperimentalAPI("还未支持") + @SinceMirai("0.37.0") actual abstract suspend fun quit(): Boolean /**