mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-29 17:20:11 +08:00
Support Group.quit
, add BotLeaveEvent.Active
This commit is contained in:
parent
0f86ad0240
commit
b9a3675dad
@ -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.TroopManagement
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
|
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.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.estimateLength
|
||||||
import net.mamoe.mirai.qqandroid.utils.toIpV4AddressString
|
import net.mamoe.mirai.qqandroid.utils.toIpV4AddressString
|
||||||
import net.mamoe.mirai.utils.*
|
import net.mamoe.mirai.utils.*
|
||||||
@ -220,10 +221,25 @@ internal class GroupImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@MiraiExperimentalAPI
|
|
||||||
override suspend fun quit(): Boolean {
|
override suspend fun quit(): Boolean {
|
||||||
check(botPermission != MemberPermission.OWNER) { "An owner cannot quit from a owning group" }
|
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)
|
@OptIn(MiraiExperimentalAPI::class)
|
||||||
|
@ -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
|
@ -21,7 +21,7 @@ internal class RequestPacket(
|
|||||||
@JceId(1) val iVersion: Short? = 3,
|
@JceId(1) val iVersion: Short? = 3,
|
||||||
@JceId(2) val cPacketType: Byte = 0,
|
@JceId(2) val cPacketType: Byte = 0,
|
||||||
@JceId(3) val iMessageType: Int = 0,
|
@JceId(3) val iMessageType: Int = 0,
|
||||||
@JceId(4) val iRequestId: Int,
|
@JceId(4) val iRequestId: Int = 0,
|
||||||
@JceId(5) val sServantName: String = "",
|
@JceId(5) val sServantName: String = "",
|
||||||
@JceId(6) val sFuncName: String = "",
|
@JceId(6) val sFuncName: String = "",
|
||||||
@JceId(7) val sBuffer: ByteArray = EMPTY_BYTE_ARRAY,
|
@JceId(7) val sBuffer: ByteArray = EMPTY_BYTE_ARRAY,
|
||||||
|
@ -15,10 +15,10 @@ import kotlinx.io.core.ByteReadPacket
|
|||||||
import kotlinx.io.core.buildPacket
|
import kotlinx.io.core.buildPacket
|
||||||
import kotlinx.io.core.writeFully
|
import kotlinx.io.core.writeFully
|
||||||
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
|
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.encryptAndWrite
|
||||||
import net.mamoe.mirai.qqandroid.utils.io.writeHex
|
import net.mamoe.mirai.qqandroid.utils.io.writeHex
|
||||||
import net.mamoe.mirai.qqandroid.utils.io.writeIntLVPacket
|
import net.mamoe.mirai.qqandroid.utils.io.writeIntLVPacket
|
||||||
|
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||||
|
|
||||||
internal class OutgoingPacket constructor(
|
internal class OutgoingPacket constructor(
|
||||||
name: String?,
|
name: String?,
|
||||||
@ -99,7 +99,7 @@ internal inline fun IncomingPacketFactory<*>.buildResponseUniPacket(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(MiraiInternalAPI::class)
|
@OptIn(MiraiInternalAPI::class)
|
||||||
internal inline fun BytePacketBuilder.writeUniPacket(
|
private inline fun BytePacketBuilder.writeUniPacket(
|
||||||
commandName: String,
|
commandName: String,
|
||||||
unknownData: ByteArray,
|
unknownData: ByteArray,
|
||||||
extraData: ByteReadPacket = BRP_STUB,
|
extraData: ByteReadPacket = BRP_STUB,
|
||||||
|
@ -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.MessageSvc
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.OnlinePush
|
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.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.ConfigPushSvc
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.Heartbeat
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.Heartbeat
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.StatSvc
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.StatSvc
|
||||||
@ -149,7 +150,8 @@ internal object KnownPacketFactories {
|
|||||||
MultiMsg.ApplyUp,
|
MultiMsg.ApplyUp,
|
||||||
NewContact.SystemMsgNewFriend,
|
NewContact.SystemMsgNewFriend,
|
||||||
NewContact.SystemMsgNewGroup,
|
NewContact.SystemMsgNewGroup,
|
||||||
NewContact.Del
|
NewContact.Del,
|
||||||
|
ProfileService.GroupMngReq
|
||||||
)
|
)
|
||||||
|
|
||||||
object IncomingFactories : List<IncomingPacketFactory<*>> by mutableListOf(
|
object IncomingFactories : List<IncomingPacketFactory<*>> by mutableListOf(
|
||||||
|
@ -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.GroupInfoImpl
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.NewContact
|
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.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.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.toByteArray
|
||||||
import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf
|
import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf
|
||||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||||
@ -67,7 +67,7 @@ internal class MessageSvc {
|
|||||||
internal object PushNotify : IncomingPacketFactory<RequestPushNotify>("MessageSvc.PushNotify") {
|
internal object PushNotify : IncomingPacketFactory<RequestPushNotify>("MessageSvc.PushNotify") {
|
||||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): RequestPushNotify {
|
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): RequestPushNotify {
|
||||||
discardExact(4) // don't remove
|
discardExact(4) // don't remove
|
||||||
return decodeUniPacket(RequestPushNotify.serializer())
|
return readUniPacket(RequestPushNotify.serializer())
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun QQAndroidBot.handle(packet: RequestPushNotify, sequenceId: Int): OutgoingPacket? {
|
override suspend fun QQAndroidBot.handle(packet: RequestPushNotify, sequenceId: Int): OutgoingPacket? {
|
||||||
@ -343,7 +343,7 @@ internal class MessageSvc {
|
|||||||
*/
|
*/
|
||||||
internal object PushForceOffline : OutgoingPacketFactory<BotOfflineEvent.Force>("MessageSvc.PushForceOffline") {
|
internal object PushForceOffline : OutgoingPacketFactory<BotOfflineEvent.Force>("MessageSvc.PushForceOffline") {
|
||||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): BotOfflineEvent.Force {
|
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 ?: "")
|
return BotOfflineEvent.Force(bot, title = struct.title ?: "", message = struct.tips ?: "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -440,7 +440,7 @@ internal class OnlinePush {
|
|||||||
val uin = vProtobuf.loadAs(SubD4.serializer()).uin
|
val uin = vProtobuf.loadAs(SubD4.serializer()).uin
|
||||||
val group = bot.getGroupByUinOrNull(uin) ?: bot.getGroupOrNull(uin)
|
val group = bot.getGroupByUinOrNull(uin) ?: bot.getGroupOrNull(uin)
|
||||||
return@lambda528 if (group != null && bot.groups.delegate.remove(group)) {
|
return@lambda528 if (group != null && bot.groups.delegate.remove(group)) {
|
||||||
sequenceOf(BotLeaveEvent(group))
|
sequenceOf(BotLeaveEvent.Active(group))
|
||||||
} else emptySequence()
|
} else emptySequence()
|
||||||
},
|
},
|
||||||
// ModFriendRemark, DelFriend
|
// ModFriendRemark, DelFriend
|
||||||
@ -482,7 +482,7 @@ internal class OnlinePush {
|
|||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): Response {
|
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<Packet> = reqPushMsg.vMsgInfos.deco(bot.client) { msgInfo ->
|
val packets: Sequence<Packet> = reqPushMsg.vMsgInfos.deco(bot.client) { msgInfo ->
|
||||||
when (msgInfo.shMsgType.toInt()) {
|
when (msgInfo.shMsgType.toInt()) {
|
||||||
|
@ -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.OutgoingPacket
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
|
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
|
||||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
|
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.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.toByteArray
|
||||||
import net.mamoe.mirai.qqandroid.utils.io.serialization.writeJceStruct
|
import net.mamoe.mirai.qqandroid.utils.io.serialization.writeJceStruct
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ internal class FriendList {
|
|||||||
internal object GetTroopMemberList :
|
internal object GetTroopMemberList :
|
||||||
OutgoingPacketFactory<GetTroopMemberList.Response>("friendlist.GetTroopMemberListReq") {
|
OutgoingPacketFactory<GetTroopMemberList.Response>("friendlist.GetTroopMemberListReq") {
|
||||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||||
val res = this.decodeUniPacket(GetTroopMemberListResp.serializer())
|
val res = this.readUniPacket(GetTroopMemberListResp.serializer())
|
||||||
return Response(
|
return Response(
|
||||||
res.vecTroopMember,
|
res.vecTroopMember,
|
||||||
res.nextUin
|
res.nextUin
|
||||||
@ -80,7 +80,7 @@ internal class FriendList {
|
|||||||
internal object GetTroopListSimplify :
|
internal object GetTroopListSimplify :
|
||||||
OutgoingPacketFactory<GetTroopListSimplify.Response>("friendlist.GetTroopListReqV2") {
|
OutgoingPacketFactory<GetTroopListSimplify.Response>("friendlist.GetTroopListReqV2") {
|
||||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
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())
|
return Response(res.vecTroopList.orEmpty())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ internal class FriendList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||||
val res = this.decodeUniPacket(GetFriendListResp.serializer())
|
val res = this.readUniPacket(GetFriendListResp.serializer())
|
||||||
return Response(
|
return Response(
|
||||||
res.stSelfInfo,
|
res.stSelfInfo,
|
||||||
res.totoalFriendCount,
|
res.totoalFriendCount,
|
||||||
|
@ -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<GroupMngReq.GroupMngReqResponse>("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
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -190,7 +190,7 @@ internal class StatSvc {
|
|||||||
) : Packet, RuntimeException("dropped by StatSvc.ReqMSFOffline")
|
) : Packet, RuntimeException("dropped by StatSvc.ReqMSFOffline")
|
||||||
|
|
||||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): BotOfflineEvent.Dropped {
|
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))
|
return BotOfflineEvent.Dropped(bot, MsfOfflineToken(decodeUniPacket.uin, decodeUniPacket.iSeqno, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,8 +36,10 @@ internal class JceDecoder(
|
|||||||
|
|
||||||
private fun SerialDescriptor.getJceTagId(index: Int): Int {
|
private fun SerialDescriptor.getJceTagId(index: Int): Int {
|
||||||
// higher performance, don't use filterIsInstance
|
// 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}")
|
?: error("missing @JceId for ${getElementName(index)} in ${this.serialName}")
|
||||||
|
return (annotation as JceId).id
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val SimpleByteArrayReader: SimpleByteArrayReaderImpl = SimpleByteArrayReaderImpl()
|
private val SimpleByteArrayReader: SimpleByteArrayReaderImpl = SimpleByteArrayReaderImpl()
|
||||||
|
@ -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.readPacketExact
|
||||||
import net.mamoe.mirai.qqandroid.utils.io.serialization.jce.Jce
|
import net.mamoe.mirai.qqandroid.utils.io.serialization.jce.Jce
|
||||||
import net.mamoe.mirai.qqandroid.utils.read
|
import net.mamoe.mirai.qqandroid.utils.read
|
||||||
import net.mamoe.mirai.qqandroid.utils.toReadPacket
|
|
||||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||||
import kotlin.jvm.JvmMultifileClass
|
import kotlin.jvm.JvmMultifileClass
|
||||||
import kotlin.jvm.JvmName
|
import kotlin.jvm.JvmName
|
||||||
|
|
||||||
|
internal fun <T : JceStruct> ByteArray.loadWithUniPacket(
|
||||||
|
deserializer: DeserializationStrategy<T>,
|
||||||
|
name: String? = null
|
||||||
|
): T = this.read { readUniPacket(deserializer, name) }
|
||||||
|
|
||||||
internal fun <T : JceStruct> ByteArray.loadAs(deserializer: DeserializationStrategy<T>, c: JceCharset = JceCharset.UTF8): T {
|
internal fun <T : JceStruct> ByteArray.loadAs(
|
||||||
return Jce.byCharSet(c).load(deserializer, this.toReadPacket())
|
deserializer: DeserializationStrategy<T>,
|
||||||
}
|
c: JceCharset = JceCharset.UTF8
|
||||||
|
): T = this.read { Jce.byCharSet(c).load(deserializer, this) }
|
||||||
|
|
||||||
internal fun <T : JceStruct> BytePacketBuilder.writeJceStruct(
|
internal fun <T : JceStruct> BytePacketBuilder.writeJceStruct(
|
||||||
serializer: SerializationStrategy<T>,
|
serializer: SerializationStrategy<T>,
|
||||||
@ -54,7 +58,10 @@ internal fun <T : JceStruct> ByteReadPacket.readJceStruct(
|
|||||||
/**
|
/**
|
||||||
* 先解析为 [RequestPacket], 即 `UniRequest`, 再按版本解析 map, 再找出指定数据并反序列化
|
* 先解析为 [RequestPacket], 即 `UniRequest`, 再按版本解析 map, 再找出指定数据并反序列化
|
||||||
*/
|
*/
|
||||||
internal fun <T : JceStruct> ByteReadPacket.decodeUniPacket(deserializer: DeserializationStrategy<T>, name: String? = null): T {
|
internal fun <T : JceStruct> ByteReadPacket.readUniPacket(
|
||||||
|
deserializer: DeserializationStrategy<T>,
|
||||||
|
name: String? = null
|
||||||
|
): T {
|
||||||
return decodeUniRequestPacketAndDeserialize(name) {
|
return decodeUniRequestPacketAndDeserialize(name) {
|
||||||
it.read {
|
it.read {
|
||||||
discardExact(1)
|
discardExact(1)
|
||||||
@ -66,7 +73,10 @@ internal fun <T : JceStruct> ByteReadPacket.decodeUniPacket(deserializer: Deseri
|
|||||||
/**
|
/**
|
||||||
* 先解析为 [RequestPacket], 即 `UniRequest`, 再按版本解析 map, 再找出指定数据并反序列化
|
* 先解析为 [RequestPacket], 即 `UniRequest`, 再按版本解析 map, 再找出指定数据并反序列化
|
||||||
*/
|
*/
|
||||||
internal fun <T : ProtoBuf> ByteReadPacket.decodeUniPacket(deserializer: DeserializationStrategy<T>, name: String? = null): T {
|
internal fun <T : ProtoBuf> ByteReadPacket.readUniPacket(
|
||||||
|
deserializer: DeserializationStrategy<T>,
|
||||||
|
name: String? = null
|
||||||
|
): T {
|
||||||
return decodeUniRequestPacketAndDeserialize(name) {
|
return decodeUniRequestPacketAndDeserialize(name) {
|
||||||
it.read {
|
it.read {
|
||||||
discardExact(1)
|
discardExact(1)
|
||||||
@ -74,9 +84,10 @@ internal fun <T : ProtoBuf> ByteReadPacket.decodeUniPacket(deserializer: Deseria
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <K, V> Map<K, V>.firstValue(): V = this.entries.first().value
|
private fun <K, V> Map<K, V>.firstValue(): V = this.entries.first().value
|
||||||
|
|
||||||
internal fun <R> ByteReadPacket.decodeUniRequestPacketAndDeserialize(name: String? = null, block: (ByteArray) -> R): R {
|
private fun <R> ByteReadPacket.decodeUniRequestPacketAndDeserialize(name: String? = null, block: (ByteArray) -> R): R {
|
||||||
val request = this.readJceStruct(RequestPacket.serializer())
|
val request = this.readJceStruct(RequestPacket.serializer())
|
||||||
|
|
||||||
return block(if (name == null) when (request.iVersion?.toInt() ?: 3) {
|
return block(if (name == null) when (request.iVersion?.toInt() ?: 3) {
|
||||||
@ -91,8 +102,10 @@ internal fun <R> ByteReadPacket.decodeUniRequestPacketAndDeserialize(name: Strin
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun <T : JceStruct> T.toByteArray(serializer: SerializationStrategy<T>, c: JceCharset = JceCharset.UTF8): ByteArray =
|
internal fun <T : JceStruct> T.toByteArray(
|
||||||
Jce.byCharSet(c).dump(serializer, this)
|
serializer: SerializationStrategy<T>,
|
||||||
|
c: JceCharset = JceCharset.UTF8
|
||||||
|
): ByteArray = Jce.byCharSet(c).dump(serializer, this)
|
||||||
|
|
||||||
internal fun <T : ProtoBuf> BytePacketBuilder.writeProtoBuf(serializer: SerializationStrategy<T>, v: T) {
|
internal fun <T : ProtoBuf> BytePacketBuilder.writeProtoBuf(serializer: SerializationStrategy<T>, v: T) {
|
||||||
this.writeFully(v.toByteArray(serializer))
|
this.writeFully(v.toByteArray(serializer))
|
||||||
@ -102,20 +115,14 @@ internal fun <T : ProtoBuf> BytePacketBuilder.writeProtoBuf(serializer: Serializ
|
|||||||
* dump
|
* dump
|
||||||
*/
|
*/
|
||||||
internal fun <T : ProtoBuf> T.toByteArray(serializer: SerializationStrategy<T>): ByteArray {
|
internal fun <T : ProtoBuf> T.toByteArray(serializer: SerializationStrategy<T>): ByteArray {
|
||||||
return ProtoBufWithNullableSupport.dump(
|
return ProtoBufWithNullableSupport.dump(serializer, this)
|
||||||
serializer,
|
|
||||||
this
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* load
|
* load
|
||||||
*/
|
*/
|
||||||
internal fun <T : ProtoBuf> ByteArray.loadAs(deserializer: DeserializationStrategy<T>): T {
|
internal fun <T : ProtoBuf> ByteArray.loadAs(deserializer: DeserializationStrategy<T>): T {
|
||||||
return ProtoBufWithNullableSupport.load(
|
return ProtoBufWithNullableSupport.load(deserializer, this)
|
||||||
deserializer,
|
|
||||||
this
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -124,24 +131,16 @@ internal fun <T : ProtoBuf> ByteArray.loadAs(deserializer: DeserializationStrate
|
|||||||
internal fun <T : ProtoBuf> ByteReadPacket.readProtoBuf(
|
internal fun <T : ProtoBuf> ByteReadPacket.readProtoBuf(
|
||||||
serializer: DeserializationStrategy<T>,
|
serializer: DeserializationStrategy<T>,
|
||||||
length: Int = this.remaining.toInt()
|
length: Int = this.remaining.toInt()
|
||||||
): T {
|
): T = ProtoBufWithNullableSupport.load(serializer, this.readBytes(length))
|
||||||
return ProtoBufWithNullableSupport.load(
|
|
||||||
serializer,
|
|
||||||
this.readBytes(length)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造 [RequestPacket] 的 [RequestPacket.sBuffer]
|
* 构造 [RequestPacket] 的 [RequestPacket.sBuffer]
|
||||||
*/
|
*/
|
||||||
internal fun <T : JceStruct> jceRequestSBuffer(name: String, serializer: SerializationStrategy<T>, jceStruct: T): ByteArray {
|
internal fun <T : JceStruct> jceRequestSBuffer(
|
||||||
return jceRequestSBuffer(
|
name: String,
|
||||||
name,
|
serializer: SerializationStrategy<T>,
|
||||||
serializer,
|
jceStruct: T
|
||||||
jceStruct,
|
): ByteArray = jceRequestSBuffer(name, serializer, jceStruct, JceCharset.UTF8)
|
||||||
JceCharset.UTF8
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun <T : JceStruct> jceRequestSBuffer(
|
internal fun <T : JceStruct> jceRequestSBuffer(
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -115,10 +115,12 @@ expect abstract class Group() : Contact, CoroutineScope {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 让机器人退出这个群. 机器人必须为非群主才能退出. 否则将会失败
|
* 让机器人退出这个群.
|
||||||
|
* @throws IllegalStateException 当机器人为群主时
|
||||||
|
* @return 退出成功时 true; 已经退出时 false
|
||||||
*/
|
*/
|
||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
@MiraiExperimentalAPI("还未支持")
|
@SinceMirai("0.37.0")
|
||||||
abstract suspend fun quit(): Boolean
|
abstract suspend fun quit(): Boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -213,9 +213,21 @@ sealed class ImageUploadEvent : BotEvent, BotActiveEvent, AbstractCancellableEve
|
|||||||
* 机器人被踢出群或在其他客户端主动退出一个群. 在事件广播前 [Bot.groups] 就已删除这个群.
|
* 机器人被踢出群或在其他客户端主动退出一个群. 在事件广播前 [Bot.groups] 就已删除这个群.
|
||||||
*/
|
*/
|
||||||
@SinceMirai("0.36.0")
|
@SinceMirai("0.36.0")
|
||||||
data class BotLeaveEvent(
|
sealed class BotLeaveEvent : BotEvent, Packet {
|
||||||
val group: Group
|
abstract val group: Group
|
||||||
) : BotEvent, Packet {
|
|
||||||
|
/**
|
||||||
|
* 机器人主动退出一个群.
|
||||||
|
*/
|
||||||
|
@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
|
override val bot: Bot get() = group.bot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ actual abstract class Group : Contact(), CoroutineScope {
|
|||||||
/**
|
/**
|
||||||
* 让机器人退出这个群. 机器人必须为非群主才能退出. 否则将会失败
|
* 让机器人退出这个群. 机器人必须为非群主才能退出. 否则将会失败
|
||||||
*/
|
*/
|
||||||
@MiraiExperimentalAPI("还未支持")
|
@SinceMirai("0.37.0")
|
||||||
actual abstract suspend fun quit(): Boolean
|
actual abstract suspend fun quit(): Boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user