Clean up code

Signed-off-by: denis0001-dev <denis0001.dev@ya.ru>
This commit is contained in:
2026-07-16 22:08:37 +03:00
Unverified
parent 23f668c07d
commit c53befe4b9
@@ -3,11 +3,12 @@ package ru.fromchat.api.instance
import kotlinx.coroutines.withTimeout
import ru.fromchat.api.ApiClient
import ru.fromchat.api.local.WebSocketManager
import ru.fromchat.api.local.db.store.InstanceRegistryStore
import ru.fromchat.config.ServerConfigData
import ru.fromchat.api.local.cache.CacheContext
import ru.fromchat.api.local.db.store.InstanceRegistryStore
import ru.fromchat.config.ServerConfig
import ru.fromchat.config.ServerConfigData
import ru.fromchat.legal.DocumentRepository
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.TimeSource
sealed interface ServerProbeResult {
@@ -51,20 +52,26 @@ fun Throwable.isSslProtocolError(): Boolean {
return false
}
suspend fun probeCallsReachable(config: ServerConfigData): Boolean {
val urlScheme = if (config.httpsEnabled) "https" else "http"
val host = config.serverIp.trim()
val authorityHost = host.removePrefix("[").removeSuffix("]").ifEmpty { host }
// Caddy rewrites this to LiveKit "/" (plain "OK"). GET /rtc is always 404 without a WS upgrade.
val url = "$urlScheme://$authorityHost:${config.apiPort}/livekit-health"
return runCatching {
withTimeout(CALLS_PROBE_MS) {
ApiClient.probeHttpGet(url)
suspend fun probeCallsReachable(config: ServerConfigData) = runCatching {
withTimeout(CALLS_PROBE_MS.milliseconds) {
ApiClient.probeHttpGet(
buildString {
append(if (config.httpsEnabled) "https" else "http")
append("://")
append(
config.serverIp.trim().let {
it.removePrefix("[").removeSuffix("]").ifEmpty { it }
}
}.getOrDefault(false)
}
)
append(":")
append(config.apiPort)
append("/livekit-health")
}
)
}
}.getOrDefault(false)
suspend fun probeServer(config: ServerConfigData): ServerProbeResult =
suspend fun probeServer(config: ServerConfigData) =
probeServerEndpoint(
host = config.serverIp,
port = config.apiPort,
@@ -82,44 +89,51 @@ suspend fun probeServerEndpoint(
httpsPreferred: Boolean,
schemeExplicit: Boolean,
): Pair<ServerConfigData, ServerProbeResult> {
val schemes = when {
schemeExplicit -> listOf(httpsPreferred)
else -> listOf(true, false)
}
var lastConfig = ServerConfigData(
serverIp = host,
apiPort = port,
callsPort = port,
httpsEnabled = httpsPreferred,
)
var lastResult: ServerProbeResult = ServerProbeResult.Unreachable
for ((index, https) in schemes.withIndex()) {
when {
schemeExplicit -> listOf(httpsPreferred)
else -> listOf(true, false)
}.apply {
forEachIndexed { index, https ->
val config = ServerConfigData(
serverIp = host,
apiPort = port,
callsPort = port,
httpsEnabled = https,
)
lastConfig = config
val (result, failure) = probeServerOnce(config)
lastResult = result
when (result) {
is ServerProbeResult.Supported,
ServerProbeResult.Unsupported,
-> return config to result
ServerProbeResult.Unsupported -> return config to result
ServerProbeResult.Timeout,
ServerProbeResult.Unreachable,
-> {
val hasHttpFallback = !schemeExplicit && https && index < schemes.lastIndex
if (!hasHttpFallback) return config to result
ServerProbeResult.Unreachable -> {
if (!(!schemeExplicit && https && index < lastIndex)) return config to result
// Browser-like: only fall back to HTTP after a TLS/protocol failure.
if (failure?.isSslProtocolError() == true) continue
if (result is ServerProbeResult.Timeout) return config to result
if (failure?.isSslProtocolError() == true)
return@forEachIndexed
if (result is ServerProbeResult.Timeout)
return config to result
// Non-SSL Unreachable (e.g. LAN cleartext / connection refused on 443): try HTTP.
continue
return@forEachIndexed
}
}
}
}
return lastConfig to lastResult
}
@@ -127,17 +141,21 @@ private suspend fun probeServerOnce(
config: ServerConfigData,
): Pair<ServerProbeResult, Throwable?> {
val apiBase = apiBaseUrlFor(config)
val mark = TimeSource.Monotonic.markNow()
val time = TimeSource.Monotonic.markNow()
InstanceIdGuard.probeConfig = config
try {
val pingMs = time.elapsedNow().inWholeMilliseconds.toInt().coerceAtLeast(0)
return ServerProbeResult.Supported(
when (
val resolve = resolveInstanceId(
config = config,
apiBaseUrl = apiBase,
forceNetwork = true,
allowCachedOnFailure = false,
)
val pingMs = mark.elapsedNow().inWholeMilliseconds.toInt().coerceAtLeast(0)
val instanceId = when (resolve) {
) {
is InstanceIdResolveResult.Cached -> resolve.instanceId
is InstanceIdResolveResult.Fetched -> resolve.instanceId
is InstanceIdResolveResult.InstanceIdChanged -> resolve.newId
@@ -151,9 +169,10 @@ private suspend fun probeServerOnce(
}.exceptionOrNull()
return ServerProbeResult.Unreachable to failure
}
}
val callsOk = probeCallsReachable(config)
return ServerProbeResult.Supported(instanceId, callsOk, pingMs) to null
},
probeCallsReachable(config),
pingMs
) to null
} finally {
InstanceIdGuard.probeConfig = null
}
@@ -182,13 +201,15 @@ suspend fun applyServerAndNavigate(
): ApplyServerResult {
val apiBase = apiBaseUrlFor(config)
val token = bearer.trim()
if (token.isEmpty()) {
applyServerConfig(config, probe.instanceId, probe.callsOk)
WebSocketManager.disconnect()
onNavigateLogin()
return ApplyServerResult.Applied
}
when (val auth = ApiClient.checkAuthAt(apiBase, token)) {
when (ApiClient.checkAuthAt(apiBase, token)) {
ApiClient.CheckAuthResult.Authenticated -> {
applyServerConfig(config, probe.instanceId, probe.callsOk)
WebSocketManager.disconnect()
@@ -196,9 +217,11 @@ suspend fun applyServerAndNavigate(
onNavigateChat()
return ApplyServerResult.Applied
}
ApiClient.CheckAuthResult.Unreachable -> {
return ApplyServerResult.ServerUnreachable
}
ApiClient.CheckAuthResult.NotAuthenticated -> {
onLogoutOldHost()
applyServerConfig(config, probe.instanceId, probe.callsOk)