Fix massive group list loading

This commit is contained in:
Him188 2020-04-08 13:25:20 +08:00
parent 4633803c55
commit faf8002de9
6 changed files with 68 additions and 59 deletions

View File

@ -206,7 +206,7 @@ internal abstract class QQAndroidBotBase constructor(
TroopManagement.GetGroupInfo( TroopManagement.GetGroupInfo(
client = bot.client, client = bot.client,
groupCode = groupCode groupCode = groupCode
).sendAndExpect<GroupInfoImpl>(retry = 2) ).sendAndExpect<GroupInfoImpl>(retry = 3)
} }
@OptIn(LowLevelAPI::class) @OptIn(LowLevelAPI::class)
@ -224,7 +224,7 @@ internal abstract class QQAndroidBotBase constructor(
targetGroupUin = groupUin, targetGroupUin = groupUin,
targetGroupCode = groupCode, targetGroupCode = groupCode,
nextUin = nextUin nextUin = nextUin
).sendAndExpect<FriendList.GetTroopMemberList.Response>(timeoutMillis = 3000) ).sendAndExpect<FriendList.GetTroopMemberList.Response>(retry = 3)
sequence += data.members.asSequence().map { troopMemberInfo -> sequence += data.members.asSequence().map { troopMemberInfo ->
MemberInfoImpl(troopMemberInfo, ownerId) MemberInfoImpl(troopMemberInfo, ownerId)
} }

View File

