refactor(network): remove unused addon probe targets

This commit is contained in:
tapframe 2026-05-28 18:44:22 +05:30
parent b3640d5280
commit f33a513b1c
2 changed files with 48 additions and 43 deletions

View file

@ -103,7 +103,6 @@ import com.nuvio.app.core.ui.isLiquidGlassNativeTabBarSupported
import com.nuvio.app.core.ui.localizedContinueWatchingSubtitle
import com.nuvio.app.features.auth.AuthScreen
import com.nuvio.app.features.addons.AddonRepository
import com.nuvio.app.features.addons.enabledAddons
import com.nuvio.app.features.catalog.CatalogRepository
import com.nuvio.app.features.catalog.CatalogScreen
import com.nuvio.app.features.catalog.INTERNAL_LIBRARY_MANIFEST_URL
@ -621,14 +620,6 @@ private fun MainAppContent(
var networkToastBaselineReady by rememberSaveable { mutableStateOf(false) }
var lastNetworkToastCondition by rememberSaveable { mutableStateOf(NetworkCondition.Unknown.name) }
val addonProbeTargets = remember(addonsUiState.addons) {
addonsUiState.addons
.enabledAddons()
.mapNotNull { it.manifest?.transportUrl }
.distinct()
.sorted()
}
fun handleRootTabClick(tab: AppScreenTab) {
if (selectedTab != tab) {
selectedTab = tab
@ -694,13 +685,9 @@ private fun MainAppContent(
initialHomeReady = true
}
LaunchedEffect(addonProbeTargets) {
NetworkStatusRepository.updateAddonProbeTargets(addonProbeTargets)
}
LaunchedEffect(Unit) {
AppForegroundMonitor.events().collect {
NetworkStatusRepository.requestRefresh(force = true)
NetworkStatusRepository.requestForegroundRefresh()
}
}

View file

@ -3,7 +3,9 @@ package com.nuvio.app.core.network
import com.nuvio.app.features.addons.httpRequestRaw
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@ -44,6 +46,8 @@ fun NetworkCondition.messageForEmptyState(): String =
object NetworkStatusRepository {
private const val REQUEST_TIMEOUT_MS = 4_500L
private const val FOREGROUND_REFRESH_DELAY_MS = 6_000L
private const val FOREGROUND_FAILURE_CONFIRM_DELAY_MS = 2_000L
private const val PUBLIC_PROBE_PRIMARY = "https://www.gstatic.com/generate_204"
private const val PUBLIC_PROBE_FALLBACK = "https://cloudflare.com/cdn-cgi/trace"
@ -54,7 +58,8 @@ object NetworkStatusRepository {
private var started = false
private var probeInFlight = false
private var pendingProbeAfterCurrent = false
private var addonProbeTargets: List<String> = emptyList()
private var pendingProbeConfirmFailures = false
private var foregroundRefreshJob: Job? = null
fun ensureStarted() {
if (started) return
@ -62,42 +67,62 @@ object NetworkStatusRepository {
requestRefresh(force = true)
}
fun updateAddonProbeTargets(urls: List<String>) {
val normalized = urls
.map { it.trim() }
.filter { it.isNotBlank() }
.distinct()
if (normalized == addonProbeTargets) return
addonProbeTargets = normalized
requestRefresh(force = true)
fun requestForegroundRefresh() {
ensureStarted()
foregroundRefreshJob?.cancel()
foregroundRefreshJob = scope.launch {
delay(FOREGROUND_REFRESH_DELAY_MS)
requestRefresh(force = true, confirmFailures = true)
}
}
fun requestRefresh(force: Boolean = false) {
ensureStarted()
fun requestRefresh(force: Boolean = false, confirmFailures: Boolean = false) {
if (!started) started = true
if (probeInFlight) {
if (force) pendingProbeAfterCurrent = true
if (force) {
pendingProbeAfterCurrent = true
pendingProbeConfirmFailures = pendingProbeConfirmFailures || confirmFailures
}
return
}
scope.launch {
var nextConfirmFailures = confirmFailures
do {
val runConfirmFailures = nextConfirmFailures || pendingProbeConfirmFailures
nextConfirmFailures = false
pendingProbeAfterCurrent = false
pendingProbeConfirmFailures = false
probeInFlight = true
runProbe()
runProbe(confirmFailures = runConfirmFailures)
probeInFlight = false
} while (pendingProbeAfterCurrent)
}
}
private suspend fun runProbe() {
private suspend fun runProbe(confirmFailures: Boolean) {
if (_uiState.value.condition == NetworkCondition.Unknown) {
_uiState.value = NetworkStatusUiState(condition = NetworkCondition.Checking)
}
val previousCondition = _uiState.value.condition
var nextCondition = probeCondition()
if (
confirmFailures &&
previousCondition == NetworkCondition.Online &&
nextCondition.isOfflineLike()
) {
delay(FOREGROUND_FAILURE_CONFIRM_DELAY_MS)
nextCondition = probeCondition()
}
_uiState.value = NetworkStatusUiState(condition = nextCondition)
}
private suspend fun probeCondition(): NetworkCondition {
val internetReachable = probePublicInternet()
if (!internetReachable) {
_uiState.value = NetworkStatusUiState(condition = NetworkCondition.NoInternet)
return
return NetworkCondition.NoInternet
}
val supabaseReachable = probeReachable(
@ -105,20 +130,10 @@ object NetworkStatusRepository {
headers = mapOf("apikey" to SupabaseConfig.ANON_KEY),
)
if (!supabaseReachable) {
_uiState.value = NetworkStatusUiState(condition = NetworkCondition.ServersUnreachable)
return
return NetworkCondition.ServersUnreachable
}
val addonTarget = addonProbeTargets.firstOrNull()
if (addonTarget != null) {
val addonReachable = probeReachable(url = addonTarget)
if (!addonReachable) {
_uiState.value = NetworkStatusUiState(condition = NetworkCondition.ServersUnreachable)
return
}
}
_uiState.value = NetworkStatusUiState(condition = NetworkCondition.Online)
return NetworkCondition.Online
}
private suspend fun probePublicInternet(): Boolean =
@ -141,4 +156,7 @@ object NetworkStatusRepository {
return response.status in 100..599
}
}
private fun NetworkCondition.isOfflineLike(): Boolean =
this == NetworkCondition.NoInternet || this == NetworkCondition.ServersUnreachable
}