List complete

This commit is contained in:
jiahua.liu 2020-02-03 00:15:09 +08:00
parent bc860a2d0d
commit bfdcee1a1c
6 changed files with 77 additions and 60 deletions

View File

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

View File

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

View File

@ -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
}
/**

View File

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

View File

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

View File

@ -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)
*/