@ -201,7 +201,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
_pendingEnabled.value = true _pendingEnabled.value = true
} }
coroutineScope { supervisorScope {
launch { launch {
lateinit var loadFriends: suspend () -> Unit lateinit var loadFriends: suspend () -> Unit
// 不要用 fun, 不要 join declaration, 不要用 val, 编译失败警告 // 不要用 fun, 不要 join declaration, 不要用 val, 编译失败警告
@ -262,56 +262,60 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
try { try {
logger.info("开始加载群组列表与群成员列表") logger.info("开始加载群组列表与群成员列表")
val troopListData = FriendList.GetTroopListSimplify(bot.client) val troopListData = FriendList.GetTroopListSimplify(bot.client)
.sendAndExpect<FriendList.GetTroopListSimplify.Response>(retry = 2) .sendAndExpect<FriendList.GetTroopListSimplify.Response>(retry = 3)
troopListData.groups.forEach { troopNum -> troopListData.groups.chunked(100).forEach { chunk ->
// 别用 fun, 别 val, 编译失败警告 coroutineScope {
lateinit var loadGroup: suspend () -> Unit chunk.forEach { troopNum ->
// 别用 fun, 别 val, 编译失败警告
lateinit var loadGroup: suspend () -> Unit
loadGroup = suspend { loadGroup = suspend {
retryCatching(3) { retryCatching(3) {
bot.groups.delegate.addLast( bot.groups.delegate.addLast(
@Suppress("DuplicatedCode") @Suppress("DuplicatedCode")
(GroupImpl( (GroupImpl(
bot = bot, bot = bot,
coroutineContext = bot.coroutineContext, coroutineContext = bot.coroutineContext,
id = troopNum.groupCode, id = troopNum.groupCode,
groupInfo = bot._lowLevelQueryGroupInfo(troopNum.groupCode).apply { groupInfo = bot._lowLevelQueryGroupInfo(troopNum.groupCode).apply {
this as GroupInfoImpl this as GroupInfoImpl
if (this.delegate.groupName == null) { if (this.delegate.groupName == null) {
this.delegate.groupName = troopNum.groupName this.delegate.groupName = troopNum.groupName
} }
if (this.delegate.groupMemo == null) { if (this.delegate.groupMemo == null) {
this.delegate.groupMemo = troopNum.groupMemo this.delegate.groupMemo = troopNum.groupMemo
} }
if (this.delegate.groupUin == null) { if (this.delegate.groupUin == null) {
this.delegate.groupUin = troopNum.groupUin this.delegate.groupUin = troopNum.groupUin
} }
this.delegate.groupCode = troopNum.groupCode this.delegate.groupCode = troopNum.groupCode
}, },
members = bot._lowLevelQueryGroupMemberList( members = bot._lowLevelQueryGroupMemberList(
troopNum.groupUin, troopNum.groupUin,
troopNum.groupCode, troopNum.groupCode,
troopNum.dwGroupOwnerUin troopNum.dwGroupOwnerUin
)
))
) )
)) }.exceptionOrNull()?.let {
) logger.error { "${troopNum.groupCode}的列表拉取失败, 一段时间后将会重试" }
}.exceptionOrNull()?.let { logger.error(it)
logger.error { "${troopNum.groupCode}的列表拉取失败, 一段时间后将会重试" } this@QQAndroidBotNetworkHandler.launch {
logger.error(it) delay(10_000)
this@QQAndroidBotNetworkHandler.launch { loadGroup()
delay(10_000) }
}
Unit // 别删, 编译失败警告
}
launch {
loadGroup() loadGroup()
} }
} }
Unit // 别删, 编译失败警告
}
launch {
loadGroup()
} }
} }
logger.info { "群组列表与群成员加载完成, 共 ${troopListData.groups.size}" } logger.info { "群组列表与群成员加载完成, 共 ${troopListData.groups.size}" }
@ -322,17 +326,18 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
} }
} }
withTimeoutOrNull(5000) { supervisorScope {
lateinit var listener: Listener<PacketReceivedEvent> withTimeoutOrNull(30000) {
listener = this.subscribeAlways { lateinit var listener: Listener<PacketReceivedEvent>
if (it.packet is MessageSvc.PbGetMsg.GetMsgSuccess) { listener = this.subscribeAlways {
listener.complete() if (it.packet is MessageSvc.PbGetMsg.GetMsgSuccess) {
listener.complete()
}
} }
}
MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect()
} ?: error("timeout syncing friend message history")
MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect<Packet>()
} ?: error("timeout syncing friend message history")
}
bot.firstLoginSucceed = true bot.firstLoginSucceed = true
_pendingEnabled.value = false _pendingEnabled.value = false

View File

@ -33,7 +33,7 @@ import net.mamoe.mirai.data.GroupInfo as MiraiGroupInfo
@OptIn(LowLevelAPI::class) @OptIn(LowLevelAPI::class)
internal class GroupInfoImpl( internal class GroupInfoImpl(
internal val delegate: Oidb0x88d.GroupInfo internal val delegate: Oidb0x88d.GroupInfo
) : MiraiGroupInfo, Packet { ) : MiraiGroupInfo, Packet, Packet.NoLog {
override val uin: Long get() = delegate.groupUin ?: error("cannot find groupUin") override val uin: Long get() = delegate.groupUin ?: error("cannot find groupUin")
override val owner: Long get() = delegate.groupOwner ?: error("cannot find groupOwner") override val owner: Long get() = delegate.groupOwner ?: error("cannot find groupOwner")
override val groupCode: Long get() = Group.calculateGroupCodeByGroupUin(uin) override val groupCode: Long get() = Group.calculateGroupCodeByGroupUin(uin)

View File

@ -35,11 +35,8 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.proto.TroopTips0x857
import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildResponseUniPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.buildResponseUniPacket
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.MsgType0x210
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.onlinePush0x210.OnlinePush0x210Factory
import net.mamoe.mirai.qqandroid.utils.io.JceStruct import net.mamoe.mirai.qqandroid.utils.io.JceStruct
import net.mamoe.mirai.qqandroid.utils.io.readString import net.mamoe.mirai.qqandroid.utils.io.readString
import net.mamoe.mirai.qqandroid.utils.io.serialization.*
import net.mamoe.mirai.qqandroid.utils.io.serialization.decodeUniPacket import net.mamoe.mirai.qqandroid.utils.io.serialization.decodeUniPacket
import net.mamoe.mirai.qqandroid.utils.io.serialization.jce.JceId import net.mamoe.mirai.qqandroid.utils.io.serialization.jce.JceId
import net.mamoe.mirai.qqandroid.utils.io.serialization.jceRequestSBuffer import net.mamoe.mirai.qqandroid.utils.io.serialization.jceRequestSBuffer
@ -310,7 +307,14 @@ internal class OnlinePush {
} }
0x10 -> { 0x10 -> {
val dataBytes = this.readBytes(26) val dataBytes = this.readBytes(26)
val message = this.readString(this.readByte().toInt()) val size = this.readByte().toInt() // orthodox, don't `readUByte`
if (size < 0) {
error(
"negative array size: $size, remaining bytes=${this.readBytes()
.toUHexString()}"
)
}
val message = this.readString(size)
// println(dataBytes.toUHexString()) // println(dataBytes.toUHexString())
if (dataBytes[0].toInt() != 59) { if (dataBytes[0].toInt() != 59) {

View File

@ -9,7 +9,7 @@ internal object ByteArrayPool : DefaultPool<ByteArray>(256) {
/** /**
* 每一个 [ByteArray] 的大小 * 每一个 [ByteArray] 的大小
*/ */
const val BUFFER_SIZE: Int = 81920 / 2 const val BUFFER_SIZE: Int = 8192000
override fun produceInstance(): ByteArray = ByteArray(BUFFER_SIZE) override fun produceInstance(): ByteArray = ByteArray(BUFFER_SIZE)

View File

@ -150,8 +150,8 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
suspend fun doInit() { suspend fun doInit() {
tryNTimesOrException(2) { tryNTimesOrException(2) {
if (it != 0) { if (it != 0) {
delay(3000)
logger.warning("Init failed. Retrying in 3s...") logger.warning("Init failed. Retrying in 3s...")
delay(3000)
} }
_network.init() _network.init()
}?.let { }?.let {