Переглянути джерело

Support handle bot invited into a group, close #259

ryoii 5 роки тому
батько
коміт
bb3944d5ae

+ 27 - 0
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt

@@ -28,6 +28,7 @@ import net.mamoe.mirai.*
 import net.mamoe.mirai.contact.*
 import net.mamoe.mirai.data.*
 import net.mamoe.mirai.event.broadcast
+import net.mamoe.mirai.event.events.BotInvitedJoinGroupRequestEvent
 import net.mamoe.mirai.event.events.MemberJoinRequestEvent
 import net.mamoe.mirai.event.events.MessageRecallEvent
 import net.mamoe.mirai.event.events.NewFriendRequestEvent
@@ -56,6 +57,7 @@ import kotlin.contracts.ExperimentalContracts
 import kotlin.contracts.contract
 import kotlin.coroutines.CoroutineContext
 import kotlin.jvm.JvmSynthetic
+import kotlin.jvm.Synchronized
 import kotlin.math.absoluteValue
 import kotlin.random.Random
 import net.mamoe.mirai.qqandroid.network.protocol.data.jce.FriendInfo as JceFriendInfo
@@ -205,6 +207,31 @@ internal class QQAndroidBot constructor(
             ).sendWithoutExpect()
         }
     }
+
+    override suspend fun acceptInvitedJoinGroupRequest(event: BotInvitedJoinGroupRequestEvent)
+        = solveInvitedJoinGroupRequest(event, accept = true)
+
+    override suspend fun ignoreInvitedJoinGroupRequest(event: BotInvitedJoinGroupRequestEvent)
+        = solveInvitedJoinGroupRequest(event, accept = false)
+
+
+    private suspend fun solveInvitedJoinGroupRequest(event: BotInvitedJoinGroupRequestEvent, accept: Boolean) {
+        check(event.responded.compareAndSet(false, true)) {
+            "the request $this has already been responded"
+        }
+
+        check(!groups.contains(event.groupId)) {
+            "the request $this is outdated: Bot has been already in the group."
+        }
+
+        network.run {
+            NewContact.SystemMsgNewGroup.Action(
+                bot.client,
+                event,
+                accept = accept
+            ).sendWithoutExpect()
+        }
+    }
 }
 
 @OptIn(MiraiInternalAPI::class, MiraiExperimentalAPI::class)

+ 51 - 14
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/NewContact.kt

@@ -2,12 +2,12 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat
 
 import kotlinx.io.core.ByteReadPacket
 import kotlinx.io.core.readBytes
+import net.mamoe.mirai.event.events.BotInvitedJoinGroupRequestEvent
 import net.mamoe.mirai.event.events.MemberJoinRequestEvent
 import net.mamoe.mirai.event.events.NewFriendRequestEvent
 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.proto.MsgComm
-import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc
 import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Structmsg
 import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
 import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
@@ -93,7 +93,7 @@ internal class NewContact {
 
 
     internal object SystemMsgNewGroup :
-        OutgoingPacketFactory<MemberJoinRequestEvent?>("ProfileService.Pb.ReqSystemMsgNew.Group") {
+        OutgoingPacketFactory<Packet?>("ProfileService.Pb.ReqSystemMsgNew.Group") {
 
         operator fun invoke(client: QQAndroidClient) = buildOutgoingUniPacket(client) {
             writeProtoBuf(
@@ -129,22 +129,35 @@ internal class NewContact {
         }
 
 
-        override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): MemberJoinRequestEvent? {
+        override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Packet? {
             readBytes().loadAs(Structmsg.RspSystemMsgNew.serializer()).run {
                 val struct = groupmsgs?.firstOrNull()
 
                 return if (struct == null) null else {
                     struct.msg?.run {
-                        MemberJoinRequestEvent(
-                            bot,
-                            struct.msgSeq,
-                            msgAdditional,
-                            struct.reqUin,
-                            groupCode,
-                            groupName,
-                            reqUinNick
-                        )
-                    }
+                        if (c2cInviteJoinGroupFlag == 1) {
+                            // 被邀请入群
+                            BotInvitedJoinGroupRequestEvent(
+                                bot,
+                                struct.msgSeq,
+                                actionUin,
+                                groupCode,
+                                groupName,
+                                actionUinNick
+                            )
+                        } else {
+                            // 成员申请入群
+                            MemberJoinRequestEvent(
+                                bot,
+                                struct.msgSeq,
+                                msgAdditional,
+                                struct.reqUin,
+                                groupCode,
+                                groupName,
+                                reqUinNick
+                            )
+                        }
+                    } as Packet // 没有 as Packet 垃圾 kotlin 会把类型推断为Any
                 }
             }
         }
@@ -183,6 +196,30 @@ internal class NewContact {
                     )
                 }
 
+            operator fun invoke(
+                client: QQAndroidClient,
+                event: BotInvitedJoinGroupRequestEvent,
+                accept: Boolean
+            ) =
+                buildOutgoingUniPacket(client) {
+                    writeProtoBuf(
+                        Structmsg.ReqSystemMsgAction.serializer(),
+                        Structmsg.ReqSystemMsgAction(
+                            actionInfo = Structmsg.SystemMsgActionInfo(
+                                type = if (accept) 11 else 12,
+                                groupCode = event.groupId
+                            ),
+                            groupMsgType = 2,
+                            language = 1000,
+                            msgSeq = event.eventId,
+                            reqUin = event.invitorId,
+                            srcId = 3,
+                            subSrcId = 10016,
+                            subType = 1
+                        )
+                    )
+                }
+
             override suspend fun ByteReadPacket.decode(bot: QQAndroidBot) = null
         }
     }

+ 1 - 1
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt

@@ -307,7 +307,7 @@ internal class MessageSvc {
                                 } else return@mapNotNull null
                             }
                         }
