From ea7f47e20b2f0edf9104b81f874871587370a4b0 Mon Sep 17 00:00:00 2001 From: Hasib Prince Date: Wed, 30 Aug 2023 14:04:45 +0600 Subject: [PATCH 1/6] error handling updated for search and homepage --- .../foundation/e/apps/data/ResultSupreme.kt | 18 ++++- .../e/apps/data/cleanapk/RetrofitModule.kt | 5 ++ .../e/apps/data/fused/FusedApiImpl.kt | 76 ++++++++++++------- .../apps/data/gplay/utils/GPlayHttpClient.kt | 26 +------ .../apps/data/login/api/LoginApiRepository.kt | 5 +- 5 files changed, 72 insertions(+), 58 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/ResultSupreme.kt b/app/src/main/java/foundation/e/apps/data/ResultSupreme.kt index 14695702f..80816f2e6 100644 --- a/app/src/main/java/foundation/e/apps/data/ResultSupreme.kt +++ b/app/src/main/java/foundation/e/apps/data/ResultSupreme.kt @@ -20,6 +20,8 @@ package foundation.e.apps.data import foundation.e.apps.data.enums.ResultStatus import java.util.concurrent.TimeoutException +private const val UNKNOWN_ERROR = "Unknown error!" + /** * Another implementation of Result class. * This removes the use of [ResultStatus] class for different status. @@ -52,10 +54,12 @@ sealed class ResultSupreme { * Example can be an empty list. * @param exception Optional exception from try-catch block. */ - class Timeout(data: T, exception: Exception = TimeoutException()) : + class Timeout(data: T? = null, exception: Exception = TimeoutException()) : ResultSupreme() { init { - setData(data) + data?.let { + setData(it) + } this.exception = exception } } @@ -119,6 +123,16 @@ sealed class ResultSupreme { this.data = data } + fun getResultStatus(): ResultStatus { + return when(this) { + is Success -> ResultStatus.OK + is Timeout -> ResultStatus.TIMEOUT + else -> ResultStatus.UNKNOWN.apply { + message = this@ResultSupreme.exception?.localizedMessage?: UNKNOWN_ERROR + } + } + } + companion object { /** diff --git a/app/src/main/java/foundation/e/apps/data/cleanapk/RetrofitModule.kt b/app/src/main/java/foundation/e/apps/data/cleanapk/RetrofitModule.kt index 43a505137..61a466b4d 100644 --- a/app/src/main/java/foundation/e/apps/data/cleanapk/RetrofitModule.kt +++ b/app/src/main/java/foundation/e/apps/data/cleanapk/RetrofitModule.kt @@ -34,6 +34,7 @@ import foundation.e.apps.data.ecloud.EcloudApiInterface import foundation.e.apps.data.exodus.ExodusTrackerApi import foundation.e.apps.data.fdroid.FdroidApiInterface import foundation.e.apps.data.fdroid.FdroidWebInterface +import foundation.e.apps.data.gplay.utils.GPlayHttpClient import okhttp3.Cache import okhttp3.Interceptor import okhttp3.MediaType.Companion.toMediaTypeOrNull @@ -48,6 +49,7 @@ import retrofit2.converter.moshi.MoshiConverterFactory import timber.log.Timber import java.net.ConnectException import java.util.Locale +import java.util.concurrent.TimeUnit import javax.inject.Named import javax.inject.Singleton @@ -55,6 +57,8 @@ import javax.inject.Singleton @InstallIn(SingletonComponent::class) object RetrofitModule { + private const val HTTP_TIMEOUT_IN_SECOND = 10L + /** * Provides an instance of Retrofit to work with CleanAPK API * @return instance of [CleanApkRetrofit] @@ -208,6 +212,7 @@ object RetrofitModule { fun provideOkHttpClient(cache: Cache, interceptor: Interceptor): OkHttpClient { return OkHttpClient.Builder() .addInterceptor(interceptor) + .callTimeout(HTTP_TIMEOUT_IN_SECOND, TimeUnit.SECONDS) .cache(cache) .build() } diff --git a/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt b/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt index cb4f227a6..c6c5ac1ac 100644 --- a/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt +++ b/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt @@ -22,7 +22,6 @@ import android.content.Context import android.text.format.Formatter import androidx.lifecycle.LiveData import androidx.lifecycle.liveData -import androidx.lifecycle.map import com.aurora.gplayapi.Constants import com.aurora.gplayapi.SearchSuggestEntry import com.aurora.gplayapi.data.models.App @@ -73,7 +72,6 @@ import kotlinx.coroutines.Deferred import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.flow.map import kotlinx.coroutines.withTimeout import retrofit2.Response import timber.log.Timber @@ -100,7 +98,7 @@ class FusedApiImpl @Inject constructor( private const val CATEGORY_TITLE_REPLACEABLE_CONJUNCTION = "&" private const val CATEGORY_OPEN_GAMES_ID = "game_open_games" private const val CATEGORY_OPEN_GAMES_TITLE = "Open games" - private const val ERROR_GPLAY_SEARCH = "Gplay search has failed!" + private const val ERROR_GPLAY_API = "Gplay api has faced error!" private const val ERROR_GPLAY_SOURCE_NOT_SELECTED = "Gplay apps are not selected!" } @@ -167,29 +165,32 @@ class FusedApiImpl @Inject constructor( authData: AuthData, ): ResultSupreme> { - val apiStatus = when (source) { - Source.GPLAY -> runCodeWithTimeout({ + val result = when (source) { + Source.GPLAY -> handleResultFromAppSources> { priorList.addAll(fetchGPlayHome(authData)) - }) + priorList + } - Source.OPEN -> runCodeWithTimeout({ + Source.OPEN -> handleResultFromAppSources { val response = (cleanApkAppsRepository.getHomeScreenData() as Response).body() response?.home?.let { priorList.addAll(generateCleanAPKHome(it, APP_TYPE_OPEN)) } - }) + priorList + } - Source.PWA -> runCodeWithTimeout({ + Source.PWA -> handleResultFromAppSources { val response = (cleanApkPWARepository.getHomeScreenData() as Response).body() response?.home?.let { priorList.addAll(generateCleanAPKHome(it, APP_TYPE_PWA)) } - }) + priorList + } } - setHomeErrorMessage(apiStatus, source) + setHomeErrorMessage(result.getResultStatus(), source) priorList.sortByDescending { when (it.source) { APP_TYPE_OPEN -> 2 @@ -197,7 +198,7 @@ class FusedApiImpl @Inject constructor( else -> 3 } } - return ResultSupreme.create(apiStatus, priorList) + return ResultSupreme.create(result.getResultStatus(), priorList) } private fun setHomeErrorMessage(apiStatus: ResultStatus, source: Source) { @@ -323,16 +324,17 @@ class FusedApiImpl @Inject constructor( searchResult: MutableList, packageSpecificResults: ArrayList ): ResultSupreme, Boolean>> { - val status = runCodeWithTimeout({ + val result = handleResultFromAppSources { cleanApkResults.addAll(getCleanAPKSearchResults(query)) - }) + cleanApkResults + } if (cleanApkResults.isNotEmpty()) { searchResult.addAll(cleanApkResults) } return ResultSupreme.create( - status, + result.getResultStatus(), Pair( filterWithKeywordSearch( searchResult, @@ -958,7 +960,7 @@ class FusedApiImpl @Inject constructor( private fun getCategoryIconName(category: FusedCategory): String { var categoryTitle = if (category.tag.getOperationalTag() - .contentEquals(AppTag.GPlay().getOperationalTag()) + .contentEquals(AppTag.GPlay().getOperationalTag()) ) category.id else category.title if (categoryTitle.contains(CATEGORY_TITLE_REPLACEABLE_CONJUNCTION)) { @@ -1083,12 +1085,12 @@ class FusedApiImpl @Inject constructor( query: String, nextPageSubBundle: Set? ): GplaySearchResult { - try { + return handleResultFromAppSources { val searchResults = gplayRepository.getSearchResult(query, nextPageSubBundle?.toMutableSet()) if (!preferenceManagerModule.isGplaySelected()) { - return ResultSupreme.Error(ERROR_GPLAY_SOURCE_NOT_SELECTED) + return@handleResultFromAppSources Pair(listOf(), setOf()) } val fusedAppList = @@ -1098,21 +1100,39 @@ class FusedApiImpl @Inject constructor( fusedAppList.add(FusedApp(isPlaceHolder = true)) } - return ResultSupreme.Success(Pair(fusedAppList.toList(), searchResults.second.toSet())) - } catch (e: GplayHttpRequestException) { - val message = ( - e.localizedMessage?.ifBlank { ERROR_GPLAY_SEARCH } - ?: ERROR_GPLAY_SEARCH - ) + "Status: ${e.status}" + return@handleResultFromAppSources Pair(fusedAppList.toList(), searchResults.second.toSet()) + } + } + private suspend fun handleResultFromAppSources(call: suspend () -> T): ResultSupreme { + return try { + ResultSupreme.Success(call()) + } catch (e: SocketTimeoutException) { + val message = extractErrorMessage(e) + val exception = GPlayException(true, message) + val resultTimeout = ResultSupreme.Timeout(exception = exception) + resultTimeout.message = message + + resultTimeout + } catch (e: GplayHttpRequestException) { + val message = extractErrorMessage(e) val exception = GPlayException(e.status == 408, message) - return ResultSupreme.Error(message, exception) + + ResultSupreme.Error(message, exception) } catch (e: Exception) { - val exception = - GPlayException(e is SocketTimeoutException, e.localizedMessage) + val message = extractErrorMessage(e) + ResultSupreme.Error(message, e) + } + } - return ResultSupreme.Error(e.localizedMessage ?: "", exception) + private fun extractErrorMessage(e: Exception): String { + val status = when (e) { + is GplayHttpRequestException -> e.status.toString() + is SocketTimeoutException -> "Timeout" + else -> "Unknown" } + return (e.localizedMessage?.ifBlank { ERROR_GPLAY_API } + ?: ERROR_GPLAY_API) + "Status: $status" } /* diff --git a/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt b/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt index 9a30a62a9..62e542c74 100644 --- a/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt +++ b/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt @@ -54,7 +54,6 @@ class GPlayHttpClient @Inject constructor( companion object { private const val TAG = "GPlayHttpClient" private const val HTTP_TIMEOUT_IN_SECOND = 10L - private const val SEARCH = "search" } private val okHttpClient = OkHttpClient().newBuilder() @@ -159,25 +158,7 @@ class GPlayHttpClient @Inject constructor( val call = okHttpClient.newCall(request) buildPlayResponse(call.execute()) } catch (e: Exception) { - // TODO: exception will be thrown for all apis when all gplay api implementation - // will handle the exceptions. this will be done in following issue. - // Issue: https://gitlab.e.foundation/e/os/backlog/-/issues/1483 - if (request.url.toString().contains(SEARCH)) { - throw e - } - - when (e) { - is UnknownHostException, - is SocketTimeoutException -> handleExceptionOnGooglePlayRequest(e) - else -> handleExceptionOnGooglePlayRequest(e) - } - } - } - - private fun handleExceptionOnGooglePlayRequest(e: Exception): PlayResponse { - Timber.e("processRequest: ${e.localizedMessage}") - return PlayResponse().apply { - errorString = "${this@GPlayHttpClient::class.java.simpleName}: ${e.localizedMessage}" + throw e } } @@ -203,10 +184,7 @@ class GPlayHttpClient @Inject constructor( } } - // TODO: exception will be thrown for all apis when all gplay api implementation - // will handle the exceptions. this will be done in following issue. - // Issue: https://gitlab.e.foundation/e/os/backlog/-/issues/1483 - if (response.request.url.toString().contains(SEARCH) && code != 200) { + if (code != 200) { throw GplayHttpRequestException(code, response.message) } diff --git a/app/src/main/java/foundation/e/apps/data/login/api/LoginApiRepository.kt b/app/src/main/java/foundation/e/apps/data/login/api/LoginApiRepository.kt index 5d97b6487..d9de1fad3 100644 --- a/app/src/main/java/foundation/e/apps/data/login/api/LoginApiRepository.kt +++ b/app/src/main/java/foundation/e/apps/data/login/api/LoginApiRepository.kt @@ -144,7 +144,6 @@ class LoginApiRepository constructor( */ private suspend fun runCodeWithTimeout( block: suspend () -> T, - timeoutBlock: (() -> T?)? = null, exceptionBlock: ((e: Exception) -> T?)? = null, ): ResultSupreme { return try { @@ -152,9 +151,7 @@ class LoginApiRepository constructor( return@withTimeout ResultSupreme.Success(block()) } } catch (e: TimeoutCancellationException) { - ResultSupreme.Timeout(timeoutBlock?.invoke()).apply { - message = e.message ?: "" - } + ResultSupreme.Timeout(exception = e) } catch (e: Exception) { e.printStackTrace() ResultSupreme.Error(exceptionBlock?.invoke(e), message = e.message ?: "") -- GitLab From c219119bb50a5c713c02776f363b1bc84288e422 Mon Sep 17 00:00:00 2001 From: Hasib Prince Date: Wed, 30 Aug 2023 15:32:27 +0600 Subject: [PATCH 2/6] error handling updated for all gplay apis --- .../e/apps/data/fused/FusedApiImpl.kt | 45 ++++++++----------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt b/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt index c6c5ac1ac..4ff5e55d5 100644 --- a/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt +++ b/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt @@ -694,7 +694,7 @@ class FusedApiImpl @Inject constructor( appList: List, ): ResultSupreme> { val filteredFusedApps = mutableListOf() - val status = runCodeWithTimeout({ + return handleResultFromAppSources { appList.forEach { val filter = getAppFilterLevel(it, authData) if (filter.isUnFiltered()) { @@ -705,9 +705,8 @@ class FusedApiImpl @Inject constructor( ) } } - }) - - return ResultSupreme.create(status, filteredFusedApps) + filteredFusedApps + } } /** @@ -786,7 +785,7 @@ class FusedApiImpl @Inject constructor( var response: FusedApp? = null - val status = runCodeWithTimeout({ + val result = handleResultFromAppSources { response = if (origin == Origin.CLEANAPK) { (cleanApkAppsRepository.getAppDetails(id) as Response).body()?.app } else { @@ -799,9 +798,10 @@ class FusedApiImpl @Inject constructor( it.updateSource() it.updateFilterLevel(authData) } - }) + response + } - return Pair(response ?: FusedApp(), status) + return Pair(result.data ?: FusedApp(), result.getResultStatus()) } /* @@ -839,9 +839,9 @@ class FusedApiImpl @Inject constructor( val gplayCategoryResult = fetchGplayCategories( type, ) - categoriesList.addAll(gplayCategoryResult.second) - apiStatus = gplayCategoryResult.first - errorApplicationCategory = gplayCategoryResult.third + categoriesList.addAll(gplayCategoryResult.data ?: listOf()) + apiStatus = gplayCategoryResult.getResultStatus() + errorApplicationCategory = APP_TYPE_ANY } return Pair(apiStatus, errorApplicationCategory) @@ -849,25 +849,18 @@ class FusedApiImpl @Inject constructor( private suspend fun fetchGplayCategories( type: CategoryType, - ): Triple, String> { - var errorApplicationCategory = "" - var apiStatus = ResultStatus.OK + ): ResultSupreme> { val categoryList = mutableListOf() - runCodeWithTimeout({ + + return handleResultFromAppSources { val playResponse = gplayRepository.getCategories(type).map { app -> val category = app.transformToFusedCategory() updateCategoryDrawable(category) category } categoryList.addAll(playResponse) - }, { - errorApplicationCategory = APP_TYPE_ANY - apiStatus = ResultStatus.TIMEOUT - }, { - errorApplicationCategory = APP_TYPE_ANY - apiStatus = ResultStatus.UNKNOWN - }) - return Triple(apiStatus, categoryList, errorApplicationCategory) + categoryList + } } private suspend fun fetchPWACategories( @@ -1131,6 +1124,7 @@ class FusedApiImpl @Inject constructor( is SocketTimeoutException -> "Timeout" else -> "Unknown" } + return (e.localizedMessage?.ifBlank { ERROR_GPLAY_API } ?: ERROR_GPLAY_API) + "Status: $status" } @@ -1437,7 +1431,7 @@ class FusedApiImpl @Inject constructor( var fusedAppList: MutableList = mutableListOf() var nextPageUrl = "" - val status = runCodeWithTimeout({ + return handleResultFromAppSources { val streamCluster = gplayRepository.getAppsByCategory(category, pageUrl) as StreamCluster @@ -1450,8 +1444,7 @@ class FusedApiImpl @Inject constructor( if (!nextPageUrl.isNullOrEmpty()) { fusedAppList.add(FusedApp(isPlaceHolder = true)) } - }) - - return ResultSupreme.create(status, Pair(fusedAppList, nextPageUrl)) + Pair(fusedAppList, nextPageUrl) + } } } -- GitLab From eb28b5ea2bba5d05c58a9dd0fe37ed09ea3fc26c Mon Sep 17 00:00:00 2001 From: Hasib Prince Date: Wed, 6 Sep 2023 18:53:06 +0600 Subject: [PATCH 3/6] error handling updated for cleanApkApps. --- .../e/apps/data/fused/FusedApiImpl.kt | 126 ++++++++---------- .../apps/data/gplay/utils/GPlayHttpClient.kt | 4 +- 2 files changed, 60 insertions(+), 70 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt b/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt index 4ff5e55d5..a4951d3f8 100644 --- a/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt +++ b/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt @@ -99,7 +99,9 @@ class FusedApiImpl @Inject constructor( private const val CATEGORY_OPEN_GAMES_ID = "game_open_games" private const val CATEGORY_OPEN_GAMES_TITLE = "Open games" private const val ERROR_GPLAY_API = "Gplay api has faced error!" - private const val ERROR_GPLAY_SOURCE_NOT_SELECTED = "Gplay apps are not selected!" + private const val TIMEOUT = "Timeout" + private const val UNKNOWN = "Unknown" + private const val STATUS = "Status: " } /** @@ -166,12 +168,12 @@ class FusedApiImpl @Inject constructor( ): ResultSupreme> { val result = when (source) { - Source.GPLAY -> handleResultFromAppSources> { + Source.GPLAY -> handleNetworkResult> { priorList.addAll(fetchGPlayHome(authData)) priorList } - Source.OPEN -> handleResultFromAppSources { + Source.OPEN -> handleNetworkResult { val response = (cleanApkAppsRepository.getHomeScreenData() as Response).body() response?.home?.let { @@ -180,7 +182,7 @@ class FusedApiImpl @Inject constructor( priorList } - Source.PWA -> handleResultFromAppSources { + Source.PWA -> handleNetworkResult { val response = (cleanApkPWARepository.getHomeScreenData() as Response).body() response?.home?.let { @@ -291,7 +293,7 @@ class FusedApiImpl @Inject constructor( packageSpecificResults: ArrayList ): ResultSupreme, Boolean>> { val pwaApps: MutableList = mutableListOf() - val status = runCodeWithTimeout({ + val result = handleNetworkResult { val apps = cleanApkPWARepository.getSearchResult(query).body()?.apps apps?.apply { @@ -299,14 +301,14 @@ class FusedApiImpl @Inject constructor( pwaApps.addAll(this) } } - }) + } - if (pwaApps.isNotEmpty() || status != ResultStatus.OK) { + if (pwaApps.isNotEmpty() || result.getResultStatus() != ResultStatus.OK) { searchResult.addAll(pwaApps) } return ResultSupreme.create( - status, + result.getResultStatus(), Pair( filterWithKeywordSearch( searchResult, @@ -324,7 +326,7 @@ class FusedApiImpl @Inject constructor( searchResult: MutableList, packageSpecificResults: ArrayList ): ResultSupreme, Boolean>> { - val result = handleResultFromAppSources { + val result = handleNetworkResult { cleanApkResults.addAll(getCleanAPKSearchResults(query)) cleanApkResults } @@ -354,7 +356,7 @@ class FusedApiImpl @Inject constructor( var gplayPackageResult: FusedApp? = null var cleanapkPackageResult: FusedApp? = null - val status = runCodeWithTimeout({ + val result = handleNetworkResult { if (preferenceManagerModule.isGplaySelected()) { gplayPackageResult = getGplayPackagResult(query, authData) } @@ -362,7 +364,7 @@ class FusedApiImpl @Inject constructor( if (preferenceManagerModule.isOpenSourceSelected()) { cleanapkPackageResult = getCleanApkPackageResult(query) } - }) + } /* * Currently only show open source package result if exists in both fdroid and gplay. @@ -381,10 +383,10 @@ class FusedApiImpl @Inject constructor( * If there was a timeout, return it and don't try to fetch anything else. * Also send true in the pair to signal more results being loaded. */ - if (status != ResultStatus.OK) { - return ResultSupreme.create(status, Pair(packageSpecificResults, false)) + if (result.getResultStatus() != ResultStatus.OK) { + return ResultSupreme.create(result.getResultStatus(), Pair(packageSpecificResults, false)) } - return ResultSupreme.create(status, Pair(packageSpecificResults, true)) + return ResultSupreme.create(result.getResultStatus(), Pair(packageSpecificResults, true)) } /* @@ -449,7 +451,7 @@ class FusedApiImpl @Inject constructor( */ private suspend fun getCleanapkSearchResult(packageName: String): ResultSupreme { var fusedApp = FusedApp() - val status = runCodeWithTimeout({ + val result = handleNetworkResult { val result = cleanApkAppsRepository.getSearchResult( packageName, "package_name" @@ -458,15 +460,15 @@ class FusedApiImpl @Inject constructor( if (result?.apps?.isNotEmpty() == true && result.numberOfResults == 1) { fusedApp = result.apps[0] } - }) - return ResultSupreme.create(status, fusedApp) + } + return ResultSupreme.create(result.getResultStatus(), fusedApp) } override suspend fun getSearchSuggestions(query: String): List { var searchSuggesions = listOf() - runCodeWithTimeout({ + handleNetworkResult { searchSuggesions = gplayRepository.getSearchSuggestions(query) - }) + } return searchSuggesions } @@ -526,7 +528,7 @@ class FusedApiImpl @Inject constructor( override suspend fun getPWAApps(category: String): ResultSupreme, String>> { val list = mutableListOf() - val status = runCodeWithTimeout({ + val result = handleNetworkResult { val response = getPWAAppsResponse(category) response?.apps?.forEach { it.updateStatus() @@ -534,13 +536,13 @@ class FusedApiImpl @Inject constructor( it.updateFilterLevel(null) list.add(it) } - }) - return ResultSupreme.create(status, Pair(list, "")) + } + return ResultSupreme.create(result.getResultStatus(), Pair(list, "")) } override suspend fun getOpenSourceApps(category: String): ResultSupreme, String>> { val list = mutableListOf() - val status = runCodeWithTimeout({ + val result = handleNetworkResult { val response = getOpenSourceAppsResponse(category) response?.apps?.forEach { it.updateStatus() @@ -548,8 +550,8 @@ class FusedApiImpl @Inject constructor( it.updateFilterLevel(null) list.add(it) } - }) - return ResultSupreme.create(status, Pair(list, "")) + } + return ResultSupreme.create(result.getResultStatus(), Pair(list, "")) } /* @@ -560,7 +562,7 @@ class FusedApiImpl @Inject constructor( */ override suspend fun getCleanapkAppDetails(packageName: String): Pair { var fusedApp = FusedApp() - val status = runCodeWithTimeout({ + val result = handleNetworkResult { val result = cleanApkAppsRepository.getSearchResult( packageName, "package_name" @@ -572,8 +574,8 @@ class FusedApiImpl @Inject constructor( ?: FusedApp() } fusedApp.updateFilterLevel(null) - }) - return Pair(fusedApp, status) + } + return Pair(fusedApp, result.getResultStatus()) } override suspend fun getApplicationDetails( @@ -617,7 +619,7 @@ class FusedApiImpl @Inject constructor( * i.e. check timeout for individual package query. */ for (packageName in packageNameList) { - status = runCodeWithTimeout({ + val result = handleNetworkResult { cleanApkAppsRepository.getSearchResult( packageName, "package_name" @@ -630,7 +632,9 @@ class FusedApiImpl @Inject constructor( ) } } - }) + } + + status = result.getResultStatus() /* * If status is not ok, immediately return. @@ -656,7 +660,7 @@ class FusedApiImpl @Inject constructor( /* * Old code moved from getApplicationDetails() */ - val status = runCodeWithTimeout({ + val result = handleNetworkResult { gplayRepository.getAppsDetails(packageNameList).forEach { app -> /* * Some apps are restricted to locations. Example "com.skype.m2". @@ -673,9 +677,9 @@ class FusedApiImpl @Inject constructor( ) } } - }) + } - return Pair(fusedAppList, status) + return Pair(fusedAppList, result.getResultStatus()) } /** @@ -694,7 +698,7 @@ class FusedApiImpl @Inject constructor( appList: List, ): ResultSupreme> { val filteredFusedApps = mutableListOf() - return handleResultFromAppSources { + return handleNetworkResult { appList.forEach { val filter = getAppFilterLevel(it, authData) if (filter.isUnFiltered()) { @@ -785,7 +789,7 @@ class FusedApiImpl @Inject constructor( var response: FusedApp? = null - val result = handleResultFromAppSources { + val result = handleNetworkResult { response = if (origin == Origin.CLEANAPK) { (cleanApkAppsRepository.getAppDetails(id) as Response).body()?.app } else { @@ -852,7 +856,7 @@ class FusedApiImpl @Inject constructor( ): ResultSupreme> { val categoryList = mutableListOf() - return handleResultFromAppSources { + return handleNetworkResult { val playResponse = gplayRepository.getCategories(type).map { app -> val category = app.transformToFusedCategory() updateCategoryDrawable(category) @@ -866,10 +870,8 @@ class FusedApiImpl @Inject constructor( private suspend fun fetchPWACategories( type: CategoryType, ): Triple, String> { - var errorApplicationCategory = "" - var apiStatus: ResultStatus = ResultStatus.OK val fusedCategoriesList = mutableListOf() - runCodeWithTimeout({ + val result = handleNetworkResult { getPWAsCategories()?.let { fusedCategoriesList.addAll( getFusedCategoryBasedOnCategoryType( @@ -877,23 +879,16 @@ class FusedApiImpl @Inject constructor( ) ) } - }, { - errorApplicationCategory = APP_TYPE_PWA - apiStatus = ResultStatus.TIMEOUT - }, { - errorApplicationCategory = APP_TYPE_PWA - apiStatus = ResultStatus.UNKNOWN - }) - return Triple(apiStatus, fusedCategoriesList, errorApplicationCategory) + } + + return Triple(result.getResultStatus(), fusedCategoriesList, APP_TYPE_PWA) } private suspend fun fetchOpenSourceCategories( type: CategoryType, ): Triple, String> { - var errorApplicationCategory = "" - var apiStatus: ResultStatus = ResultStatus.OK val fusedCategoryList = mutableListOf() - runCodeWithTimeout({ + val result = handleNetworkResult { getOpenSourceCategories()?.let { fusedCategoryList.addAll( getFusedCategoryBasedOnCategoryType( @@ -903,14 +898,9 @@ class FusedApiImpl @Inject constructor( ) ) } - }, { - errorApplicationCategory = APP_TYPE_OPEN - apiStatus = ResultStatus.TIMEOUT - }, { - errorApplicationCategory = APP_TYPE_OPEN - apiStatus = ResultStatus.UNKNOWN - }) - return Triple(apiStatus, fusedCategoryList, errorApplicationCategory) + } + + return Triple(result.getResultStatus(), fusedCategoryList, APP_TYPE_OPEN) } /** @@ -1078,12 +1068,12 @@ class FusedApiImpl @Inject constructor( query: String, nextPageSubBundle: Set? ): GplaySearchResult { - return handleResultFromAppSources { + return handleNetworkResult { val searchResults = gplayRepository.getSearchResult(query, nextPageSubBundle?.toMutableSet()) if (!preferenceManagerModule.isGplaySelected()) { - return@handleResultFromAppSources Pair(listOf(), setOf()) + return@handleNetworkResult Pair(listOf(), setOf()) } val fusedAppList = @@ -1093,19 +1083,17 @@ class FusedApiImpl @Inject constructor( fusedAppList.add(FusedApp(isPlaceHolder = true)) } - return@handleResultFromAppSources Pair(fusedAppList.toList(), searchResults.second.toSet()) + return@handleNetworkResult Pair(fusedAppList.toList(), searchResults.second.toSet()) } } - private suspend fun handleResultFromAppSources(call: suspend () -> T): ResultSupreme { + private suspend fun handleNetworkResult(call: suspend () -> T): ResultSupreme { return try { ResultSupreme.Success(call()) } catch (e: SocketTimeoutException) { val message = extractErrorMessage(e) - val exception = GPlayException(true, message) - val resultTimeout = ResultSupreme.Timeout(exception = exception) + val resultTimeout = ResultSupreme.Timeout(exception = e) resultTimeout.message = message - resultTimeout } catch (e: GplayHttpRequestException) { val message = extractErrorMessage(e) @@ -1121,12 +1109,12 @@ class FusedApiImpl @Inject constructor( private fun extractErrorMessage(e: Exception): String { val status = when (e) { is GplayHttpRequestException -> e.status.toString() - is SocketTimeoutException -> "Timeout" - else -> "Unknown" + is SocketTimeoutException -> TIMEOUT + else -> UNKNOWN } return (e.localizedMessage?.ifBlank { ERROR_GPLAY_API } - ?: ERROR_GPLAY_API) + "Status: $status" + ?: ERROR_GPLAY_API) + "$STATUS$status" } /* @@ -1431,7 +1419,7 @@ class FusedApiImpl @Inject constructor( var fusedAppList: MutableList = mutableListOf() var nextPageUrl = "" - return handleResultFromAppSources { + return handleNetworkResult { val streamCluster = gplayRepository.getAppsByCategory(category, pageUrl) as StreamCluster diff --git a/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt b/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt index 62e542c74..a9829bd7d 100644 --- a/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt +++ b/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt @@ -39,6 +39,7 @@ import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response import timber.log.Timber import java.io.IOException +import java.net.Socket import java.net.SocketTimeoutException import java.net.UnknownHostException import java.util.concurrent.TimeUnit @@ -158,7 +159,8 @@ class GPlayHttpClient @Inject constructor( val call = okHttpClient.newCall(request) buildPlayResponse(call.execute()) } catch (e: Exception) { - throw e + val status = if (e is SocketTimeoutException) 408 else -1 + throw GplayHttpRequestException(status, e.localizedMessage ?: "") } } -- GitLab From 2bbb9abed059653702b0a36da7d47ae3a424495f Mon Sep 17 00:00:00 2001 From: Hasib Prince Date: Thu, 7 Sep 2023 14:34:15 +0600 Subject: [PATCH 4/6] resolved conflict --- .../foundation/e/apps/data/NetworkHandler.kt | 44 +++++++++++++++++++ .../e/apps/data/fused/FusedApiImpl.kt | 40 +++-------------- .../apps/data/gplay/utils/GPlayHttpClient.kt | 6 ++- .../apps/data/login/api/LoginApiRepository.kt | 34 ++++---------- .../ApplicationListViewModel.kt | 26 +++++------ 5 files changed, 75 insertions(+), 75 deletions(-) create mode 100644 app/src/main/java/foundation/e/apps/data/NetworkHandler.kt diff --git a/app/src/main/java/foundation/e/apps/data/NetworkHandler.kt b/app/src/main/java/foundation/e/apps/data/NetworkHandler.kt new file mode 100644 index 000000000..e99dec8a0 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/data/NetworkHandler.kt @@ -0,0 +1,44 @@ +package foundation.e.apps.data + +import foundation.e.apps.data.gplay.utils.GPlayHttpClient +import foundation.e.apps.data.gplay.utils.GplayHttpRequestException +import foundation.e.apps.data.login.exceptions.GPlayException +import java.net.SocketTimeoutException + +private const val TIMEOUT = "Timeout" +private const val UNKNOWN = "Unknown" +private const val STATUS = "Status:" +private const val ERROR_GPLAY_API = "Gplay api has faced error!" + +suspend fun handleNetworkResult(call: suspend () -> T): ResultSupreme { + return try { + ResultSupreme.Success(call()) + } catch (e: SocketTimeoutException) { + val message = extractErrorMessage(e) + val resultTimeout = ResultSupreme.Timeout(exception = e) + resultTimeout.message = message + resultTimeout + } catch (e: GplayHttpRequestException) { + val message = extractErrorMessage(e) + val exception = GPlayException(e.status == GPlayHttpClient.STATUS_CODE_TIMEOUT, message) + + if (exception.isTimeout) { + ResultSupreme.Timeout(exception = exception) + } else { + ResultSupreme.Error(message, exception) + } + } catch (e: Exception) { + val message = extractErrorMessage(e) + ResultSupreme.Error(message, e) + } +} + +private fun extractErrorMessage(e: Exception): String { + val status = when (e) { + is GplayHttpRequestException -> e.status.toString() + is SocketTimeoutException -> TIMEOUT + else -> UNKNOWN + } + return (e.localizedMessage?.ifBlank { ERROR_GPLAY_API } + ?: ERROR_GPLAY_API) + " $STATUS $status" +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt b/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt index 6a7cbec24..3502f4b74 100644 --- a/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt +++ b/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt @@ -63,6 +63,7 @@ import foundation.e.apps.data.fused.utils.CategoryUtils import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.data.gplay.GplayStoreRepository import foundation.e.apps.data.gplay.utils.GplayHttpRequestException +import foundation.e.apps.data.handleNetworkResult import foundation.e.apps.data.login.exceptions.GPlayException import foundation.e.apps.data.preference.PreferenceManagerModule import foundation.e.apps.install.pkg.PWAManagerModule @@ -98,10 +99,6 @@ class FusedApiImpl @Inject constructor( private const val CATEGORY_TITLE_REPLACEABLE_CONJUNCTION = "&" private const val CATEGORY_OPEN_GAMES_ID = "game_open_games" private const val CATEGORY_OPEN_GAMES_TITLE = "Open games" - private const val ERROR_GPLAY_API = "Gplay api has faced error!" - private const val TIMEOUT = "Timeout" - private const val UNKNOWN = "Unknown" - private const val STATUS = "Status: " } /** @@ -383,7 +380,10 @@ class FusedApiImpl @Inject constructor( * Also send true in the pair to signal more results being loaded. */ if (result.getResultStatus() != ResultStatus.OK) { - return ResultSupreme.create(result.getResultStatus(), Pair(packageSpecificResults, false)) + return ResultSupreme.create( + result.getResultStatus(), + Pair(packageSpecificResults, false) + ) } return ResultSupreme.create(result.getResultStatus(), Pair(packageSpecificResults, true)) } @@ -1086,36 +1086,6 @@ class FusedApiImpl @Inject constructor( } } - private suspend fun handleNetworkResult(call: suspend () -> T): ResultSupreme { - return try { - ResultSupreme.Success(call()) - } catch (e: SocketTimeoutException) { - val message = extractErrorMessage(e) - val resultTimeout = ResultSupreme.Timeout(exception = e) - resultTimeout.message = message - resultTimeout - } catch (e: GplayHttpRequestException) { - val message = extractErrorMessage(e) - val exception = GPlayException(e.status == 408, message) - - ResultSupreme.Error(message, exception) - } catch (e: Exception) { - val message = extractErrorMessage(e) - ResultSupreme.Error(message, e) - } - } - - private fun extractErrorMessage(e: Exception): String { - val status = when (e) { - is GplayHttpRequestException -> e.status.toString() - is SocketTimeoutException -> TIMEOUT - else -> UNKNOWN - } - - return (e.localizedMessage?.ifBlank { ERROR_GPLAY_API } - ?: ERROR_GPLAY_API) + "$STATUS$status" - } - /* * This function will replace a GPlay app with F-Droid app if exists, * else will show the GPlay app itself. diff --git a/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt b/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt index c7117bc2f..7e95f06a2 100644 --- a/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt +++ b/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt @@ -45,6 +45,7 @@ import java.net.UnknownHostException import java.util.concurrent.TimeUnit import javax.inject.Inject + class GPlayHttpClient @Inject constructor( private val cache: Cache, ) : IHttpClient { @@ -59,6 +60,7 @@ class GPlayHttpClient @Inject constructor( private const val SEARCH_SUGGEST = "searchSuggest" private const val STATUS_CODE_UNAUTHORIZED = 401 private const val STATUS_CODE_TOO_MANY_REQUESTS = 429 + const val STATUS_CODE_TIMEOUT = 408 } private val okHttpClient = OkHttpClient().newBuilder() @@ -164,8 +166,10 @@ class GPlayHttpClient @Inject constructor( val call = okHttpClient.newCall(request) response = call.execute() buildPlayResponse(response) + } catch (e: GplayHttpRequestException) { + throw e } catch (e: Exception) { - val status = if (e is SocketTimeoutException) 408 else -1 + val status = if (e is SocketTimeoutException) STATUS_CODE_TIMEOUT else -1 throw GplayHttpRequestException(status, e.localizedMessage ?: "") } finally { response?.close() diff --git a/app/src/main/java/foundation/e/apps/data/login/api/LoginApiRepository.kt b/app/src/main/java/foundation/e/apps/data/login/api/LoginApiRepository.kt index d9de1fad3..acad60241 100644 --- a/app/src/main/java/foundation/e/apps/data/login/api/LoginApiRepository.kt +++ b/app/src/main/java/foundation/e/apps/data/login/api/LoginApiRepository.kt @@ -23,6 +23,7 @@ import foundation.e.apps.data.Constants.timeoutDurationInMillis import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.enums.User import foundation.e.apps.data.gplay.utils.AC2DMUtil +import foundation.e.apps.data.handleNetworkResult import foundation.e.apps.data.login.exceptions.GPlayLoginException import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.withTimeout @@ -52,9 +53,9 @@ class LoginApiRepository constructor( * else blank for Anonymous login. */ suspend fun fetchAuthData(email: String, aasToken: String, locale: Locale): ResultSupreme { - val result = runCodeWithTimeout({ + val result = handleNetworkResult { gPlayLoginInterface.fetchAuthData(email, aasToken) - }) + } return result.apply { this.data?.locale = locale this.exception = when (result) { @@ -76,13 +77,13 @@ class LoginApiRepository constructor( */ suspend fun login(authData: AuthData): ResultSupreme { var response = PlayResponse() - val result = runCodeWithTimeout({ + val result = handleNetworkResult { response = gPlayLoginInterface.login(authData) if (response.code != 200) { throw Exception("Validation network code: ${response.code}") } response - }) + } return ResultSupreme.replicate(result, response).apply { this.exception = when (result) { is ResultSupreme.Timeout -> GPlayLoginException(true, "GPlay API timeout", user) @@ -109,8 +110,8 @@ class LoginApiRepository constructor( googleLoginApi: GoogleLoginApi, email: String, oauthToken: String - ): ResultSupreme { - val result = runCodeWithTimeout({ + ): ResultSupreme { + val result = handleNetworkResult { var aasToken = "" val response = googleLoginApi.getAC2DMResponse(email, oauthToken) var error = response.errorString @@ -129,7 +130,7 @@ class LoginApiRepository constructor( throw Exception(error) } aasToken - }) + } return result.apply { this.exception = when (result) { is ResultSupreme.Timeout -> GPlayLoginException(true, "GPlay API timeout", User.GOOGLE) @@ -138,23 +139,4 @@ class LoginApiRepository constructor( } } } - - /** - * Utility method to run a specified code block in a fixed amount of time. - */ - private suspend fun runCodeWithTimeout( - block: suspend () -> T, - exceptionBlock: ((e: Exception) -> T?)? = null, - ): ResultSupreme { - return try { - withTimeout(timeoutDurationInMillis) { - return@withTimeout ResultSupreme.Success(block()) - } - } catch (e: TimeoutCancellationException) { - ResultSupreme.Timeout(exception = e) - } catch (e: Exception) { - e.printStackTrace() - ResultSupreme.Error(exceptionBlock?.invoke(e), message = e.message ?: "") - } - } } diff --git a/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListViewModel.kt b/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListViewModel.kt index 79c8cc52d..86be6867d 100644 --- a/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListViewModel.kt +++ b/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListViewModel.kt @@ -42,9 +42,11 @@ class ApplicationListViewModel @Inject constructor( val appListLiveData: MutableLiveData>?> = MutableLiveData() - var isLoading = false + private var isLoading = false - var nextPageUrl: String? = null + private var nextPageUrl: String? = null + + private var currentAuthListObject: List? = null fun loadData( category: String, @@ -54,11 +56,18 @@ class ApplicationListViewModel @Inject constructor( ) { super.onLoadData(authObjectList, { successAuthList, _ -> - if (appListLiveData.value?.data?.isNotEmpty() == true) { + // if token is refreshed, then reset all data + if (currentAuthListObject != null && currentAuthListObject != authObjectList) { + appListLiveData.postValue(ResultSupreme.Success(emptyList())) + nextPageUrl = null + } + + if (appListLiveData.value?.data?.isNotEmpty() == true && currentAuthListObject == authObjectList) { appListLiveData.postValue(appListLiveData.value) return@onLoadData } + this.currentAuthListObject = authObjectList successAuthList.find { it is AuthObject.GPlayAuth }?.run { getList(category, result.data!! as AuthData, source) return@onLoadData @@ -163,18 +172,9 @@ class ApplicationListViewModel @Inject constructor( private fun appendAppList(it: Pair, String>): List? { val currentAppList = appListLiveData.value?.data?.toMutableList() currentAppList?.removeIf { item -> item.isPlaceHolder } - val appList = currentAppList?.plus(it.first) - return appList + return currentAppList?.plus(it.first) } - /** - * @return returns true if there is changes in data, otherwise false - */ - fun isAnyAppUpdated( - newFusedApps: List, - oldFusedApps: List - ) = fusedAPIRepository.isAnyFusedAppUpdated(newFusedApps, oldFusedApps) - fun hasAnyAppInstallStatusChanged(currentList: List) = fusedAPIRepository.isAnyAppInstallStatusChanged(currentList) } -- GitLab From 3ec564d42d4468c6a2025f83f2b23db9af4b31b1 Mon Sep 17 00:00:00 2001 From: Hasib Prince Date: Thu, 7 Sep 2023 15:45:27 +0600 Subject: [PATCH 5/6] fixed: lint issues --- .../main/java/foundation/e/apps/data/NetworkHandler.kt | 5 ++--- app/src/main/java/foundation/e/apps/data/ResultSupreme.kt | 4 ++-- .../foundation/e/apps/data/cleanapk/RetrofitModule.kt | 1 - .../java/foundation/e/apps/data/fused/FusedApiImpl.kt | 8 ++------ .../foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt | 3 --- .../e/apps/data/login/api/LoginApiRepository.kt | 3 --- 6 files changed, 6 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/NetworkHandler.kt b/app/src/main/java/foundation/e/apps/data/NetworkHandler.kt index e99dec8a0..29b58d296 100644 --- a/app/src/main/java/foundation/e/apps/data/NetworkHandler.kt +++ b/app/src/main/java/foundation/e/apps/data/NetworkHandler.kt @@ -39,6 +39,5 @@ private fun extractErrorMessage(e: Exception): String { is SocketTimeoutException -> TIMEOUT else -> UNKNOWN } - return (e.localizedMessage?.ifBlank { ERROR_GPLAY_API } - ?: ERROR_GPLAY_API) + " $STATUS $status" -} \ No newline at end of file + return (e.localizedMessage?.ifBlank { ERROR_GPLAY_API } ?: ERROR_GPLAY_API) + " $STATUS $status" +} diff --git a/app/src/main/java/foundation/e/apps/data/ResultSupreme.kt b/app/src/main/java/foundation/e/apps/data/ResultSupreme.kt index 80816f2e6..a7a773f60 100644 --- a/app/src/main/java/foundation/e/apps/data/ResultSupreme.kt +++ b/app/src/main/java/foundation/e/apps/data/ResultSupreme.kt @@ -124,11 +124,11 @@ sealed class ResultSupreme { } fun getResultStatus(): ResultStatus { - return when(this) { + return when (this) { is Success -> ResultStatus.OK is Timeout -> ResultStatus.TIMEOUT else -> ResultStatus.UNKNOWN.apply { - message = this@ResultSupreme.exception?.localizedMessage?: UNKNOWN_ERROR + message = this@ResultSupreme.exception?.localizedMessage ?: UNKNOWN_ERROR } } } diff --git a/app/src/main/java/foundation/e/apps/data/cleanapk/RetrofitModule.kt b/app/src/main/java/foundation/e/apps/data/cleanapk/RetrofitModule.kt index 61a466b4d..c924f27c7 100644 --- a/app/src/main/java/foundation/e/apps/data/cleanapk/RetrofitModule.kt +++ b/app/src/main/java/foundation/e/apps/data/cleanapk/RetrofitModule.kt @@ -34,7 +34,6 @@ import foundation.e.apps.data.ecloud.EcloudApiInterface import foundation.e.apps.data.exodus.ExodusTrackerApi import foundation.e.apps.data.fdroid.FdroidApiInterface import foundation.e.apps.data.fdroid.FdroidWebInterface -import foundation.e.apps.data.gplay.utils.GPlayHttpClient import okhttp3.Cache import okhttp3.Interceptor import okhttp3.MediaType.Companion.toMediaTypeOrNull diff --git a/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt b/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt index 3502f4b74..e08bb6ded 100644 --- a/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt +++ b/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt @@ -62,9 +62,7 @@ import foundation.e.apps.data.fused.utils.CategoryType import foundation.e.apps.data.fused.utils.CategoryUtils import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.data.gplay.GplayStoreRepository -import foundation.e.apps.data.gplay.utils.GplayHttpRequestException import foundation.e.apps.data.handleNetworkResult -import foundation.e.apps.data.login.exceptions.GPlayException import foundation.e.apps.data.preference.PreferenceManagerModule import foundation.e.apps.install.pkg.PWAManagerModule import foundation.e.apps.install.pkg.PkgManagerModule @@ -76,7 +74,6 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.withTimeout import retrofit2.Response import timber.log.Timber -import java.net.SocketTimeoutException import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton @@ -941,9 +938,8 @@ class FusedApiImpl @Inject constructor( } private fun getCategoryIconName(category: FusedCategory): String { - var categoryTitle = if (category.tag.getOperationalTag() - .contentEquals(AppTag.GPlay().getOperationalTag()) - ) category.id else category.title + var categoryTitle = if (category.tag.getOperationalTag().contentEquals(AppTag.GPlay().getOperationalTag())) + category.id else category.title if (categoryTitle.contains(CATEGORY_TITLE_REPLACEABLE_CONJUNCTION)) { categoryTitle = categoryTitle.replace(CATEGORY_TITLE_REPLACEABLE_CONJUNCTION, "and") diff --git a/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt b/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt index 7e95f06a2..38fb0ad22 100644 --- a/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt +++ b/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt @@ -39,13 +39,10 @@ import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response import timber.log.Timber import java.io.IOException -import java.net.Socket import java.net.SocketTimeoutException -import java.net.UnknownHostException import java.util.concurrent.TimeUnit import javax.inject.Inject - class GPlayHttpClient @Inject constructor( private val cache: Cache, ) : IHttpClient { diff --git a/app/src/main/java/foundation/e/apps/data/login/api/LoginApiRepository.kt b/app/src/main/java/foundation/e/apps/data/login/api/LoginApiRepository.kt index acad60241..b2fbd026c 100644 --- a/app/src/main/java/foundation/e/apps/data/login/api/LoginApiRepository.kt +++ b/app/src/main/java/foundation/e/apps/data/login/api/LoginApiRepository.kt @@ -19,14 +19,11 @@ package foundation.e.apps.data.login.api import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.PlayResponse -import foundation.e.apps.data.Constants.timeoutDurationInMillis import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.enums.User import foundation.e.apps.data.gplay.utils.AC2DMUtil import foundation.e.apps.data.handleNetworkResult import foundation.e.apps.data.login.exceptions.GPlayLoginException -import kotlinx.coroutines.TimeoutCancellationException -import kotlinx.coroutines.withTimeout import java.util.Locale /** -- GitLab From 203974c7a2136d5c8ee1ab1cf2dc81438b6c5f8e Mon Sep 17 00:00:00 2001 From: Hasib Prince Date: Thu, 7 Sep 2023 20:35:18 +0600 Subject: [PATCH 6/6] minor refactoring --- .../foundation/e/apps/data/NetworkHandler.kt | 58 ++++++++++++++----- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/NetworkHandler.kt b/app/src/main/java/foundation/e/apps/data/NetworkHandler.kt index 29b58d296..78985de5f 100644 --- a/app/src/main/java/foundation/e/apps/data/NetworkHandler.kt +++ b/app/src/main/java/foundation/e/apps/data/NetworkHandler.kt @@ -1,3 +1,21 @@ +/* + * Copyright MURENA SAS 2023 + * Apps Quickly and easily install Android apps onto your device! + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package foundation.e.apps.data import foundation.e.apps.data.gplay.utils.GPlayHttpClient @@ -14,25 +32,37 @@ suspend fun handleNetworkResult(call: suspend () -> T): ResultSupreme { return try { ResultSupreme.Success(call()) } catch (e: SocketTimeoutException) { - val message = extractErrorMessage(e) - val resultTimeout = ResultSupreme.Timeout(exception = e) - resultTimeout.message = message - resultTimeout + handleSocketTimeoutException(e) } catch (e: GplayHttpRequestException) { - val message = extractErrorMessage(e) - val exception = GPlayException(e.status == GPlayHttpClient.STATUS_CODE_TIMEOUT, message) - - if (exception.isTimeout) { - ResultSupreme.Timeout(exception = exception) - } else { - ResultSupreme.Error(message, exception) - } + resultSupremeGplayHttpRequestException(e) } catch (e: Exception) { - val message = extractErrorMessage(e) - ResultSupreme.Error(message, e) + handleOthersException(e) } } +private fun handleSocketTimeoutException(e: SocketTimeoutException): ResultSupreme.Timeout { + val message = extractErrorMessage(e) + val resultTimeout = ResultSupreme.Timeout(exception = e) + resultTimeout.message = message + return resultTimeout +} + +private fun resultSupremeGplayHttpRequestException(e: GplayHttpRequestException): ResultSupreme { + val message = extractErrorMessage(e) + val exception = GPlayException(e.status == GPlayHttpClient.STATUS_CODE_TIMEOUT, message) + + return if (exception.isTimeout) { + ResultSupreme.Timeout(exception = exception) + } else { + ResultSupreme.Error(message, exception) + } +} + +private fun handleOthersException(e: Exception): ResultSupreme.Error { + val message = extractErrorMessage(e) + return ResultSupreme.Error(message, e) +} + private fun extractErrorMessage(e: Exception): String { val status = when (e) { is GplayHttpRequestException -> e.status.toString() -- GitLab