Commit fa211cab authored by Him188's avatar Him188

Fix retry when no Internet connection

parent ac6f411e
......@@ -39,6 +39,7 @@ 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
import net.mamoe.mirai.qqandroid.utils.io.useBytes
import net.mamoe.mirai.qqandroid.utils.retryCatching
......@@ -127,9 +128,9 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
while (isActive) {
try {
channel.connect(host, port)
channel.connect(coroutineContext + CoroutineName("Socket"), host, port)
break
} catch (e: NoRouteToHostException) {
} catch (e: SocketException) {
logger.warning { "No route to host (Mostly due to no Internet connection). Retrying in 3s..." }
delay(3000)
}
......
......@@ -33,10 +33,12 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.proto.CSDataHighwayHead
import net.mamoe.mirai.qqandroid.utils.ByteArrayPool
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.serialization.readProtoBuf
import net.mamoe.mirai.qqandroid.utils.io.withUse
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.copyAndClose
import kotlin.coroutines.EmptyCoroutineContext
@OptIn(MiraiInternalAPI::class, InternalSerializationApi::class)
@Suppress("SpellCheckingInspection")
......@@ -117,9 +119,9 @@ internal object HighwayHelper {
val socket = PlatformSocket()
while (client.bot.network.isActive) {
try {
socket.connect(serverIp, serverPort)
socket.connect(EmptyCoroutineContext, serverIp, serverPort)
break
} catch (e: NoRouteToHostException) {
} catch (e: SocketException) {
delay(3000)
}
}
......
......@@ -13,13 +13,14 @@ import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.Closeable
import kotlinx.io.errors.IOException
import net.mamoe.mirai.utils.Throws
import kotlin.coroutines.CoroutineContext
/**
* 多平台适配的 TCP Socket.
*/
internal expect class PlatformSocket() : Closeable {
@Throws(NoRouteToHostException::class)
suspend fun connect(serverHost: String, serverPort: Int)
@Throws(SocketException::class)
suspend fun connect(coroutineContext: CoroutineContext, serverHost: String, serverPort: Int)
/**
* @throws SendPacketInternalException
......
......@@ -27,7 +27,6 @@ import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic
@MiraiInternalAPI
internal inline fun <R> ByteReadPacket.useBytes(
n: Int = remaining.toInt(),//not that safe but adequate
block: (data: ByteArray, length: Int) -> R
......@@ -36,7 +35,6 @@ internal inline fun <R> ByteReadPacket.useBytes(
block(it, n)
}
@MiraiInternalAPI
internal inline fun ByteReadPacket.readPacketExact(
n: Int = remaining.toInt()//not that safe but adequate
): ByteReadPacket = this.readBytes(n).toReadPacket()
......
......@@ -21,6 +21,7 @@ import java.io.BufferedInputStream
import java.io.BufferedOutputStream
import java.net.Socket
import java.net.SocketException
import kotlin.coroutines.CoroutineContext
/**
* 多平台适配的 TCP Socket.
......@@ -81,7 +82,7 @@ internal actual class PlatformSocket : Closeable {
}
@OptIn(ExperimentalIoApi::class)
actual suspend fun connect(serverHost: String, serverPort: Int) {
actual suspend fun connect(coroutineContext: CoroutineContext, serverHost: String, serverPort: Int) {
withContext(Dispatchers.IO) {
socket = Socket(serverHost, serverPort)
readChannel = socket.getInputStream().buffered()
......@@ -92,4 +93,113 @@ internal actual class PlatformSocket : Closeable {
actual typealias NoRouteToHostException = java.net.NoRouteToHostException
actual typealias SocketException = SocketException
\ No newline at end of file
actual typealias SocketException = SocketException
// ktor aSocket
/*
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.qqandroid.utils
import io.ktor.network.selector.ActorSelectorManager
import io.ktor.network.sockets.*
import io.ktor.util.KtorExperimentalAPI
import io.ktor.utils.io.ByteReadChannel
import io.ktor.utils.io.ByteWriteChannel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.Closeable
import kotlinx.io.core.ExperimentalIoApi
import kotlinx.io.core.buildPacket
import kotlinx.io.errors.IOException
import net.mamoe.mirai.qqandroid.utils.io.useBytes
import java.net.InetSocketAddress
import java.net.SocketException
import kotlin.coroutines.CoroutineContext
/**
* 多平台适配的 TCP Socket.
*/
internal actual class PlatformSocket : Closeable {
private lateinit var socket: io.ktor.network.sockets.Socket
actual val isOpen: Boolean
get() =
if (::socket.isInitialized)
!socket.isClosed
else false
actual override fun close() {
if (::socket.isInitialized) {
socket.close()
}
}
@PublishedApi
internal lateinit var writeChannel: ByteWriteChannel
@PublishedApi
internal lateinit var readChannel: ByteReadChannel
actual suspend fun send(packet: ByteArray, offset: Int, length: Int) {
withContext(Dispatchers.IO) {
writeChannel.writeFully(packet, offset, length)
}
}
/**
* @throws SendPacketInternalException
*/
actual suspend fun send(packet: ByteReadPacket) {
withContext(Dispatchers.IO) {
try {
packet.useBytes { data: ByteArray, length: Int ->
writeChannel.writeFully(data, offset = 0, length = length)
}
} catch (e: IOException) {
throw SendPacketInternalException(e)
}
}
}
/**
* @throws ReadPacketInternalException
*/
actual suspend fun read(): ByteReadPacket {
return withContext(Dispatchers.IO) {
try {
buildPacket {
readChannel.read {
writeFully(it)
}
}
} catch (e: IOException) {
throw ReadPacketInternalException(e)
}
}
}
@OptIn(ExperimentalIoApi::class, KtorExperimentalAPI::class)
actual suspend fun connect(coroutineContext: CoroutineContext, serverHost: String, serverPort: Int) {
withContext(Dispatchers.IO) {
socket = aSocket(ActorSelectorManager(coroutineContext)).tcp().tcpNoDelay()
.connect(InetSocketAddress(serverHost, serverPort))
readChannel = socket.openReadChannel()
writeChannel = socket.openWriteChannel(true)
}
}
}
actual typealias NoRouteToHostException = java.net.NoRouteToHostException
actual typealias SocketException = SocketException
*/
\ No newline at end of file
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