This commit is contained in:
Him188 2020-02-19 10:59:29 +08:00
parent 12e62c8aee
commit 0ce0b336a1

View File

@ -88,8 +88,24 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
}.also { _packetReceiverJob = it } }.also { _packetReceiverJob = it }
} }
private fun startHeartbeatJobOrKill(cancelCause: CancellationException? = null): Job {
heartbeatJob?.cancel(cancelCause)
return this@QQAndroidBotNetworkHandler.launch(CoroutineName("Heartbeat")) {
while (this.isActive) {
delay(bot.configuration.heartbeatPeriodMillis)
val failException = doHeartBeat()
if (failException != null) {
delay(bot.configuration.firstReconnectDelayMillis)
close()
BotOfflineEvent.Dropped(bot).broadcast()
}
}
}
}
override suspend fun relogin() { override suspend fun relogin() {
heartbeatJob?.cancel() heartbeatJob?.cancel(CancellationException("relogin"))
if (::channel.isInitialized) { if (::channel.isInitialized) {
if (channel.isOpen) { if (channel.isOpen) {
kotlin.runCatching { kotlin.runCatching {
@ -100,13 +116,12 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
channel.close() channel.close()
} }
channel = PlatformSocket() channel = PlatformSocket()
// TODO: 2020/2/14 连接多个服务器 // TODO: 2020/2/14 连接多个服务器, #52
withTimeoutOrNull(3000) { withTimeoutOrNull(3000) {
channel.connect("113.96.13.208", 8080) channel.connect("113.96.13.208", 8080)
} ?: error("timeout connecting server") } ?: error("timeout connecting server")
startPacketReceiverJobOrKill(CancellationException("reconnect")) startPacketReceiverJobOrKill(CancellationException("reconnect"))
// logger.info("Trying login")
var response: WtLogin.Login.LoginPacketResponse = WtLogin.Login.SubCommand9(bot.client).sendAndExpect() var response: WtLogin.Login.LoginPacketResponse = WtLogin.Login.SubCommand9(bot.client).sendAndExpect()
mainloop@ while (true) { mainloop@ while (true) {
when (response) { when (response) {
@ -159,8 +174,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
registerClientOnline() registerClientOnline()
} }
private suspend fun registerClientOnline() { private suspend fun registerClientOnline(timeoutMillis: Long = 3000) {
StatSvc.Register(bot.client).sendAndExpect<StatSvc.Register.Response>() StatSvc.Register(bot.client).sendAndExpect<StatSvc.Register.Response>(timeoutMillis)
} }
// caches // caches
@ -176,19 +191,27 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
bot.groups.delegate.clear() bot.groups.delegate.clear()
val friendListJob = launch { val friendListJob = launch {
try { lateinit var loadFriends: suspend () -> Unit
// 不要用 fun, 不要 join declaration, 不要用 val, 编译失败警告
loadFriends = suspend loadFriends@{
logger.info("开始加载好友信息") logger.info("开始加载好友信息")
var currentFriendCount = 0 var currentFriendCount = 0
var totalFriendCount: Short var totalFriendCount: Short
while (true) { while (true) {
val data = FriendList.GetFriendGroupList( val data = runCatching {
bot.client, 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)
}.getOrElse {
logger.error("无法加载好友列表", it)
this@QQAndroidBotNetworkHandler.launch { delay(10.secondsToMillis); loadFriends() }
logger.error("稍后重试加载好友列表")
return@loadFriends
}
totalFriendCount = data.totalFriendCount totalFriendCount = data.totalFriendCount
data.friendList.forEach { data.friendList.forEach {
// atomic add // atomic add
@ -196,16 +219,16 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
currentFriendCount++ currentFriendCount++
} }
} }
logger.verbose("正在加载好友列表 ${currentFriendCount}/${totalFriendCount}") logger.verbose { "正在加载好友列表 ${currentFriendCount}/${totalFriendCount}" }
if (currentFriendCount >= totalFriendCount) { if (currentFriendCount >= totalFriendCount) {
break break
} }
// delay(200) // delay(200)
} }
logger.info("好友列表加载完成, 共 ${currentFriendCount}") logger.info { "好友列表加载完成, 共 ${currentFriendCount}" }
} catch (e: Exception) {
logger.error("加载好友列表失败|一般这是由于加载过于频繁导致/将以热加载方式加载好友列表")
} }
loadFriends()
} }
val groupJob = launch { val groupJob = launch {
@ -247,7 +270,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
)) ))
) )
}?.let { }?.let {
logger.error("${troopNum.groupCode}的列表拉取失败, 一段时间后将会重试") logger.error { "${troopNum.groupCode}的列表拉取失败, 一段时间后将会重试" }
logger.error(it) logger.error(it)
this@QQAndroidBotNetworkHandler.launch { this@QQAndroidBotNetworkHandler.launch {
delay(10_000) delay(10_000)
@ -260,27 +283,16 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
loadGroup() loadGroup()
} }
} }
logger.info("群组列表与群成员加载完成, 共 ${troopListData.groups.size}") logger.info { "群组列表与群成员加载完成, 共 ${troopListData.groups.size}" }
} catch (e: Exception) { } catch (e: Exception) {
logger.error("加载组信息失败|一般这是由于加载过于频繁导致/将以热加载方式加载群列表") logger.error { "加载组信息失败|一般这是由于加载过于频繁导致/将以热加载方式加载群列表" }
logger.error(e) logger.error(e)
} }
} }
heartbeatJob = startHeartbeatJobOrKill()
joinAll(friendListJob, groupJob) joinAll(friendListJob, groupJob)
heartbeatJob = this@QQAndroidBotNetworkHandler.launch(CoroutineName("Heartbeat")) {
while (this.isActive) {
delay(bot.configuration.heartbeatPeriodMillis)
val failException = doHeartBeat()
if (failException != null) {
delay(bot.configuration.firstReconnectDelayMillis)
close()
BotOfflineEvent.Dropped(bot).broadcast()
}
}
}
bot.firstLoginSucceed = true bot.firstLoginSucceed = true
_pendingEnabled.value = false _pendingEnabled.value = false
@ -288,10 +300,12 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
KnownPacketFactories.handleIncomingPacket(it as KnownPacketFactories.IncomingPacket<Packet>, bot, it.flag2, it.consumer) KnownPacketFactories.handleIncomingPacket(it as KnownPacketFactories.IncomingPacket<Packet>, bot, it.flag2, it.consumer)
} }
pendingIncomingPackets = null // release val list = pendingIncomingPackets
pendingIncomingPackets = null // release, help gc
list?.clear() // help gc
BotOnlineEvent(bot).broadcast() BotOnlineEvent(bot).broadcast()
Unit Unit // dont remove. can help type inference
} }
suspend fun doHeartBeat(): Exception? { suspend fun doHeartBeat(): Exception? {