mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-02 04:30:25 +08:00
Fix #248
This commit is contained in:
parent
72fb82c01f
commit
d9135cb8a3
@ -37,6 +37,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.login.ConfigPushSvc
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.Heartbeat
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.StatSvc
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.WtLogin
|
||||
import net.mamoe.mirai.qqandroid.utils.NoRouteToHostException
|
||||
import net.mamoe.mirai.qqandroid.utils.PlatformSocket
|
||||
import net.mamoe.mirai.qqandroid.utils.SocketException
|
||||
import net.mamoe.mirai.qqandroid.utils.io.readPacketExact
|
||||
@ -130,8 +131,12 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
channel.connect(coroutineContext + CoroutineName("Socket"), host, port)
|
||||
break
|
||||
} catch (e: SocketException) {
|
||||
logger.warning { "No route to host (Mostly due to no Internet connection). Retrying in 3s..." }
|
||||
delay(3000)
|
||||
if (e is NoRouteToHostException || e.message?.contains("Network is unreachable") == true) {
|
||||
logger.warning { "No route to host (Mostly due to no Internet connection). Retrying in 3s..." }
|
||||
delay(3000)
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.info { "Connected to server $host:$port" }
|
||||
|
@ -126,11 +126,14 @@ internal open class QQAndroidClient(
|
||||
lateinit var fileStoragePushFSSvcList: FileStoragePushFSSvcListFuckKotlin
|
||||
|
||||
internal suspend inline fun useNextServers(crossinline block: suspend (host: String, port: Int) -> Unit) {
|
||||
if (bot.client.serverList.isEmpty()) {
|
||||
throw NoServerAvailableException(null)
|
||||
}
|
||||
retryCatching(bot.client.serverList.size, except = LoginFailedException::class) {
|
||||
val pair = bot.client.serverList.random()
|
||||
kotlin.runCatching {
|
||||
block(pair.first, pair.second)
|
||||
return
|
||||
return@retryCatching
|
||||
}.getOrElse {
|
||||
bot.client.serverList.remove(pair)
|
||||
bot.logger.warning(it)
|
||||
|
@ -24,7 +24,7 @@ internal expect fun Throwable.addSuppressedMirai(e: Throwable)
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "RESULT_CLASS_IN_RETURN_TYPE")
|
||||
@kotlin.internal.InlineOnly
|
||||
internal inline fun <R> retryCatching(n: Int, except: KClass<out Throwable>? = null, block: () -> R): Result<R> {
|
||||
require(n >= 0) { "param n for retryCatching must not be negative" }
|
||||
require(n > 0) { "param n for retryCatching must not be negative" }
|
||||
var exception: Throwable? = null
|
||||
repeat(n) {
|
||||
try {
|
||||
|
@ -107,25 +107,37 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
|
||||
}
|
||||
bot.logger.info { "Connection dropped by server or lost, retrying login" }
|
||||
|
||||
retryCatching(configuration.reconnectionRetryTimes,
|
||||
except = LoginFailedException::class) { tryCount, _ ->
|
||||
if (tryCount != 0) {
|
||||
delay(configuration.reconnectPeriodMillis)
|
||||
tailrec suspend fun reconnect() {
|
||||
retryCatching<Unit>(configuration.reconnectionRetryTimes,
|
||||
except = LoginFailedException::class) { tryCount, _ ->
|
||||
if (tryCount != 0) {
|
||||
delay(configuration.reconnectPeriodMillis)
|
||||
}
|
||||
network.withConnectionLock {
|
||||
/**
|
||||
* [BotImpl.relogin] only, no [BotNetworkHandler.init]
|
||||
*/
|
||||
@OptIn(ThisApiMustBeUsedInWithConnectionLockBlock::class)
|
||||
relogin((event as? BotOfflineEvent.Dropped)?.cause)
|
||||
}
|
||||
logger.info { "Reconnected successfully" }
|
||||
BotReloginEvent(bot, (event as? BotOfflineEvent.Dropped)?.cause).broadcast()
|
||||
return
|
||||
}.getOrElse {
|
||||
if (it is LoginFailedException && !it.killBot) {
|
||||
logger.info { "Cannot reconnect" }
|
||||
logger.warning(it)
|
||||
logger.info { "Retrying in 3s..." }
|
||||
delay(3000)
|
||||
return@getOrElse
|
||||
}
|
||||
logger.info { "Cannot reconnect" }
|
||||
throw it
|
||||
}
|
||||
network.withConnectionLock {
|
||||
/**
|
||||
* [BotImpl.relogin] only, no [BotNetworkHandler.init]
|
||||
*/
|
||||
@OptIn(ThisApiMustBeUsedInWithConnectionLockBlock::class)
|
||||
relogin((event as? BotOfflineEvent.Dropped)?.cause)
|
||||
}
|
||||
logger.info { "Reconnected successfully" }
|
||||
BotReloginEvent(bot, (event as? BotOfflineEvent.Dropped)?.cause).broadcast()
|
||||
return@subscribeAlways
|
||||
}.getOrElse {
|
||||
logger.info { "Cannot reconnect" }
|
||||
throw it
|
||||
reconnect()
|
||||
}
|
||||
|
||||
reconnect()
|
||||
}
|
||||
is BotOfflineEvent.Active -> {
|
||||
val msg = if (event.cause == null) {
|
||||
@ -158,7 +170,14 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
|
||||
relogin(null)
|
||||
return
|
||||
} catch (e: LoginFailedException) {
|
||||
throw e
|
||||
if (e.killBot) {
|
||||
throw e
|
||||
} else {
|
||||
logger.warning("Login failed. Retrying in 3s...")
|
||||
_network.closeAndJoin(e)
|
||||
delay(3000)
|
||||
continue
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
network.logger.error(e)
|
||||
_network.closeAndJoin(e)
|
||||
|
@ -17,35 +17,37 @@ import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||
/**
|
||||
* 在 [登录][Bot.login] 失败时抛出, 可正常地中断登录过程.
|
||||
*/
|
||||
sealed class LoginFailedException : RuntimeException {
|
||||
constructor() : super()
|
||||
constructor(message: String?) : super(message)
|
||||
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
constructor(cause: Throwable?) : super(cause)
|
||||
}
|
||||
sealed class LoginFailedException constructor(
|
||||
/**
|
||||
* 是否可因此登录失败而关闭 [Bot]. 一般是密码错误, 被冻结等异常时.
|
||||
*/
|
||||
val killBot: Boolean = false,
|
||||
message: String? = null,
|
||||
cause: Throwable? = null
|
||||
) : RuntimeException(message, cause)
|
||||
|
||||
/**
|
||||
* 密码输入错误
|
||||
*/
|
||||
class WrongPasswordException(message: String?) : LoginFailedException(message)
|
||||
class WrongPasswordException(message: String?) : LoginFailedException(true, message)
|
||||
|
||||
/**
|
||||
* 无可用服务器
|
||||
*/
|
||||
class NoServerAvailableException(override val cause: Throwable?) : LoginFailedException("no server available")
|
||||
class NoServerAvailableException(override val cause: Throwable?) : LoginFailedException(false, "no server available")
|
||||
|
||||
/**
|
||||
* 需要短信验证时抛出. mirai 目前还不支持短信验证.
|
||||
*/
|
||||
@MiraiExperimentalAPI
|
||||
class UnsupportedSMSLoginException(message: String?) : LoginFailedException(message)
|
||||
class UnsupportedSMSLoginException(message: String?) : LoginFailedException(true, message)
|
||||
|
||||
/**
|
||||
* 非 mirai 实现的异常
|
||||
*/
|
||||
abstract class CustomLoginFailedException : LoginFailedException {
|
||||
constructor() : super()
|
||||
constructor(message: String?) : super(message)
|
||||
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
constructor(cause: Throwable?) : super(cause)
|
||||
constructor(killBot: Boolean) : super(killBot)
|
||||
constructor(killBot: Boolean, message: String?) : super(killBot, message)
|
||||
constructor(killBot: Boolean, message: String?, cause: Throwable?) : super(killBot, message, cause)
|
||||
constructor(killBot: Boolean, cause: Throwable?) : super(killBot, cause = cause)
|
||||
}
|
Loading…
Reference in New Issue
Block a user