Handle event of new member joining

This commit is contained in:
Him188 2020-02-12 23:09:23 +08:00
parent 3b0ee9ad99
commit 348d13a4c1
8 changed files with 157 additions and 40 deletions

View File

@ -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")

View File

@ -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 {

View File

@ -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)"
}
}

View File

@ -187,6 +187,9 @@ internal class OnlinePush {
)
}
} else {
if (target == bot.uin) {
}
val member = group[target]
if (time == 0) {
MemberUnmuteEvent(operator = operator, member = member)

View File

@ -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

View File

@ -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

View File

@ -57,4 +57,9 @@ interface GroupInfo {
* 全员禁言
*/
val muteAll: Boolean
/**
* 机器人被禁言还剩时间, .
*/
val botMuteRemaining: Int
}

View File

@ -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
/**
* 成员离开群的事件