mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-19 18:53:33 +08:00
Handle event of new member joining
This commit is contained in:
parent
3b0ee9ad99
commit
348d13a4c1
@ -325,6 +325,15 @@ internal class GroupImpl(
|
||||
@UseExperimental(MiraiExperimentalAPI::class)
|
||||
override lateinit var botPermission: MemberPermission
|
||||
|
||||
var _botMuteRemaining: Int = groupInfo.botMuteRemaining
|
||||
|
||||
override val botMuteRemaining: Int =
|
||||
if (_botMuteRemaining == 0 || _botMuteRemaining == 0xFFFFFFFF.toInt()) {
|
||||
0
|
||||
} else {
|
||||
_botMuteRemaining - currentTimeSeconds.toInt() - bot.client.timeDifference.toInt()
|
||||
}
|
||||
|
||||
override val members: ContactList<Member> = ContactList(members.mapNotNull {
|
||||
if (it.uin == bot.uin) {
|
||||
botPermission = it.permission
|
||||
@ -487,6 +496,7 @@ internal class GroupImpl(
|
||||
}
|
||||
|
||||
override suspend fun sendMessage(message: MessageChain) {
|
||||
check(!isBotMuted) { "bot is muted. Remaining seconds=$botMuteRemaining" }
|
||||
val event = GroupMessageSendEvent(this, message).broadcast()
|
||||
if (event.isCancelled) {
|
||||
throw EventCancelledException("cancelled by FriendMessageSendEvent")
|
||||
|
@ -44,6 +44,7 @@ internal inline class GroupInfoImpl(
|
||||
override val autoApprove get() = delegate.groupFlagext3?.and(0x00100000) == 0
|
||||
override val confessTalk get() = delegate.groupFlagext3?.and(0x00002000) == 0
|
||||
override val muteAll: Boolean get() = delegate.shutupTimestamp != 0
|
||||
override val botMuteRemaining: Int get() = delegate.shutupTimestampMe ?: 0
|
||||
}
|
||||
|
||||
internal class TroopManagement {
|
||||
|
@ -11,12 +11,18 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
|
||||
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.discardExact
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.MemberPermission
|
||||
import net.mamoe.mirai.data.MemberInfo
|
||||
import net.mamoe.mirai.data.MultiPacket
|
||||
import net.mamoe.mirai.data.Packet
|
||||
import net.mamoe.mirai.event.BroadcastControllable
|
||||
import net.mamoe.mirai.event.events.BotJoinGroupEvent
|
||||
import net.mamoe.mirai.event.events.BotOfflineEvent
|
||||
import net.mamoe.mirai.event.events.MemberJoinEvent
|
||||
import net.mamoe.mirai.message.FriendMessage
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.qqandroid.GroupImpl
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.io.serialization.decodeUniPacket
|
||||
import net.mamoe.mirai.qqandroid.io.serialization.readProtoBuf
|
||||
@ -32,6 +38,9 @@ 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.SyncCookie
|
||||
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.list.FriendList
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
import net.mamoe.mirai.utils.currentTimeSeconds
|
||||
import kotlin.math.absoluteValue
|
||||
@ -94,13 +103,13 @@ internal class MessageSvc {
|
||||
}
|
||||
|
||||
@UseExperimental(MiraiInternalAPI::class)
|
||||
internal class GetMsgSuccess(delegate: List<FriendMessage>) : Response(MsgSvc.SyncFlag.STOP, delegate)
|
||||
internal class GetMsgSuccess(delegate: List<Packet>) : Response(MsgSvc.SyncFlag.STOP, delegate)
|
||||
|
||||
/**
|
||||
* 不要直接 expect 这个 class. 它可能
|
||||
*/
|
||||
@MiraiInternalAPI
|
||||
open class Response(internal val syncFlagFromServer: MsgSvc.SyncFlag, delegate: List<FriendMessage>) : MultiPacket<FriendMessage>(delegate),
|
||||
open class Response(internal val syncFlagFromServer: MsgSvc.SyncFlag, delegate: List<Packet>) : MultiPacket<Packet>(delegate),
|
||||
BroadcastControllable {
|
||||
override val shouldBroadcast: Boolean
|
||||
get() = syncFlagFromServer == MsgSvc.SyncFlag.STOP
|
||||
@ -112,7 +121,7 @@ internal class MessageSvc {
|
||||
|
||||
object EmptyResponse : Response(MsgSvc.SyncFlag.STOP, emptyList())
|
||||
|
||||
@UseExperimental(MiraiInternalAPI::class)
|
||||
@UseExperimental(MiraiInternalAPI::class, MiraiExperimentalAPI::class)
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||
// 00 00 01 0F 08 00 12 00 1A 34 08 FF C1 C4 F1 05 10 FF C1 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 8A CA 91 D1 0C 48 9B A5 BD 9B 0A 58 DE 9D 99 F8 08 60 1D 68 FF C1 C4 F1 05 70 00 20 02 2A 9D 01 08 F3 C1 C4 F1 05 10 A2 FF 8C F0 03 18 01 22 8A 01 0A 2A 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 18 A6 01 20 0B 28 AE F9 01 30 F4 C1 C4 F1 05 38 A7 E3 D8 D4 84 80 80 80 01 B8 01 CD B5 01 12 08 08 01 10 00 18 00 20 00 1A 52 0A 50 0A 27 08 00 10 F4 C1 C4 F1 05 18 A7 E3 D8 D4 04 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 08 0A 06 0A 04 4E 4D 53 4C 12 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 12 04 4A 02 08 00 30 01 2A 15 08 97 A2 C1 F1 05 10 95 A6 F5 E5 0C 18 01 30 01 40 01 48 81 01 2A 10 08 D3 F7 B5 F1 05 10 DD F1 92 B7 07 18 01 30 01 38 00 42 00 48 00
|
||||
val resp = readProtoBuf(MsgSvc.PbGetMsgResp.serializer())
|
||||
@ -130,40 +139,86 @@ internal class MessageSvc {
|
||||
return EmptyResponse
|
||||
}
|
||||
|
||||
val messages = resp.uinPairMsgs.asSequence().filterNot { it.msg == null }.flatMap { it.msg!!.asSequence() }.mapNotNull {
|
||||
when (it.msgHead.msgType) {
|
||||
33 -> {
|
||||
if (it.msgHead.authUin == bot.uin) {
|
||||
val group = bot.getGroupByUinOrNull(it.msgHead.fromUin)
|
||||
if (group == null) {
|
||||
TODO("查询群信息, 添加群")
|
||||
val messages = resp.uinPairMsgs.asSequence()
|
||||
.filterNot { it.msg == null }
|
||||
.flatMap { it.msg!!.asSequence() }
|
||||
.toList() // so as to inline
|
||||
.mapNotNull<MsgComm.Msg, Packet> { msg ->
|
||||
when (msg.msgHead.msgType) {
|
||||
33 -> {
|
||||
val group = bot.getGroupByUinOrNull(msg.msgHead.fromUin)
|
||||
if (msg.msgHead.authUin == bot.uin) {
|
||||
if (group != null) {
|
||||
error("group is not null while bot is invited to the group")
|
||||
}
|
||||
// 新群
|
||||
|
||||
val troopNum = bot.network.run {
|
||||
FriendList.GetTroopListSimplify(bot.client)
|
||||
.sendAndExpect<FriendList.GetTroopListSimplify.Response>(retry = 2)
|
||||
}.groups.first { it.groupUin == msg.msgHead.fromUin }
|
||||
|
||||
|
||||
val newGroup = GroupImpl(
|
||||
bot = bot,
|
||||
coroutineContext = bot.coroutineContext,
|
||||
id = Group.calculateGroupCodeByGroupUin(msg.msgHead.fromUin),
|
||||
groupInfo = bot.queryGroupInfo(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.queryGroupMemberList(troopNum.groupUin, troopNum.groupCode, troopNum.dwGroupOwnerUin)
|
||||
)
|
||||
bot.groups.delegate.addLast(newGroup)
|
||||
return@mapNotNull BotJoinGroupEvent(newGroup)
|
||||
} else {
|
||||
checkNotNull(group) { "group is null while a member is joining to" }
|
||||
if (group.members.contains(msg.msgHead.authUin)) {
|
||||
return@mapNotNull null
|
||||
} else {
|
||||
return@mapNotNull MemberJoinEvent(group.Member(object : MemberInfo {
|
||||
override val nameCard: String get() = ""
|
||||
override val permission: MemberPermission get() = MemberPermission.MEMBER
|
||||
override val specialTitle: String get() = ""
|
||||
override val uin: Long get() = msg.msgHead.authUin
|
||||
override val nick: String get() = msg.msgHead.authNick.takeIf { it.isNotEmpty() } ?: msg.msgHead.fromNick
|
||||
}).also { group.members.delegate.addLast(it) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TODO("为 group 添加一个 fun Member() 来构造 member")
|
||||
// bot.getGroupByUin(it.msgHead.fromUin).members.delegate.addLast()
|
||||
println("GroupUin" + it.msgHead.fromUin + "新群员" + it.msgHead.authUin + " 出现了[" + it.msgHead.authNick + "] 添加刷新")
|
||||
null
|
||||
}
|
||||
166 -> {
|
||||
when {
|
||||
it.msgHead.fromUin == bot.uin -> null
|
||||
!bot.firstLoginSucceed -> null
|
||||
else -> FriendMessage(
|
||||
bot,
|
||||
bot.getFriend(it.msgHead.fromUin),
|
||||
it.toMessageChain()
|
||||
)
|
||||
166 -> {
|
||||
return@mapNotNull when {
|
||||
msg.msgHead.fromUin == bot.uin -> null
|
||||
!bot.firstLoginSucceed -> null
|
||||
else -> FriendMessage(
|
||||
bot,
|
||||
bot.getFriend(msg.msgHead.fromUin),
|
||||
msg.toMessageChain()
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> return@mapNotNull null
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}.toMutableList()
|
||||
if (resp.syncFlag == MsgSvc.SyncFlag.STOP) {
|
||||
messages.ifEmpty {
|
||||
return EmptyResponse
|
||||
}
|
||||
return GetMsgSuccess(mutableListOf(messages.last()))
|
||||
return GetMsgSuccess(listOf(messages.last()))
|
||||
}
|
||||
return Response(resp.syncFlag, messages)
|
||||
}
|
||||
@ -201,7 +256,8 @@ internal class MessageSvc {
|
||||
}
|
||||
|
||||
data class Failed(val resultType: Int, val errorCode: Int, val errorMessage: String) : Response() {
|
||||
override fun toString(): String = "MessageSvc.PbSendMsg.Response.Failed(resultType=$resultType, errorCode=$errorCode, errorMessage=$errorMessage)"
|
||||
override fun toString(): String =
|
||||
"MessageSvc.PbSendMsg.Response.Failed(resultType=$resultType, errorCode=$errorCode, errorMessage=$errorMessage)"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,6 +187,9 @@ internal class OnlinePush {
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (target == bot.uin) {
|
||||
|
||||
}
|
||||
val member = group[target]
|
||||
if (time == 0) {
|
||||
MemberUnmuteEvent(operator = operator, member = member)
|
||||
|
@ -14,6 +14,7 @@ package net.mamoe.mirai.contact
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.event.events.BeforeImageUploadEvent
|
||||
import net.mamoe.mirai.event.events.EventCancelledException
|
||||
import net.mamoe.mirai.event.events.ImageUploadEvent
|
||||
import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
|
||||
import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
|
||||
@ -47,16 +48,20 @@ interface Contact : CoroutineScope {
|
||||
*
|
||||
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
|
||||
* @see GroupMessageSendEvent 发送群消息事件. cancellable
|
||||
*
|
||||
* @throws EventCancelledException 当发送消息事件被取消
|
||||
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
|
||||
*/
|
||||
suspend fun sendMessage(message: MessageChain)
|
||||
|
||||
/**
|
||||
* 上传一个图片以备发送.
|
||||
* TODO: 群图片与好友图片之间是否通用还不确定.
|
||||
* TODO: 好友之间图片是否通用还不确定.
|
||||
* TODO 群图片与好友图片在服务器上是通用的, 在 mirai 目前不通用.
|
||||
*
|
||||
* @see BeforeImageUploadEvent 图片发送前事件, cancellable
|
||||
* @see ImageUploadEvent 图片发送完成事件
|
||||
*
|
||||
* @throws EventCancelledException 当发送消息事件被取消
|
||||
*/
|
||||
suspend fun uploadImage(image: ExternalImage): Image
|
||||
|
||||
|
@ -24,18 +24,20 @@ interface Group : Contact, CoroutineScope {
|
||||
/**
|
||||
* 群名称.
|
||||
*
|
||||
* 在修改时将会异步上传至服务器. 无权限修改时将会抛出异常 [PermissionDeniedException]
|
||||
* 在修改时将会异步上传至服务器.
|
||||
* 频繁修改可能会被服务器拒绝.
|
||||
*
|
||||
* @see MemberPermissionChangeEvent
|
||||
* @throws PermissionDeniedException 无权限修改时将会抛出异常
|
||||
*/
|
||||
var name: String
|
||||
/**
|
||||
* 入群公告, 没有时为空字符串.
|
||||
*
|
||||
* 在修改时将会异步上传至服务器. 无权限修改时将会抛出异常 [PermissionDeniedException]
|
||||
* 在修改时将会异步上传至服务器.
|
||||
*
|
||||
* @see GroupEntranceAnnouncementChangeEvent
|
||||
* @throws PermissionDeniedException 无权限修改时将会抛出异常
|
||||
*/
|
||||
var entranceAnnouncement: String
|
||||
/**
|
||||
@ -49,17 +51,19 @@ interface Group : Contact, CoroutineScope {
|
||||
/**
|
||||
* 坦白说状态. `true` 为允许.
|
||||
*
|
||||
* 在修改时将会异步上传至服务器. 无权限修改时将会抛出异常 [PermissionDeniedException]
|
||||
|
||||
* 在修改时将会异步上传至服务器.
|
||||
*
|
||||
* @see GroupAllowConfessTalkEvent
|
||||
* @throws PermissionDeniedException 无权限修改时将会抛出异常
|
||||
*/
|
||||
var confessTalk: Boolean
|
||||
/**
|
||||
* 允许群员邀请好友入群的状态. `true` 为允许
|
||||
*
|
||||
* 在修改时将会异步上传至服务器. 无权限修改时将会抛出异常 [PermissionDeniedException]
|
||||
* 在修改时将会异步上传至服务器.
|
||||
*
|
||||
* @see GroupAllowMemberInviteEvent
|
||||
* @throws PermissionDeniedException 无权限修改时将会抛出异常
|
||||
*/
|
||||
var allowMemberInvite: Boolean
|
||||
/**
|
||||
@ -77,10 +81,17 @@ interface Group : Contact, CoroutineScope {
|
||||
override val id: Long
|
||||
|
||||
/**
|
||||
* 群主 (同步事件更新)
|
||||
* 群主
|
||||
*/
|
||||
val owner: Member
|
||||
|
||||
/**
|
||||
* 机器人被禁言还剩余多少秒
|
||||
*
|
||||
* @see BotMuteEvent
|
||||
* @see isBotMuted
|
||||
*/
|
||||
val botMuteRemaining: Int
|
||||
|
||||
/**
|
||||
* 机器人在这个群里的权限
|
||||
@ -124,7 +135,7 @@ interface Group : Contact, CoroutineScope {
|
||||
* 非特殊情况请不要使用这个函数. 优先使用 [get].
|
||||
*/
|
||||
@MiraiExperimentalAPI("dangerous")
|
||||
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||
@Suppress("INAPPLICABLE_JVM_NAME", "FunctionName")
|
||||
@JvmName("newMember")
|
||||
fun Member(memberInfo: MemberInfo): Member
|
||||
|
||||
@ -168,4 +179,9 @@ interface Group : Contact, CoroutineScope {
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
fun toFullString(): String = "Group(id=${this.id}, name=$name, owner=${owner.id}, members=${members.idContentString})"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回机器人是否正在被禁言
|
||||
*/
|
||||
val Group.isBotMuted: Boolean get() = this.botMuteRemaining == 0
|
||||
|
@ -57,4 +57,9 @@ interface GroupInfo {
|
||||
* 全员禁言
|
||||
*/
|
||||
val muteAll: Boolean
|
||||
|
||||
/**
|
||||
* 机器人被禁言还剩时间, 秒.
|
||||
*/
|
||||
val botMuteRemaining: Int
|
||||
}
|
@ -18,6 +18,7 @@ import net.mamoe.mirai.event.CancellableEvent
|
||||
import net.mamoe.mirai.message.data.Image
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.utils.ExternalImage
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||
|
||||
|
||||
@Suppress("unused")
|
||||
@ -123,6 +124,26 @@ data class BotGroupPermissionChangeEvent(
|
||||
val new: MemberPermission
|
||||
) : BotPassiveEvent, GroupEvent, Packet
|
||||
|
||||
/**
|
||||
* Bot 被禁言
|
||||
*/
|
||||
data class BotMuteEvent(
|
||||
val durationSeconds: Int,
|
||||
override val group: Group,
|
||||
/**
|
||||
* 操作人. 为 null 则为机器人操作
|
||||
*/
|
||||
val operator: Member?
|
||||
) : GroupEvent, Packet, BotPassiveEvent
|
||||
|
||||
/**
|
||||
* Bot 加入了一个新群
|
||||
*/
|
||||
@MiraiExperimentalAPI
|
||||
data class BotJoinGroupEvent(
|
||||
override val group: Group
|
||||
) : BotPassiveEvent, GroupEvent, Packet
|
||||
|
||||
// region 群设置
|
||||
|
||||
/**
|
||||
@ -219,7 +240,7 @@ data class GroupAllowMemberInviteEvent(
|
||||
/**
|
||||
* 成员加入群的事件
|
||||
*/
|
||||
data class MemberJoinEvent(override val member: Member) : GroupMemberEvent, BotPassiveEvent
|
||||
data class MemberJoinEvent(override val member: Member) : GroupMemberEvent, BotPassiveEvent, Packet
|
||||
|
||||
/**
|
||||
* 成员离开群的事件
|
||||
|
Loading…
Reference in New Issue
Block a user