All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.CaptureProgress.kt Maven / Gradle / Ivy

package opensavvy.state.coroutines

import kotlinx.coroutines.channels.ProducerScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.withContext
import opensavvy.logger.Logger.Companion.warn
import opensavvy.logger.loggerFor
import opensavvy.progress.Progress
import opensavvy.progress.coroutines.CoroutineProgressReporter
import opensavvy.state.outcome.Outcome
import opensavvy.state.outcome.failed
import opensavvy.state.progressive.ProgressiveOutcome
import opensavvy.state.progressive.withProgress

private fun  ProducerScope>.progressExtractor() = CoroutineProgressReporter {
    if (it is Progress.Loading) {
        val result = trySend(ProgressiveOutcome.Incomplete(it))

        if (result.isFailure) {
            loggerFor(this).warn(
                it,
                result
            ) { "Could not send the progression event to the channel, it has been ignored" }
        }
    }
    // else: the action has reported that it's over, but the results haven't reached us yet, they'll probably
    //       arrive just afterward
}

/**
 * Captures the progress information of the current operation using [CoroutineProgressReporter].
 *
 * Because flows cannot emit from multiple coroutines, the implementation of this function requires the usage
 * of channels, which are more expensive.
 * If possible, prefer using the [failed] builder.
 */
// TODO in #145: Rewrite on top of Progress' captureProgress
@Suppress("RemoveExplicitTypeArguments") // IDEA bug, they are necessary here
fun  Flow>.captureProgress(): Flow> = channelFlow {
    this@captureProgress
        .flowOn(progressExtractor())
        .map { it.withProgress() }
        .onEach { send(it) }
        .collect()
}.buffer(1)

/**
 * Captures the progress information of [block] using [CoroutineProgressReporter].
 *
 * Because flows cannot emit from multiple coroutines, the implementation of this function requires the usage
 * of channels, which are more expensive.
 * If possible, prefer using the [failed] builder.
 */
// TODO in #145: Rewrite on top of Progress' captureProgress
fun  captureProgress(block: suspend () -> Outcome): Flow> = channelFlow {
    withContext(progressExtractor()) {
        send(block().withProgress())
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy