diff --git a/composeApp/libs/lib-nuvio-engine-android-0.1.0.aar b/composeApp/libs/lib-nuvio-engine-android-0.1.1.aar similarity index 65% rename from composeApp/libs/lib-nuvio-engine-android-0.1.0.aar rename to composeApp/libs/lib-nuvio-engine-android-0.1.1.aar index 16dbe39b8..abd3606ec 100644 Binary files a/composeApp/libs/lib-nuvio-engine-android-0.1.0.aar and b/composeApp/libs/lib-nuvio-engine-android-0.1.1.aar differ diff --git a/composeApp/src/androidHostTest/kotlin/com/nuvio/app/features/p2p/P2pStreamingEngineAndroidTest.kt b/composeApp/src/androidHostTest/kotlin/com/nuvio/app/features/p2p/P2pStreamingEngineAndroidTest.kt index 393e18eaa..e9ebaad7f 100644 --- a/composeApp/src/androidHostTest/kotlin/com/nuvio/app/features/p2p/P2pStreamingEngineAndroidTest.kt +++ b/composeApp/src/androidHostTest/kotlin/com/nuvio/app/features/p2p/P2pStreamingEngineAndroidTest.kt @@ -89,4 +89,53 @@ class P2pStreamingEngineAndroidTest { ), ) } + + @Test + fun globalCachePressureDoesNotBecomeTerminalError() { + assertNull( + unexpectedTorrentError( + requestId = 0L, + eventTorrentId = null, + currentTorrentId = "torrent", + message = "disk cache budget is exceeded by protected torrent data", + fallbackMessage = "unknown", + ) + ) + } + + @Test + fun matchingUnsolicitedTorrentFailureBecomesTerminalError() { + assertEquals( + P2pStreamingState.Error("file write failed"), + unexpectedTorrentError( + requestId = 0L, + eventTorrentId = "torrent", + currentTorrentId = "torrent", + message = "file write failed", + fallbackMessage = "unknown", + ), + ) + } + + @Test + fun commandAndStaleTorrentFailuresAreIgnored() { + assertNull( + unexpectedTorrentError( + requestId = 9L, + eventTorrentId = "torrent", + currentTorrentId = "torrent", + message = "failed", + fallbackMessage = "unknown", + ) + ) + assertNull( + unexpectedTorrentError( + requestId = 0L, + eventTorrentId = "old-torrent", + currentTorrentId = "torrent", + message = "failed", + fallbackMessage = "unknown", + ) + ) + } } diff --git a/composeApp/src/androidMain/kotlin/com/nuvio/app/features/p2p/P2pStreamingEngine.android.kt b/composeApp/src/androidMain/kotlin/com/nuvio/app/features/p2p/P2pStreamingEngine.android.kt index b7523e666..2bd8066e3 100644 --- a/composeApp/src/androidMain/kotlin/com/nuvio/app/features/p2p/P2pStreamingEngine.android.kt +++ b/composeApp/src/androidMain/kotlin/com/nuvio/app/features/p2p/P2pStreamingEngine.android.kt @@ -73,6 +73,25 @@ internal fun unexpectedStreamStopError( ) } +internal fun unexpectedTorrentError( + requestId: Long, + eventTorrentId: String?, + currentTorrentId: String?, + message: String?, + fallbackMessage: String, +): P2pStreamingState.Error? { + if (requestId != 0L || + eventTorrentId == null || + currentTorrentId == null || + eventTorrentId != currentTorrentId + ) { + return null + } + return P2pStreamingState.Error( + message?.trim()?.takeIf(String::isNotEmpty) ?: fallbackMessage, + ) +} + actual object P2pStreamingEngine { private data class EngineConfigurationKey( val uploadEnabled: Boolean, @@ -517,16 +536,16 @@ actual object P2pStreamingEngine { if (engine !== activeEngine) return@collect when (event.type) { NuvioEventType.TorrentError -> { - if (event.requestId != 0L) return@collect - val terminalError = P2pStreamingState.Error( - event.message ?: localizedP2pUnknownTorrentError() - ) + val fallbackMessage = localizedP2pUnknownTorrentError() synchronized(lifecycleLock) { - if (engine !== activeEngine || - (event.torrentId != null && event.torrentId != currentTorrentId) - ) { - return@synchronized - } + if (engine !== activeEngine) return@synchronized + val terminalError = unexpectedTorrentError( + requestId = event.requestId, + eventTorrentId = event.torrentId, + currentTorrentId = currentTorrentId, + message = event.message, + fallbackMessage = fallbackMessage, + ) ?: return@synchronized streamGeneration += 1 statsJob?.cancel() statsJob = null