-                        84 -> { // 请求入群验证
+                        84, 87 -> { // 请求入群验证 和 被要求入群
                             bot.network.run {
                                 NewContact.SystemMsgNewGroup(bot.client).sendWithoutExpect()
                             }

+ 19 - 0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt

@@ -19,6 +19,7 @@ import kotlinx.coroutines.io.ByteReadChannel
 import kotlinx.coroutines.launch
 import net.mamoe.mirai.contact.*
 import net.mamoe.mirai.data.AddFriendResult
+import net.mamoe.mirai.event.events.BotInvitedJoinGroupRequestEvent
 import net.mamoe.mirai.event.events.MemberJoinRequestEvent
 import net.mamoe.mirai.event.events.NewFriendRequestEvent
 import net.mamoe.mirai.message.MessageReceipt
@@ -271,6 +272,24 @@ abstract class Bot : CoroutineScope, LowLevelBotAPIAccessor, BotJavaFriendlyAPI(
     @JvmSynthetic
     abstract suspend fun ignoreMemberJoinRequest(event: MemberJoinRequestEvent, blackList: Boolean = false)
 
+    /**
+     * 接收邀请入群(需管理员权限)
+     *
+     * @param event 邀请入群的事件对象
+     */
+    @SinceMirai("0.40.0")
+    @JvmSynthetic
+    abstract suspend fun acceptInvitedJoinGroupRequest(event: BotInvitedJoinGroupRequestEvent)
+
+    /**
+     * 忽略邀请入群(需管理员权限)
+     *
+     * @param event 邀请入群的事件对象
+     */
+    @JvmSynthetic
+    @SinceMirai("0.40.0")
+    abstract suspend fun ignoreInvitedJoinGroupRequest(event: BotInvitedJoinGroupRequestEvent)
+
     // endregion
 
     /**

+ 38 - 0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt

@@ -711,4 +711,42 @@ data class MemberJoinRequestEvent(
         runBlocking { bot.ignoreMemberJoinRequest(this@MemberJoinRequestEvent, blackList) }
 }
 
+@SinceMirai("0.40.0")
+data class BotInvitedJoinGroupRequestEvent(
+    override val bot: Bot,
+    /**
+     * 事件唯一识别号
+     */
+    val eventId: Long,
+    /**
+     * 邀请入群的账号的 id
+     */
+    val invitorId: Long,
+    val groupId: Long,
+    val groupName: String,
+    /**
+     * 邀请人昵称
+     */
+    val invitorNick: String
+) : BotEvent, Packet {
+    val invitor: Friend = this.bot.getFriend(invitorId)
+
+    @JvmField
+    internal val responded: MiraiAtomicBoolean = MiraiAtomicBoolean(false)
+
+    @JvmSynthetic
+    suspend fun accept() = bot.acceptInvitedJoinGroupRequest(this)
+
+    @JvmSynthetic
+    suspend fun ignore() = bot
+
+    @JavaFriendlyAPI
+    @JvmName("accept")
+    fun __acceptBlockingForJava__() = runBlocking { bot.acceptInvitedJoinGroupRequest(this@BotInvitedJoinGroupRequestEvent) }
+
+    @JavaFriendlyAPI
+    @JvmName("ignore")
+    fun __ignoreBlockingForJava__() = runBlocking { bot.ignoreInvitedJoinGroupRequest(this@BotInvitedJoinGroupRequestEvent) }
+}
+
 // endregion 好友、群认证