mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-06 08:00:10 +08:00
List complete
This commit is contained in:
parent
bc860a2d0d
commit
bfdcee1a1c
@ -10,6 +10,7 @@ import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc
|
||||
import net.mamoe.mirai.utils.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
internal abstract class ContactImpl : Contact
|
||||
|
||||
@ -74,13 +75,12 @@ internal class MemberImpl(
|
||||
|
||||
@UseExperimental(MiraiInternalAPI::class)
|
||||
internal class GroupImpl(
|
||||
bot: QQAndroidBot, override val coroutineContext: CoroutineContext, override val id: Long
|
||||
bot: QQAndroidBot, override val coroutineContext: CoroutineContext, override val id: Long,
|
||||
override var name: String,
|
||||
override var announcement: String,
|
||||
override var members: ContactList<Member>
|
||||
) : ContactImpl(), Group {
|
||||
override lateinit var owner: Member
|
||||
override lateinit var name: String
|
||||
override lateinit var announcement: String
|
||||
override lateinit var members: ContactList<Member>
|
||||
|
||||
override val internalId: GroupInternalId = GroupId(id).toInternalId()
|
||||
|
||||
override fun getMember(id: Long): Member =
|
||||
|
@ -43,17 +43,17 @@ internal abstract class QQAndroidBotBase constructor(
|
||||
override val groups: ContactList<Group> = ContactList(LockFreeLinkedList())
|
||||
|
||||
override suspend fun getGroup(id: GroupId): Group {
|
||||
return groups.delegate.filteringGetOrAdd({ it.id == id.value }, { GroupImpl(this as QQAndroidBot, coroutineContext, id.value) })
|
||||
return groups.delegate.getOrNull(id.value) ?: throw NoSuchElementException("Can not found group ${id.value}")
|
||||
}
|
||||
|
||||
override suspend fun getGroup(internalId: GroupInternalId): Group {
|
||||
internalId.toId().value.let { id ->
|
||||
return groups.delegate.filteringGetOrAdd({ it.id == id }, { GroupImpl(this as QQAndroidBot, coroutineContext, id) })
|
||||
with(internalId.toId().value) {
|
||||
return groups.delegate.getOrNull(this) ?: throw NoSuchElementException("Can not found group $this")
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getGroup(id: Long): Group {
|
||||
return groups.delegate.filteringGetOrAdd({ it.id == id }, { GroupImpl(this as QQAndroidBot, coroutineContext, id) })
|
||||
return groups.delegate.getOrNull(id) ?: throw NoSuchElementException("Can not found group $id")
|
||||
}
|
||||
|
||||
override suspend fun Image.getLink(): ImageLink {
|
||||
|
@ -9,11 +9,15 @@ import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.Input
|
||||
import kotlinx.io.core.buildPacket
|
||||
import kotlinx.io.core.use
|
||||
import net.mamoe.mirai.contact.ContactList
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.data.MultiPacket
|
||||
import net.mamoe.mirai.data.Packet
|
||||
import net.mamoe.mirai.event.*
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.qqandroid.GroupImpl
|
||||
import net.mamoe.mirai.qqandroid.MemberImpl
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.QQImpl
|
||||
import net.mamoe.mirai.qqandroid.event.ForceOfflineEvent
|
||||
@ -106,8 +110,6 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
}
|
||||
|
||||
override suspend fun init() {
|
||||
// delay(5000)
|
||||
|
||||
this@QQAndroidBotNetworkHandler.subscribeAlways<ForceOfflineEvent> {
|
||||
if (this@QQAndroidBotNetworkHandler.bot == this.bot) {
|
||||
close()
|
||||
@ -149,28 +151,65 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
}
|
||||
|
||||
try {
|
||||
bot.logger.info("开始加载群组列表")
|
||||
bot.logger.info("开始加载群组列表与群成员列表")
|
||||
val troopData = FriendList.GetTroopListSimplify(
|
||||
bot.client
|
||||
).sendAndExpect<FriendList.GetTroopListSimplify.Response>(timeoutMillis = 1000)
|
||||
println("获取到群数量" + troopData.groups.size)
|
||||
val toGet: MutableMap<GroupImpl, ContactList<Member>> = mutableMapOf()
|
||||
troopData.groups.forEach {
|
||||
bot.groups.delegate.addLast(GroupImpl(bot, EmptyCoroutineContext, it.groupUin))
|
||||
val contactList = ContactList(LockFreeLinkedList<Member>())
|
||||
val group =
|
||||
GroupImpl(bot, EmptyCoroutineContext, it.groupUin, it.groupName!!, it.groupMemo!!, contactList)
|
||||
group.owner =
|
||||
MemberImpl(QQImpl(bot, EmptyCoroutineContext, it.dwGroupOwnerUin!!), group, EmptyCoroutineContext)
|
||||
toGet[group] = contactList
|
||||
bot.groups.delegate.addLast(group)
|
||||
println(it.groupUin.toString() + " - " + it.groupCode)
|
||||
}
|
||||
bot.logger.info("群组列表加载完成, 共 ${troopData.groups.size}个")
|
||||
toGet.forEach {
|
||||
try {
|
||||
getTroopMemberList(it.key, it.value)
|
||||
} catch (e: Exception) {
|
||||
bot.logger.info("群${it.key.id}的列表拉取失败, 将采用动态加入")
|
||||
}
|
||||
delay(200)
|
||||
}
|
||||
bot.logger.info("群组列表与群成员加载完成, 共 ${troopData.groups.size}个")
|
||||
} catch (e: Exception) {
|
||||
bot.logger.info("加载组信息失败|一般这是由于加载过于频繁导致/将以热加载方式加载群列表")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
suspend fun getTroopMemberList(groupUni: Long) {
|
||||
bot.logger.info("开始群[$groupUni]成员")
|
||||
val data = FriendList.GetTroopMemberList(
|
||||
bot.client,
|
||||
groupUni,
|
||||
0
|
||||
).sendAndExpect<FriendList.GetFriendGroupList.Response>(timeoutMillis = 1000)
|
||||
println(data.contentToString())
|
||||
suspend fun getTroopMemberList(group: GroupImpl, list: ContactList<Member>): ContactList<Member> {
|
||||
bot.logger.info("开始获取群[${group.id}]成员列表")
|
||||
var size = 0
|
||||
var nextUin = 0L
|
||||
while (true) {
|
||||
val data = FriendList.GetTroopMemberList(
|
||||
bot.client,
|
||||
group.id,
|
||||
nextUin
|
||||
).sendAndExpect<FriendList.GetTroopMemberList.Response>(timeoutMillis = 3000)
|
||||
data.members.forEach {
|
||||
list.delegate.addLast(
|
||||
MemberImpl(
|
||||
QQImpl(bot, EmptyCoroutineContext, it.memberUin),
|
||||
group,
|
||||
EmptyCoroutineContext
|
||||
)
|
||||
)
|
||||
}
|
||||
size += data.members.size
|
||||
nextUin = data.nextUin
|
||||
if (nextUin == 0L) {
|
||||
break
|
||||
}
|
||||
println("已获取群[${group.id}]成员列表前" + size + "个成员")
|
||||
}
|
||||
println("群[${group.id}]成员全部获取完成, 共${list.size}个成员")
|
||||
return list
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -116,7 +116,8 @@ internal object KnownPacketFactories {
|
||||
MessageSvc.PushForceOffline,
|
||||
MessageSvc.PbSendMsg,
|
||||
FriendList.GetFriendGroupList,
|
||||
FriendList.GetTroopListSimplify
|
||||
FriendList.GetTroopListSimplify,
|
||||
FriendList.GetTroopMemberList
|
||||
)
|
||||
|
||||
object IncomingFactories : List<IncomingPacketFactory<*>> by mutableListOf(
|
||||
|
@ -27,10 +27,11 @@ internal class FriendList {
|
||||
|
||||
internal object GetTroopMemberList :
|
||||
OutgoingPacketFactory<GetTroopMemberList.Response>("friendlist.GetTroopMemberListReq") {
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GetTroopMemberList.Response {
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||
val res = this.debugIfFail { this.decodeUniPacket(GetTroopMemberListResp.serializer()) }
|
||||
return Response(
|
||||
res.vecTroopMember
|
||||
res.vecTroopMember,
|
||||
res.nextUin
|
||||
)
|
||||
}
|
||||
|
||||
@ -52,10 +53,11 @@ internal class FriendList {
|
||||
GetTroopMemberListReq.serializer(),
|
||||
GetTroopMemberListReq(
|
||||
uin = client.uin,
|
||||
groupCode = GroupId(targetGroupId).toInternalId().value,
|
||||
groupCode = targetGroupId,
|
||||
groupUin = targetGroupId,
|
||||
nextUin = nextUin,
|
||||
reqType = 0
|
||||
reqType = 0,
|
||||
version = 2
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -64,7 +66,8 @@ internal class FriendList {
|
||||
}
|
||||
|
||||
class Response(
|
||||
val members: List<stTroopMemberInfo>
|
||||
val members: List<stTroopMemberInfo>,
|
||||
val nextUin: Long
|
||||
) : Packet {
|
||||
override fun toString(): String = "Friendlist.GetTroopMemberList.Response"
|
||||
}
|
||||
@ -73,7 +76,6 @@ internal class FriendList {
|
||||
|
||||
internal object GetTroopListSimplify :
|
||||
OutgoingPacketFactory<GetTroopListSimplify.Response>("friendlist.GetTroopListReqV2") {
|
||||
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||
val res = this.decodeUniPacket(GetTroopListRespV2.serializer())
|
||||
return Response(res.vecTroopList.orEmpty())
|
||||
|
@ -10,10 +10,11 @@ import net.mamoe.mirai.utils.coerceAtLeastOrFail
|
||||
/**
|
||||
* 群. 在 QQ Android 中叫做 "Troop"
|
||||
*
|
||||
* Group ID 与 Group Number 并不是同一个值.
|
||||
* - Group Number([Group.id]) 是通常使用的群号码.(在 QQ 客户端中可见)
|
||||
* - Group ID([Group.internalId]) 是与调用 API 时使用的 id.(在 QQ 客户端中不可见)
|
||||
* @author Him188moe
|
||||
* Group UIN 与 Group Code 并不是同一个值.
|
||||
* Group Code是在客户端显示的code
|
||||
* Group Uin是QQ内部的群ID
|
||||
* 在网络调用层 Code与Uin会被混用
|
||||
* 但在开发层 你应该只关注Group Code
|
||||
*/
|
||||
interface Group : Contact, CoroutineScope {
|
||||
/**
|
||||
@ -75,30 +76,4 @@ interface Group : Contact, CoroutineScope {
|
||||
*
|
||||
* @see GroupInternalId.toId 由 [GroupInternalId] 转换为 [GroupId]
|
||||
* @see GroupId.toInternalId 由 [GroupId] 转换为 [GroupInternalId]
|
||||
*/
|
||||
inline class GroupId(inline val value: Long)
|
||||
|
||||
/**
|
||||
* 将 [this] 转为 [GroupInternalId].
|
||||
*/
|
||||
fun Long.groupInternalId(): GroupInternalId = GroupInternalId(this)
|
||||
|
||||
/**
|
||||
* 将无符号整数格式的 [Long] 转为 [GroupId].
|
||||
*
|
||||
* 注: 在 Java 中常用 [Long] 来表示 [UInt].
|
||||
*
|
||||
* 注: 在 Kotlin/Java, 有符号的数据类型的二进制最高位为符号标志.
|
||||
* 如一个 byte, `1000 0000` 最高位为 1, 则为负数.
|
||||
*/
|
||||
fun Long.groupId(): GroupId = GroupId(this.coerceAtLeastOrFail(0))
|
||||
|
||||
/**
|
||||
* 一些群 API 使用的 ID. 在使用时会特别注明
|
||||
*
|
||||
* 注: 在引用群 ID 时, 应使用 [GroupId] 或 [GroupInternalId] 类型, 而不是 [UInt]
|
||||
*
|
||||
* @see GroupInternalId.toId 由 [GroupInternalId] 转换为 [GroupId]
|
||||
* @see GroupId.toInternalId 由 [GroupId] 转换为 [GroupInternalId]
|
||||
*/
|
||||
inline class GroupInternalId(inline val value: Long)
|
||||
*/
|
Loading…
Reference in New Issue
Block a user