music: correctly bubble exceptions

Correctly bubble failures in the music loading process.

Do it the easy way and simply map to a result, then backl to an
exception. I need to actually just make it fully bubble event
This commit is contained in:
Alexander Capehart 2023-04-15 17:59:29 -06:00
parent 89d599ae4e
commit b031adabeb
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47

View file

@ -23,17 +23,10 @@ import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.content.ContextCompat
import kotlinx.coroutines.*
import java.util.LinkedList
import javax.inject.Inject
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.yield
import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.cache.CacheRepository
@ -44,6 +37,8 @@ import org.oxycblt.auxio.music.storage.MediaStoreExtractor
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logE
import org.oxycblt.auxio.util.logW
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
/**
* Core music loading state class.
@ -351,14 +346,15 @@ constructor(
// Do the initial query of the cache and media databases in parallel.
logD("Starting queries")
val mediaStoreQueryJob = scope.async { mediaStoreExtractor.query() }
val mediaStoreQueryJob = scope.tryAsync { mediaStoreExtractor.query() }
val cache =
if (withCache) {
cacheRepository.readCache()
} else {
null
}
val query = mediaStoreQueryJob.await()
// TODO: Stupid, actually bubble results properly
val query = mediaStoreQueryJob.await().getOrThrow()
// Now start processing the queried song information in parallel. Songs that can't be
// received from the cache are consisted incomplete and pushed to a separate channel
@ -367,10 +363,10 @@ constructor(
val completeSongs = Channel<RawSong>(Channel.UNLIMITED)
val incompleteSongs = Channel<RawSong>(Channel.UNLIMITED)
val mediaStoreJob =
scope.async {
scope.tryAsync {
mediaStoreExtractor.consume(query, cache, incompleteSongs, completeSongs)
}
val metadataJob = scope.async { tagExtractor.consume(incompleteSongs, completeSongs) }
val metadataJob = scope.tryAsync { tagExtractor.consume(incompleteSongs, completeSongs) }
// Await completed raw songs as they are processed.
val rawSongs = LinkedList<RawSong>()
@ -379,8 +375,8 @@ constructor(
emitIndexing(Indexer.Indexing.Songs(rawSongs.size, query.projectedTotal))
}
// These should be no-ops
mediaStoreJob.await()
metadataJob.await()
mediaStoreJob.await().getOrThrow()
metadataJob.await().getOrThrow()
if (rawSongs.isEmpty()) {
logE("Music library was empty")
@ -391,11 +387,19 @@ constructor(
// parallel.
logD("Discovered ${rawSongs.size} songs, starting finalization")
emitIndexing(Indexer.Indexing.Indeterminate)
val libraryJob = scope.async(Dispatchers.Main) { Library.from(rawSongs, musicSettings) }
val libraryJob = scope.tryAsync(Dispatchers.Main) { Library.from(rawSongs, musicSettings) }
if (cache == null || cache.invalidated) {
cacheRepository.writeCache(rawSongs)
}
return libraryJob.await()
return libraryJob.await().getOrThrow()
}
private inline fun <R> CoroutineScope.tryAsync(context: CoroutineContext = EmptyCoroutineContext, crossinline block: suspend () -> R) = async(context) {
try {
Result.success(block())
} catch (e: Exception) {
Result.failure(e)
}
}
/**