mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-08-15 20:11:57 +00:00
refactor(network): remove unused addon probe targets
This commit is contained in:
parent
b3640d5280
commit
f33a513b1c
2 changed files with 48 additions and 43 deletions
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue