Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d0fe175b authored by Jonathan Klee's avatar Jonathan Klee
Browse files

fix: consider InterruptedIOException as Timeout also

parent b07033bb
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -27,9 +27,11 @@ import foundation.e.apps.data.playstore.utils.GplayHttpRequestException
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.delay
import timber.log.Timber
import java.io.InterruptedIOException
import java.net.SocketTimeoutException

private const val TIMEOUT = "Timeout"
private val TIMEOUT_MESSAGE_PATTERNS = listOf("timeout", "timed out")
private const val UNKNOWN = "Unknown"
private const val STATUS = "Status:"
private const val ERROR_GPLAY_API = "Gplay api has faced error!"
@@ -49,6 +51,8 @@ suspend fun <T> handleNetworkResult(call: suspend () -> T): ResultSupreme<T> {
        throw e
    } catch (e: SocketTimeoutException) {
        handleSocketTimeoutException(e)
    } catch (e: InterruptedIOException) {
        handleInterruptedIOException(e)
    } catch (e: GplayHttpRequestException) {
        resultSupremeGplayHttpRequestException(e)
    } catch (e: Exception) {
@@ -63,6 +67,16 @@ private fun <T> handleSocketTimeoutException(e: SocketTimeoutException): ResultS
    return resultTimeout
}

private fun <T> handleInterruptedIOException(e: InterruptedIOException): ResultSupreme<T> {
    return if (isTimeoutInterruptedIOException(e)) {
        val resultTimeout = ResultSupreme.Timeout<T>(exception = e)
        resultTimeout.message = extractErrorMessage(e)
        resultTimeout
    } else {
        handleOthersException(e)
    }
}

private fun <T> resultSupremeGplayHttpRequestException(e: GplayHttpRequestException): ResultSupreme<T> {
    val message = extractErrorMessage(e)
    val exception = GPlayException(e.status == GPlayHttpClient.STATUS_CODE_TIMEOUT, message)
@@ -83,12 +97,20 @@ private fun extractErrorMessage(e: Exception): String {
    val status = when (e) {
        is GplayHttpRequestException -> e.status.toString()
        is SocketTimeoutException -> TIMEOUT
        is InterruptedIOException -> if (isTimeoutInterruptedIOException(e)) TIMEOUT else UNKNOWN
        else -> UNKNOWN
    }

    return (e.localizedMessage?.ifBlank { ERROR_GPLAY_API } ?: ERROR_GPLAY_API) + " $STATUS $status"
}

private fun isTimeoutInterruptedIOException(e: InterruptedIOException): Boolean {
    val message = e.message ?: return true
    return TIMEOUT_MESSAGE_PATTERNS.any { pattern ->
        message.contains(pattern, ignoreCase = true)
    }
}

suspend fun <T> retryWithBackoff(retryDelayInSeconds: Int = -1, operation: suspend () -> T): T? {
    var result: T? = null
    try {
+34 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ import foundation.e.apps.data.playstore.utils.GplayHttpRequestException
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Test
import java.io.InterruptedIOException
import java.net.SocketTimeoutException

@OptIn(ExperimentalCoroutinesApi::class)
@@ -33,6 +34,39 @@ class NetworkHandlerTest {
        assertThat(result.exception).isSameInstanceAs(timeout)
    }

    @Test
    fun handleNetworkResult_convertsInterruptedTimeout() = runTest {
        val timeout = InterruptedIOException("timeout")

        val result = handleNetworkResult<String> { throw timeout }

        assertThat(result.isTimeout()).isTrue()
        assertThat(result.message).isEqualTo("timeout Status: Timeout")
        assertThat(result.exception).isSameInstanceAs(timeout)
    }

    @Test
    fun handleNetworkResult_convertsInterruptedTimedOutMessage() = runTest {
        val timeout = InterruptedIOException("Read timed out")

        val result = handleNetworkResult<String> { throw timeout }

        assertThat(result.isTimeout()).isTrue()
        assertThat(result.message).isEqualTo("Read timed out Status: Timeout")
        assertThat(result.exception).isSameInstanceAs(timeout)
    }

    @Test
    fun handleNetworkResult_mapsNonTimeoutInterruptedIoExceptionToError() = runTest {
        val interrupted = InterruptedIOException("stream closed")

        val result = handleNetworkResult<String> { throw interrupted }

        assertThat(result.isUnknownError()).isTrue()
        assertThat(result.message).isEqualTo("stream closed Status: Unknown")
        assertThat(result.exception).isSameInstanceAs(interrupted)
    }

    @Test
    fun handleNetworkResult_mapsHttp429ToError() = runTest {
        val exception = GplayHttpRequestException(