Commit ab464388 authored by Him188's avatar Him188

Support BotJoinGroupEvent.Invite, close #344

parent e8345c38
...@@ -450,9 +450,10 @@ internal fun List<ImMsgBody.Elem>.joinToMessageChain(groupIdOrZero: Long, bot: B ...@@ -450,9 +450,10 @@ internal fun List<ImMsgBody.Elem>.joinToMessageChain(groupIdOrZero: Long, bot: B
internal fun contextualBugReportException( internal fun contextualBugReportException(
context: String, context: String,
forDebug: String, forDebug: String,
e: Throwable? = null e: Throwable? = null,
additional: String = ""
): IllegalStateException { ): IllegalStateException {
return IllegalStateException("在 $context 时遇到了意料之中的问题. 请完整复制此日志提交给 mirai. 调试信息: $forDebug", e) return IllegalStateException("在 $context 时遇到了意料之中的问题. 请完整复制此日志提交给 mirai. $additional 调试信息: $forDebug", e)
} }
@OptIn(ExperimentalContracts::class) @OptIn(ExperimentalContracts::class)
......
...@@ -14,10 +14,7 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat ...@@ -14,10 +14,7 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat
import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.readBytes import kotlinx.io.core.readBytes
import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.event.events.BotInvitedJoinGroupRequestEvent import net.mamoe.mirai.event.events.*
import net.mamoe.mirai.event.events.BotLeaveEvent
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.QQAndroidBot
import net.mamoe.mirai.qqandroid.message.contextualBugReportException import net.mamoe.mirai.qqandroid.message.contextualBugReportException
import net.mamoe.mirai.qqandroid.network.Packet import net.mamoe.mirai.qqandroid.network.Packet
...@@ -25,6 +22,7 @@ import net.mamoe.mirai.qqandroid.network.QQAndroidClient ...@@ -25,6 +22,7 @@ import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Structmsg 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.OutgoingPacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.getNewGroup
import net.mamoe.mirai.qqandroid.utils._miraiContentToString import net.mamoe.mirai.qqandroid.utils._miraiContentToString
import net.mamoe.mirai.qqandroid.utils.io.serialization.loadAs import net.mamoe.mirai.qqandroid.utils.io.serialization.loadAs
import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf
...@@ -169,10 +167,19 @@ internal class NewContact { ...@@ -169,10 +167,19 @@ internal class NewContact {
} }
else -> throw contextualBugReportException( else -> throw contextualBugReportException(
"parse SystemMsgNewGroup, subType=1", "parse SystemMsgNewGroup, subType=1",
forDebug = this._miraiContentToString() this._miraiContentToString(),
additional = "并尽量描述此时机器人是否正被邀请加入群, 或者是有有新群员加入此群"
) )
} }
} }
2 -> {
// 被邀请入群, 自动同意
val group = bot.getNewGroup(groupCode) ?: return null
val invitor = group[actionUin]
BotJoinGroupEvent.Invite(reqUinNick, invitor)
}
5 -> { 5 -> {
val group = bot.getGroup(groupCode) val group = bot.getGroup(groupCode)
val operator = group[actionUin] val operator = group[actionUin]
...@@ -180,7 +187,8 @@ internal class NewContact { ...@@ -180,7 +187,8 @@ internal class NewContact {
} }
else -> throw contextualBugReportException( else -> throw contextualBugReportException(
"parse SystemMsgNewGroup", "parse SystemMsgNewGroup",
forDebug = this._miraiContentToString() forDebug = this._miraiContentToString(),
additional = "并尽量描述此时机器人是否正被邀请加入群, 或者是有有新群员加入此群"
) )
} }
} as Packet // 没有 as Packet 垃圾 kotlin 会把类型推断为Any } as Packet // 没有 as Packet 垃圾 kotlin 会把类型推断为Any
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE * https://github.com/mamoe/mirai/blob/master/LICENSE
*/ */
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
import kotlinx.atomicfu.loop import kotlinx.atomicfu.loop
...@@ -105,42 +107,6 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re ...@@ -105,42 +107,6 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
object EmptyResponse : GetMsgSuccess(emptyList()) object EmptyResponse : GetMsgSuccess(emptyList())
private suspend fun MsgComm.Msg.getNewGroup(bot: QQAndroidBot): Group? {
val troopNum = bot.network.run {
FriendList.GetTroopListSimplify(bot.client)
.sendAndExpect<FriendList.GetTroopListSimplify.Response>(retry = 2)
}.groups.firstOrNull { it.groupUin == msgHead.fromUin } ?: return null
@Suppress("DuplicatedCode")
return GroupImpl(
bot = bot,
coroutineContext = bot.coroutineContext,
id = Group.calculateGroupCodeByGroupUin(msgHead.fromUin),
groupInfo = bot._lowLevelQueryGroupInfo(troopNum.groupCode).apply {
this as GroupInfoImpl
if (this.delegate.groupName == null) {
this.delegate.groupName = troopNum.groupName
}
if (this.delegate.groupMemo == null) {
this.delegate.groupMemo = troopNum.groupMemo
}
if (this.delegate.groupUin == null) {
this.delegate.groupUin = troopNum.groupUin
}
this.delegate.groupCode = troopNum.groupCode
},
members = bot._lowLevelQueryGroupMemberList(
troopNum.groupUin,
troopNum.groupCode,
troopNum.dwGroupOwnerUin
)
)
}
private fun MsgComm.Msg.getNewMemberInfo(): MemberInfo { private fun MsgComm.Msg.getNewMemberInfo(): MemberInfo {
return object : MemberInfo { return object : MemberInfo {
override val nameCard: String get() = "" override val nameCard: String get() = ""
...@@ -189,10 +155,10 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re ...@@ -189,10 +155,10 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
} }
// 新群 // 新群
val newGroup = msg.getNewGroup(bot) ?: return@mapNotNull null val newGroup = bot.getNewGroup(Group.calculateGroupCodeByGroupUin(msg.msgHead.fromUin))
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") ?: return@mapNotNull null
bot.groups.delegate.addLast(newGroup) bot.groups.delegate.addLast(newGroup)
return@mapNotNull BotJoinGroupEvent(newGroup) return@mapNotNull BotJoinGroupEvent.Active(newGroup)
} else { } else {
group ?: return@mapNotNull null group ?: return@mapNotNull null
...@@ -212,12 +178,10 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re ...@@ -212,12 +178,10 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
discardExact(9) discardExact(9)
readByte().toInt().and(0xff) readByte().toInt().and(0xff)
} == 0x83) { } == 0x83) {
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
return@mapNotNull MemberJoinEvent.Invite(group.newMember(msg.getNewMemberInfo()) return@mapNotNull MemberJoinEvent.Invite(group.newMember(msg.getNewMemberInfo())
.also { group.members.delegate.addLast(it) }) .also { group.members.delegate.addLast(it) })
} }
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
return@mapNotNull MemberJoinEvent.Active(group.newMember(msg.getNewMemberInfo()) return@mapNotNull MemberJoinEvent.Active(group.newMember(msg.getNewMemberInfo())
.also { group.members.delegate.addLast(it) }) .also { group.members.delegate.addLast(it) })
} }
...@@ -394,3 +358,39 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re ...@@ -394,3 +358,39 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
} }
} }
internal suspend fun QQAndroidBot.getNewGroup(groupCode: Long): Group? {
val troopNum = network.run {
FriendList.GetTroopListSimplify(client)
.sendAndExpect<FriendList.GetTroopListSimplify.Response>(timeoutMillis = 10_000, retry = 5)
}.groups.firstOrNull { it.groupCode == groupCode } ?: return null
@Suppress("DuplicatedCode")
return GroupImpl(
bot = this,
coroutineContext = coroutineContext,
id = groupCode,
groupInfo = _lowLevelQueryGroupInfo(troopNum.groupCode).apply {
this as GroupInfoImpl
if (this.delegate.groupName == null) {
this.delegate.groupName = troopNum.groupName
}
if (this.delegate.groupMemo == null) {
this.delegate.groupMemo = troopNum.groupMemo
}
if (this.delegate.groupUin == null) {
this.delegate.groupUin = troopNum.groupUin
}
this.delegate.groupCode = troopNum.groupCode
},
members = _lowLevelQueryGroupMemberList(
troopNum.groupUin,
troopNum.groupCode,
troopNum.dwGroupOwnerUin
)
)
}
...@@ -174,6 +174,7 @@ abstract class Group : Contact(), CoroutineScope { ...@@ -174,6 +174,7 @@ abstract class Group : Contact(), CoroutineScope {
companion object { companion object {
/** /**
* 使用 groupCode 计算 groupUin. 这两个值仅在 mirai 内部协议区分, 一般人使用时无需在意.
* @suppress internal api * @suppress internal api
*/ */
@JvmStatic @JvmStatic
...@@ -181,6 +182,7 @@ abstract class Group : Contact(), CoroutineScope { ...@@ -181,6 +182,7 @@ abstract class Group : Contact(), CoroutineScope {
CommonGroupCalculations.calculateGroupUinByGroupCode(groupCode) CommonGroupCalculations.calculateGroupUinByGroupCode(groupCode)
/** /**
* 使用 groupUin 计算 groupCode. 这两个值仅在 mirai 内部协议区分, 一般人使用时无需在意.
* @suppress internal api * @suppress internal api
*/ */
@JvmStatic @JvmStatic
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
@file:JvmMultifileClass @file:JvmMultifileClass
@file:JvmName("BotEventsKt") @file:JvmName("BotEventsKt")
@file:Suppress("unused", "FunctionName") @file:Suppress("unused", "FunctionName", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
package net.mamoe.mirai.event.events package net.mamoe.mirai.event.events
...@@ -25,6 +25,7 @@ import net.mamoe.mirai.event.internal.MiraiAtomicBoolean ...@@ -25,6 +25,7 @@ import net.mamoe.mirai.event.internal.MiraiAtomicBoolean
import net.mamoe.mirai.qqandroid.network.Packet import net.mamoe.mirai.qqandroid.network.Packet
import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.internal.runBlocking import net.mamoe.mirai.utils.internal.runBlocking
import kotlin.internal.LowPriorityInOverloadResolution
import kotlin.jvm.* import kotlin.jvm.*
/** /**
...@@ -91,10 +92,44 @@ data class BotUnmuteEvent internal constructor( ...@@ -91,10 +92,44 @@ data class BotUnmuteEvent internal constructor(
/** /**
* Bot 成功加入了一个新群 * Bot 成功加入了一个新群
*/ */
@MiraiExperimentalAPI sealed class BotJoinGroupEvent : GroupEvent, Packet, AbstractEvent() {
data class BotJoinGroupEvent internal constructor( abstract override val group: Group
override val group: Group
) : BotPassiveEvent, GroupEvent, Packet, AbstractEvent() /**
* 不确定. 可能是主动加入
*/
@MiraiExperimentalAPI
data class Active internal constructor(
override val group: Group
) : BotPassiveEvent, GroupEvent, Packet, AbstractEvent() {
override fun toString(): String {
return "BotJoinGroupEvent.Active(group=$group)"
}
}
/**
* Bot 被一个群内的成员直接邀请加入了群.
*
* 此时服务器基于 Bot 的 QQ 设置自动同意了请求.
*/
@MiraiExperimentalAPI
data class Invite internal constructor(
/**
* 邀请人昵称 (可能为备注或群名片)
*/
val invitorName: String,
/**
* 邀请人
*/
val invitor: Member
) : BotPassiveEvent, GroupEvent, Packet, AbstractEvent() {
override val group: Group get() = invitor.group
override fun toString(): String {
return "BotJoinGroupEvent.Invite(invitorName='$invitorName', invitor=$invitor)"
}
}
}
// region 群设置 // region 群设置
...@@ -121,6 +156,7 @@ data class GroupNameChangeEvent internal constructor( ...@@ -121,6 +156,7 @@ data class GroupNameChangeEvent internal constructor(
*/ */
override val operator: Member? override val operator: Member?
) : GroupSettingChangeEvent<String>, Packet, GroupOperableEvent, AbstractEvent() { ) : GroupSettingChangeEvent<String>, Packet, GroupOperableEvent, AbstractEvent() {
@LowPriorityInOverloadResolution
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
val isByBot: Boolean val isByBot: Boolean
get() = operator == null get() = operator == null
...@@ -202,7 +238,8 @@ data class GroupAllowMemberInviteEvent internal constructor( ...@@ -202,7 +238,8 @@ data class GroupAllowMemberInviteEvent internal constructor(
/** /**
* 成员已经加入群的事件 * 成员已经加入群的事件
*/ */
sealed class MemberJoinEvent(override val member: Member) : GroupMemberEvent, BotPassiveEvent, Packet, AbstractEvent() { sealed class MemberJoinEvent(override val member: Member) : GroupMemberEvent, BotPassiveEvent, Packet,
AbstractEvent() {
/** /**
* 被邀请加入群 * 被邀请加入群
*/ */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE * https://github.com/mamoe/mirai/blob/master/LICENSE
*/ */
@file:Suppress("WRONG_MODIFIER_CONTAINING_DECLARATION") @file:Suppress("WRONG_MODIFIER_CONTAINING_DECLARATION", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
package net.mamoe.mirai.event.events package net.mamoe.mirai.event.events
...@@ -16,6 +16,7 @@ import net.mamoe.mirai.contact.Friend ...@@ -16,6 +16,7 @@ import net.mamoe.mirai.contact.Friend
import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.Member
import net.mamoe.mirai.event.Event import net.mamoe.mirai.event.Event
import kotlin.internal.HidesMembers
import kotlin.jvm.JvmSynthetic import kotlin.jvm.JvmSynthetic
/** /**
...@@ -69,6 +70,7 @@ interface GroupOperableEvent : GroupEvent { ...@@ -69,6 +70,7 @@ interface GroupOperableEvent : GroupEvent {
/** /**
* 是否由 [Bot] 操作 * 是否由 [Bot] 操作
*/ */
@HidesMembers
@get:JvmSynthetic // inline: planning to change to another file (1.2.0) @get:JvmSynthetic // inline: planning to change to another file (1.2.0)
inline val GroupOperableEvent.isByBot: Boolean inline val GroupOperableEvent.isByBot: Boolean
get() = operator == null get() = operator == null
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment