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:
parent
89d599ae4e
commit
b031adabeb
1 changed files with 20 additions and 16 deletions
|
|
@ -23,17 +23,10 @@ import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import kotlinx.coroutines.*
|
||||||
import java.util.LinkedList
|
import java.util.LinkedList
|
||||||
import javax.inject.Inject
|
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.channels.Channel
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import kotlinx.coroutines.yield
|
|
||||||
import org.oxycblt.auxio.BuildConfig
|
import org.oxycblt.auxio.BuildConfig
|
||||||
import org.oxycblt.auxio.music.*
|
import org.oxycblt.auxio.music.*
|
||||||
import org.oxycblt.auxio.music.cache.CacheRepository
|
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.logD
|
||||||
import org.oxycblt.auxio.util.logE
|
import org.oxycblt.auxio.util.logE
|
||||||
import org.oxycblt.auxio.util.logW
|
import org.oxycblt.auxio.util.logW
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Core music loading state class.
|
* Core music loading state class.
|
||||||
|
|
@ -351,14 +346,15 @@ constructor(
|
||||||
|
|
||||||
// Do the initial query of the cache and media databases in parallel.
|
// Do the initial query of the cache and media databases in parallel.
|
||||||
logD("Starting queries")
|
logD("Starting queries")
|
||||||
val mediaStoreQueryJob = scope.async { mediaStoreExtractor.query() }
|
val mediaStoreQueryJob = scope.tryAsync { mediaStoreExtractor.query() }
|
||||||
val cache =
|
val cache =
|
||||||
if (withCache) {
|
if (withCache) {
|
||||||
cacheRepository.readCache()
|
cacheRepository.readCache()
|
||||||
} else {
|
} else {
|
||||||
null
|
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
|
// 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
|
// 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 completeSongs = Channel<RawSong>(Channel.UNLIMITED)
|
||||||
val incompleteSongs = Channel<RawSong>(Channel.UNLIMITED)
|
val incompleteSongs = Channel<RawSong>(Channel.UNLIMITED)
|
||||||
val mediaStoreJob =
|
val mediaStoreJob =
|
||||||
scope.async {
|
scope.tryAsync {
|
||||||
mediaStoreExtractor.consume(query, cache, incompleteSongs, completeSongs)
|
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.
|
// Await completed raw songs as they are processed.
|
||||||
val rawSongs = LinkedList<RawSong>()
|
val rawSongs = LinkedList<RawSong>()
|
||||||
|
|
@ -379,8 +375,8 @@ constructor(
|
||||||
emitIndexing(Indexer.Indexing.Songs(rawSongs.size, query.projectedTotal))
|
emitIndexing(Indexer.Indexing.Songs(rawSongs.size, query.projectedTotal))
|
||||||
}
|
}
|
||||||
// These should be no-ops
|
// These should be no-ops
|
||||||
mediaStoreJob.await()
|
mediaStoreJob.await().getOrThrow()
|
||||||
metadataJob.await()
|
metadataJob.await().getOrThrow()
|
||||||
|
|
||||||
if (rawSongs.isEmpty()) {
|
if (rawSongs.isEmpty()) {
|
||||||
logE("Music library was empty")
|
logE("Music library was empty")
|
||||||
|
|
@ -391,11 +387,19 @@ constructor(
|
||||||
// parallel.
|
// parallel.
|
||||||
logD("Discovered ${rawSongs.size} songs, starting finalization")
|
logD("Discovered ${rawSongs.size} songs, starting finalization")
|
||||||
emitIndexing(Indexer.Indexing.Indeterminate)
|
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) {
|
if (cache == null || cache.invalidated) {
|
||||||
cacheRepository.writeCache(rawSongs)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue