Commit ce3ba66d authored by Him188's avatar Him188

Faster init: saved 200ms for each load

parent 44cdbf8a
...@@ -33,6 +33,8 @@ import net.mamoe.mirai.utils.* ...@@ -33,6 +33,8 @@ import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.io.* import net.mamoe.mirai.utils.io.*
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.jvm.Volatile import kotlin.jvm.Volatile
import kotlin.time.ExperimentalTime
import kotlin.time.measureTime
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
@UseExperimental(MiraiInternalAPI::class) @UseExperimental(MiraiInternalAPI::class)
...@@ -106,8 +108,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -106,8 +108,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
StatSvc.Register(bot.client).sendAndExpect<StatSvc.Register.Response>(6000) // it's slow StatSvc.Register(bot.client).sendAndExpect<StatSvc.Register.Response>(6000) // it's slow
} }
@UseExperimental(MiraiExperimentalAPI::class) @UseExperimental(MiraiExperimentalAPI::class, ExperimentalTime::class)
override suspend fun init() { override suspend fun init(): Unit = coroutineScope {
this@QQAndroidBotNetworkHandler.subscribeAlways<ForceOfflineEvent> { this@QQAndroidBotNetworkHandler.subscribeAlways<ForceOfflineEvent> {
if (this@QQAndroidBotNetworkHandler.bot == this.bot) { if (this@QQAndroidBotNetworkHandler.bot == this.bot) {
this.bot.logger.error("被挤下线") this.bot.logger.error("被挤下线")
...@@ -117,102 +119,106 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -117,102 +119,106 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect() MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect()
//val msg = MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect<MessageSvc.PbGetMsg.Response>()
//println(msg.contentToString())
bot.qqs.delegate.clear() bot.qqs.delegate.clear()
bot.groups.delegate.clear() bot.groups.delegate.clear()
val startTime = currentTimeMillis val friendListLoadTime = async {
try { measureTime {
bot.logger.info("开始加载好友信息") try {
var currentFriendCount = 0 bot.logger.info("开始加载好友信息")
var totalFriendCount: Short var currentFriendCount = 0
while (true) { var totalFriendCount: Short
val data = FriendList.GetFriendGroupList( while (true) {
bot.client, val data = FriendList.GetFriendGroupList(
currentFriendCount, bot.client,
150, currentFriendCount,
0, 150,
0 0,
).sendAndExpect<FriendList.GetFriendGroupList.Response>(timeoutMillis = 5000, retry = 2) 0
).sendAndExpect<FriendList.GetFriendGroupList.Response>(timeoutMillis = 5000, retry = 2)
totalFriendCount = data.totalFriendCount
data.friendList.forEach { totalFriendCount = data.totalFriendCount
// atomic add data.friendList.forEach {
bot.qqs.delegate.addLast(QQImpl(bot, bot.coroutineContext, it.friendUin)).also { // atomic add
currentFriendCount++ bot.qqs.delegate.addLast(QQImpl(bot, bot.coroutineContext, it.friendUin)).also {
currentFriendCount++
}
}
bot.logger.verbose("正在加载好友列表 ${currentFriendCount}/${totalFriendCount}")
if (currentFriendCount >= totalFriendCount) {
break
}
// delay(200)
} }
bot.logger.info("好友列表加载完成, 共 ${currentFriendCount}个")
} catch (e: Exception) {
bot.logger.error("加载好友列表失败|一般这是由于加载过于频繁导致/将以热加载方式加载好友列表")
} }
bot.logger.verbose("正在加载好友列表 ${currentFriendCount}/${totalFriendCount}")
if (currentFriendCount >= totalFriendCount) {
break
}
// delay(200)
} }
bot.logger.info("好友列表加载完成, 共 ${currentFriendCount}个")
} catch (e: Exception) {
bot.logger.error("加载好友列表失败|一般这是由于加载过于频繁导致/将以热加载方式加载好友列表")
} }
val friendLoadFinish = currentTimeMillis
val groupInfo = mutableMapOf<Long, Int>() val groupInfo = mutableMapOf<Long, Int>()
coroutineScope {
try { val groupTime = async {
bot.logger.info("开始加载群组列表与群成员列表") measureTime {
val troopListData = FriendList.GetTroopListSimplify(bot.client) try {
.sendAndExpect<FriendList.GetTroopListSimplify.Response>(timeoutMillis = 5000, retry = 2) bot.logger.info("开始加载群组列表与群成员列表")
// println("获取到群数量" + troopData.groups.size) val troopListData = FriendList.GetTroopListSimplify(bot.client)
val toGet: MutableMap<GroupImpl, ContactList<Member>> = mutableMapOf() .sendAndExpect<FriendList.GetTroopListSimplify.Response>(timeoutMillis = 5000, retry = 2)
troopListData.groups.forEach { troopNum -> // println("获取到群数量" + troopData.groups.size)
val contactList = ContactList(LockFreeLinkedList<Member>()) val toGet: MutableMap<GroupImpl, ContactList<Member>> = mutableMapOf()
val groupInfoResponse = try { troopListData.groups.forEach { troopNum ->
TroopManagement.GetGroupOperationInfo( val contactList = ContactList(LockFreeLinkedList<Member>())
client = bot.client, val groupInfoResponse = try {
groupCode = troopNum.groupCode TroopManagement.GetGroupOperationInfo(
).sendAndExpect<TroopManagement.GetGroupOperationInfo.Response>() client = bot.client,
} catch (e: Exception) { groupCode = troopNum.groupCode
bot.logger.info("获取" + troopNum.groupCode + "的群设置失败") ).sendAndExpect<TroopManagement.GetGroupOperationInfo.Response>()
TroopManagement.GetGroupOperationInfo.Response(
allowAnonymousChat = false,
allowMemberInvite = false,
autoApprove = false,
confessTalk = false
)
}
val group =
GroupImpl(
bot = bot,
coroutineContext = bot.coroutineContext,
id = troopNum.groupCode,
uin = troopNum.groupUin,
_name = troopNum.groupName,
_announcement = troopNum.groupMemo,
_allowMemberInvite = groupInfoResponse.allowMemberInvite,
_confessTalk = groupInfoResponse.confessTalk,
_muteAll = troopNum.dwShutUpTimestamp != 0L,
_autoApprove = groupInfoResponse.autoApprove,
_anonymousChat = groupInfoResponse.allowAnonymousChat,
members = contactList
)
toGet[group] = contactList
bot.groups.delegate.addLast(group)
launch {
try {
getTroopMemberList(group, contactList, troopNum.dwGroupOwnerUin)
groupInfo[troopNum.groupCode] = contactList.size
} catch (e: Exception) { } catch (e: Exception) {
groupInfo[troopNum.groupCode] = -1 bot.logger.info("获取" + troopNum.groupCode + "的群设置失败")
bot.logger.info("群${troopNum.groupCode}的列表拉取失败, 将采用动态加入") TroopManagement.GetGroupOperationInfo.Response(
bot.logger.error(e) allowAnonymousChat = false,
allowMemberInvite = false,
autoApprove = false,
confessTalk = false
)
}
val group =
GroupImpl(
bot = bot,
coroutineContext = bot.coroutineContext,
id = troopNum.groupCode,
uin = troopNum.groupUin,
_name = troopNum.groupName,
_announcement = troopNum.groupMemo,
_allowMemberInvite = groupInfoResponse.allowMemberInvite,
_confessTalk = groupInfoResponse.confessTalk,
_muteAll = troopNum.dwShutUpTimestamp != 0L,
_autoApprove = groupInfoResponse.autoApprove,
_anonymousChat = groupInfoResponse.allowAnonymousChat,
members = contactList
)
toGet[group] = contactList
bot.groups.delegate.addLast(group)
launch {
try {
fillTroopMemberList(group, contactList, troopNum.dwGroupOwnerUin)
groupInfo[troopNum.groupCode] = contactList.size
} catch (e: Exception) {
groupInfo[troopNum.groupCode] = -1
bot.logger.warning("群${troopNum.groupCode}的列表拉取失败, 将采用动态加入")
bot.logger.error(e)
}
} }
} }
bot.logger.info("群组列表与群成员加载完成, 共 ${troopListData.groups.size}个")
} catch (e: Exception) {
bot.logger.error("加载组信息失败|一般这是由于加载过于频繁导致/将以热加载方式加载群列表")
bot.logger.error(e)
} }
bot.logger.info("群组列表与群成员加载完成, 共 ${troopListData.groups.size}个")
} catch (e: Exception) {
bot.logger.error("加载组信息失败|一般这是由于加载过于频繁导致/将以热加载方式加载群列表")
bot.logger.error(e)
} }
} }
//===log===// //===log===//
fun fillUntil(long: Number, size: Int): String { fun fillUntil(long: Number, size: Int): String {
val x = long.toString() val x = long.toString()
...@@ -225,9 +231,11 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -225,9 +231,11 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
) )
} }
joinAll(friendListLoadTime, groupTime)
bot.logger.info("====================Mirai Bot List初始化完毕====================") bot.logger.info("====================Mirai Bot List初始化完毕====================")
bot.logger.info("好友数量: ${fillUntil(bot.qqs.size, 9)}\t\t\t 加载时间: ${friendLoadFinish - startTime}ms") bot.logger.info("好友数量: ${fillUntil(bot.qqs.size, 9)}\t\t\t 加载时间: ${friendListLoadTime.await().inMilliseconds}ms")
bot.logger.info("加入群组: ${fillUntil(bot.groups.size, 9)}\t\t\t 加载时间: ${currentTimeMillis - friendLoadFinish}ms") bot.logger.info("加入群组: ${fillUntil(bot.groups.size, 9)}\t\t\t 加载时间: ${groupTime.await().inMilliseconds}ms")
groupInfo.forEach { groupInfo.forEach {
if (it.value == -1) { if (it.value == -1) {
bot.logger.error("群组号码: ${fillUntil(it.key, 9)}\t 成员数量加载失败") bot.logger.error("群组号码: ${fillUntil(it.key, 9)}\t 成员数量加载失败")
...@@ -242,34 +250,40 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -242,34 +250,40 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
} }
bot.logger.info("====================Mirai Bot List初始化完毕====================") bot.logger.info("====================Mirai Bot List初始化完毕====================")
bot.firstLoginSucceed = true this@QQAndroidBotNetworkHandler.launch(CoroutineName("Heartbeat")) {
launch {
while (this.isActive) { while (this.isActive) {
delay(bot.configuration.heartbeatPeriodMillis) delay(bot.configuration.heartbeatPeriodMillis)
var lastException: Exception? val failException = doHeartBeat()
try { if (failException != null) {
check( delay(bot.configuration.firstReconnectDelayMillis)
StatSvc.GetOnlineStatus(bot.client) close()
.sendAndExpect<StatSvc.GetOnlineStatus.Response>( bot.tryReinitializeNetworkHandler(failException)
timeoutMillis = bot.configuration.heartbeatTimeoutMillis,
retry = 1
) is StatSvc.GetOnlineStatus.Response.Success
)
continue
} catch (e: Exception) {
lastException = e
} }
delay(bot.configuration.firstReconnectDelayMillis)
close()
bot.tryReinitializeNetworkHandler(lastException)
} }
} }
bot.firstLoginSucceed = true
} }
suspend fun doHeartBeat(): Exception? {
var lastException: Exception?
try {
check(
StatSvc.GetOnlineStatus(bot.client)
.sendAndExpect<StatSvc.GetOnlineStatus.Response>(
timeoutMillis = bot.configuration.heartbeatTimeoutMillis,
retry = 1
) is StatSvc.GetOnlineStatus.Response.Success
)
return null
} catch (e: Exception) {
lastException = e
}
return lastException
}
suspend fun getTroopMemberList(group: GroupImpl, list: ContactList<Member>, owner: Long): ContactList<Member> { suspend fun fillTroopMemberList(group: GroupImpl, list: ContactList<Member>, owner: Long) {
bot.logger.info("开始获取群[${group.uin}]成员列表") bot.logger.verbose("开始获取群[${group.uin}]成员列表")
var size = 0 var size = 0
var nextUin = 0L var nextUin = 0L
while (true) { while (true) {
...@@ -306,10 +320,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -306,10 +320,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
if (nextUin == 0L) { if (nextUin == 0L) {
break break
} }
//println("已获取群[${group.uin}]成员列表前" + size + "个成员")
} }
//println("群[${group.uin}]成员全部获取完成, 共${list.size}个成员")
return list
} }
/** /**
...@@ -473,7 +484,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -473,7 +484,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
cachedPacketTimeoutJob = launch { cachedPacketTimeoutJob = launch {
delay(1000) delay(1000)
if (cachedPacketTimeoutJob == this.coroutineContext[Job] && cachedPacket.getAndSet(null) != null) { if (cachedPacketTimeoutJob == this.coroutineContext[Job] && cachedPacket.getAndSet(null) != null) {
PacketLogger.verbose("等待另一部分包时超时. 将舍弃已接收的半个包") PacketLogger.verbose { "等待另一部分包时超时. 将舍弃已接收的半个包" }
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment