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

Commit c9951aa8 authored by Hasib Prince's avatar Hasib Prince
Browse files

handled auth error of gplay api

parent ac3cadf2
Loading
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -11,7 +11,7 @@ plugins {


def versionMajor = 2
def versionMajor = 2
def versionMinor = 4
def versionMinor = 4
def versionPatch = 7
def versionPatch = 9


def getGitHash = { ->
def getGitHash = { ->
    def stdOut = new ByteArrayOutputStream()
    def stdOut = new ByteArrayOutputStream()
+8 −1
Original line number Original line Diff line number Diff line
@@ -55,7 +55,6 @@ import foundation.e.apps.utils.eventBus.AppEvent
import foundation.e.apps.utils.eventBus.EventBus
import foundation.e.apps.utils.eventBus.EventBus
import foundation.e.apps.utils.exceptions.GPlayValidationException
import foundation.e.apps.utils.exceptions.GPlayValidationException
import foundation.e.apps.utils.modules.CommonUtilsFunctions
import foundation.e.apps.utils.modules.CommonUtilsFunctions
import foundation.e.apps.utils.modules.CommonUtilsModule
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.launch
import kotlinx.coroutines.launch
@@ -214,6 +213,14 @@ class MainActivity : AppCompatActivity() {
        viewModel.updateAppWarningList()
        viewModel.updateAppWarningList()


        lifecycleScope.launchWhenResumed {
        lifecycleScope.launchWhenResumed {
            EventBus.events.filter { it is AppEvent.AuthUpdateEvent }.collectLatest {
                Timber.d("Updated AuthObjects")
                val authObjectMutableList = loginViewModel.authObjects.value?.toMutableList()
                authObjectMutableList?.removeIf { it.result.data is AuthData }
                authObjectMutableList?.add(it.data as AuthObject)
                loginViewModel.authObjects.postValue(authObjectMutableList)
            }

            EventBus.events.filter { appEvent ->
            EventBus.events.filter { appEvent ->
                appEvent is AppEvent.SignatureMissMatchError
                appEvent is AppEvent.SignatureMissMatchError
            }.collectLatest {
            }.collectLatest {
+73 −22
Original line number Original line Diff line number Diff line
@@ -32,6 +32,7 @@ import com.aurora.gplayapi.data.models.AuthData
import com.aurora.gplayapi.data.models.Category
import com.aurora.gplayapi.data.models.Category
import com.aurora.gplayapi.data.models.StreamBundle
import com.aurora.gplayapi.data.models.StreamBundle
import com.aurora.gplayapi.data.models.StreamCluster
import com.aurora.gplayapi.data.models.StreamCluster
import com.aurora.gplayapi.exceptions.ApiException
import com.aurora.gplayapi.helpers.TopChartsHelper
import com.aurora.gplayapi.helpers.TopChartsHelper
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.android.qualifiers.ApplicationContext
import foundation.e.apps.R
import foundation.e.apps.R
@@ -48,7 +49,10 @@ import foundation.e.apps.api.fused.data.FusedHome
import foundation.e.apps.api.fused.data.Ratings
import foundation.e.apps.api.fused.data.Ratings
import foundation.e.apps.api.fused.utils.CategoryUtils
import foundation.e.apps.api.fused.utils.CategoryUtils
import foundation.e.apps.api.gplay.GPlayAPIRepository
import foundation.e.apps.api.gplay.GPlayAPIRepository
import foundation.e.apps.api.gplay.utils.GPlayHttpClient
import foundation.e.apps.home.model.HomeChildFusedAppDiffUtil
import foundation.e.apps.home.model.HomeChildFusedAppDiffUtil
import foundation.e.apps.login.AuthObject
import foundation.e.apps.login.LoginSourceRepository
import foundation.e.apps.manager.database.fusedDownload.FusedDownload
import foundation.e.apps.manager.database.fusedDownload.FusedDownload
import foundation.e.apps.manager.pkg.PkgManagerModule
import foundation.e.apps.manager.pkg.PkgManagerModule
import foundation.e.apps.utils.Constants.timeoutDurationInMillis
import foundation.e.apps.utils.Constants.timeoutDurationInMillis
@@ -60,6 +64,8 @@ import foundation.e.apps.utils.enums.Source
import foundation.e.apps.utils.enums.Status
import foundation.e.apps.utils.enums.Status
import foundation.e.apps.utils.enums.Type
import foundation.e.apps.utils.enums.Type
import foundation.e.apps.utils.enums.isUnFiltered
import foundation.e.apps.utils.enums.isUnFiltered
import foundation.e.apps.utils.eventBus.AppEvent
import foundation.e.apps.utils.eventBus.EventBus
import foundation.e.apps.utils.modules.PWAManagerModule
import foundation.e.apps.utils.modules.PWAManagerModule
import foundation.e.apps.utils.modules.PreferenceManagerModule
import foundation.e.apps.utils.modules.PreferenceManagerModule
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.TimeoutCancellationException
@@ -76,6 +82,7 @@ class FusedAPIImpl @Inject constructor(
    private val pwaManagerModule: PWAManagerModule,
    private val pwaManagerModule: PWAManagerModule,
    private val preferenceManagerModule: PreferenceManagerModule,
    private val preferenceManagerModule: PreferenceManagerModule,
    private val fdroidWebInterface: FdroidWebInterface,
    private val fdroidWebInterface: FdroidWebInterface,
    private val loginSourceRepository: LoginSourceRepository,
    @ApplicationContext private val context: Context
    @ApplicationContext private val context: Context
) {
) {


@@ -148,7 +155,7 @@ class FusedAPIImpl @Inject constructor(
        val apiStatus = when (source) {
        val apiStatus = when (source) {


            Source.GPLAY -> runCodeBlockWithTimeout({
            Source.GPLAY -> runCodeBlockWithTimeout({
                priorList.addAll(fetchGPlayHome(authData))
                priorList.addAll(fetchGPlayHome(it ?: authData))
            })
            })


            Source.OPEN -> runCodeBlockWithTimeout({
            Source.OPEN -> runCodeBlockWithTimeout({
@@ -234,10 +241,11 @@ class FusedAPIImpl @Inject constructor(
         * for all results to be fetched from network before showing them.
         * for all results to be fetched from network before showing them.
         * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171
         * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171
         */
         */

        return liveData {
        return liveData {
            val packageSpecificResults = ArrayList<FusedApp>()
            val packageSpecificResults = ArrayList<FusedApp>()
            fetchPackageSpecificResult(authData, query, packageSpecificResults)?.let {
            fetchPackageSpecificResult(authData, query, packageSpecificResults)?.let {
                if (it.data?.second == true) { // if there are no data to load
                if (it.data?.second == false) { // if there are no data to load
                    emit(it)
                    emit(it)
                    return@liveData
                    return@liveData
                }
                }
@@ -374,7 +382,7 @@ class FusedAPIImpl @Inject constructor(


        val status = runCodeBlockWithTimeout({
        val status = runCodeBlockWithTimeout({
            if (preferenceManagerModule.isGplaySelected()) {
            if (preferenceManagerModule.isGplaySelected()) {
                gplayPackageResult = getGplayPackagResult(query, authData)
                gplayPackageResult = getGplayPackagResult(query, it ?: authData)
            }
            }


            if (preferenceManagerModule.isOpenSourceSelected()) {
            if (preferenceManagerModule.isOpenSourceSelected()) {
@@ -395,7 +403,7 @@ class FusedAPIImpl @Inject constructor(
         * If there was a timeout, return it and don't try to fetch anything else.
         * 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.
         * Also send true in the pair to signal more results being loaded.
         */
         */
        if (status != ResultStatus.OK) {
        if (status != ResultStatus.OK || packageSpecificResults.isEmpty()) {
            return ResultSupreme.create(status, Pair(packageSpecificResults, true))
            return ResultSupreme.create(status, Pair(packageSpecificResults, true))
        }
        }
        return ResultSupreme.create(status, Pair(packageSpecificResults, false))
        return ResultSupreme.create(status, Pair(packageSpecificResults, false))
@@ -558,7 +566,7 @@ class FusedAPIImpl @Inject constructor(
        var streamBundle = StreamBundle()
        var streamBundle = StreamBundle()
        val status = runCodeBlockWithTimeout({
        val status = runCodeBlockWithTimeout({
            streamBundle =
            streamBundle =
                gPlayAPIRepository.getNextStreamBundle(authData, homeUrl, currentStreamBundle)
                gPlayAPIRepository.getNextStreamBundle(it ?: authData, homeUrl, currentStreamBundle)
        })
        })
        return ResultSupreme.create(status, streamBundle)
        return ResultSupreme.create(status, streamBundle)
    }
    }
@@ -571,7 +579,7 @@ class FusedAPIImpl @Inject constructor(
        var streamCluster = StreamCluster()
        var streamCluster = StreamCluster()
        val status = runCodeBlockWithTimeout({
        val status = runCodeBlockWithTimeout({
            streamCluster =
            streamCluster =
                gPlayAPIRepository.getAdjustedFirstCluster(authData, streamBundle, pointer)
                gPlayAPIRepository.getAdjustedFirstCluster(it ?: authData, streamBundle, pointer)
        })
        })
        return ResultSupreme.create(status, streamCluster)
        return ResultSupreme.create(status, streamCluster)
    }
    }
@@ -582,7 +590,8 @@ class FusedAPIImpl @Inject constructor(
    ): ResultSupreme<StreamCluster> {
    ): ResultSupreme<StreamCluster> {
        var streamCluster = StreamCluster()
        var streamCluster = StreamCluster()
        val status = runCodeBlockWithTimeout({
        val status = runCodeBlockWithTimeout({
            streamCluster = gPlayAPIRepository.getNextStreamCluster(authData, currentStreamCluster)
            streamCluster =
                gPlayAPIRepository.getNextStreamCluster(it ?: authData, currentStreamCluster)
        })
        })
        return ResultSupreme.create(status, streamCluster)
        return ResultSupreme.create(status, streamCluster)
    }
    }
@@ -594,7 +603,7 @@ class FusedAPIImpl @Inject constructor(
        val list = mutableListOf<FusedApp>()
        val list = mutableListOf<FusedApp>()
        val status = runCodeBlockWithTimeout({
        val status = runCodeBlockWithTimeout({
            list.addAll(
            list.addAll(
                gPlayAPIRepository.listApps(browseUrl, authData).map { app ->
                gPlayAPIRepository.listApps(browseUrl, it ?: authData).map { app ->
                    app.transformToFusedApp()
                    app.transformToFusedApp()
                }
                }
            )
            )
@@ -706,7 +715,7 @@ class FusedAPIImpl @Inject constructor(
         * Old code moved from getApplicationDetails()
         * Old code moved from getApplicationDetails()
         */
         */
        val status = runCodeBlockWithTimeout({
        val status = runCodeBlockWithTimeout({
            gPlayAPIRepository.getAppDetails(packageNameList, authData).forEach { app ->
            gPlayAPIRepository.getAppDetails(packageNameList, it ?: authData).forEach { app ->
                /*
                /*
                 * Some apps are restricted to locations. Example "com.skype.m2".
                 * Some apps are restricted to locations. Example "com.skype.m2".
                 * For restricted apps, check if it is possible to get their specific app info.
                 * For restricted apps, check if it is possible to get their specific app info.
@@ -743,9 +752,9 @@ class FusedAPIImpl @Inject constructor(
        appList: List<App>,
        appList: List<App>,
    ): ResultSupreme<List<FusedApp>> {
    ): ResultSupreme<List<FusedApp>> {
        val filteredFusedApps = mutableListOf<FusedApp>()
        val filteredFusedApps = mutableListOf<FusedApp>()
        val status = runCodeBlockWithTimeout({
        val status = runCodeBlockWithTimeout({ auth ->
            appList.forEach {
            appList.forEach {
                val filter = getAppFilterLevel(it, authData)
                val filter = getAppFilterLevel(it, auth ?: authData)
                if (filter.isUnFiltered()) {
                if (filter.isUnFiltered()) {
                    filteredFusedApps.add(
                    filteredFusedApps.add(
                        it.transformToFusedApp().apply {
                        it.transformToFusedApp().apply {
@@ -837,10 +846,11 @@ class FusedAPIImpl @Inject constructor(
        var response: FusedApp? = null
        var response: FusedApp? = null


        val status = runCodeBlockWithTimeout({
        val status = runCodeBlockWithTimeout({

            response = if (origin == Origin.CLEANAPK) {
            response = if (origin == Origin.CLEANAPK) {
                cleanAPKRepository.getAppOrPWADetailsByID(id).body()?.app
                cleanAPKRepository.getAppOrPWADetailsByID(id).body()?.app
            } else {
            } else {
                val app = gPlayAPIRepository.getAppDetails(packageName, authData)
                val app = gPlayAPIRepository.getAppDetails(packageName, it ?: authData)
                app?.transformToFusedApp()
                app?.transformToFusedApp()
            }
            }
            response?.let {
            response?.let {
@@ -850,7 +860,7 @@ class FusedAPIImpl @Inject constructor(
                it.updateFilterLevel(authData)
                it.updateFilterLevel(authData)
            }
            }
        })
        })

        Timber.d("getAppDetails: $status")
        return Pair(response ?: FusedApp(), status)
        return Pair(response ?: FusedApp(), status)
    }
    }


@@ -945,8 +955,11 @@ class FusedAPIImpl @Inject constructor(
        var errorApplicationCategory = ""
        var errorApplicationCategory = ""
        var apiStatus = ResultStatus.OK
        var apiStatus = ResultStatus.OK
        val categoryList = mutableListOf<FusedCategory>()
        val categoryList = mutableListOf<FusedCategory>()

        runCodeBlockWithTimeout({
        runCodeBlockWithTimeout({
            val playResponse = gPlayAPIRepository.getCategoriesList(type, authData).map { app ->

            val playResponse =
                gPlayAPIRepository.getCategoriesList(type, it ?: authData).map { app ->
                    val category = app.transformToFusedCategory()
                    val category = app.transformToFusedCategory()
                    updateCategoryDrawable(category)
                    updateCategoryDrawable(category)
                    category
                    category
@@ -1022,13 +1035,18 @@ class FusedAPIImpl @Inject constructor(
     * @return Instance of [ResultStatus] based on whether [block] was executed within timeout limit.
     * @return Instance of [ResultStatus] based on whether [block] was executed within timeout limit.
     */
     */
    private suspend fun runCodeBlockWithTimeout(
    private suspend fun runCodeBlockWithTimeout(
        block: suspend () -> Unit,
        block: suspend (authData: AuthData?) -> Unit,
        timeoutBlock: (() -> Unit)? = null,
        timeoutBlock: (() -> Unit)? = null,
        exceptionBlock: ((e: Exception) -> Unit)? = null,
        exceptionBlock: ((e: Exception) -> Unit)? = null,
    ): ResultStatus {
    ): ResultStatus {
        return try {
        return try {
            var authObject: AuthObject?
            withTimeout(timeoutDurationInMillis) {
            withTimeout(timeoutDurationInMillis) {
                block()
                authObject = executeBlockHandlingException(block)
            }

            authObject?.let {
                EventBus.invokeEvent(AppEvent.AuthUpdateEvent(it))
            }
            }
            ResultStatus.OK
            ResultStatus.OK
        } catch (e: TimeoutCancellationException) {
        } catch (e: TimeoutCancellationException) {
@@ -1043,6 +1061,35 @@ class FusedAPIImpl @Inject constructor(
        }
        }
    }
    }


    private suspend fun FusedAPIImpl.executeBlockHandlingException(
        block: suspend (authData: AuthData?) -> Unit,
    ): AuthObject? {
        return try {
            block(null)
            handleUnauthorizedAuthData(block)
        } catch (e: ApiException.AppNotFound) {
            Timber.w(e)
            handleUnauthorizedAuthData(block) ?: throw e
        }
    }

    private suspend fun handleUnauthorizedAuthData(
        block: suspend (authData: AuthData?) -> Unit
    ): AuthObject? {
        if (!GPlayHttpClient.IS_AUTH_VALID) {
            val loginSources = loginSourceRepository.getAuthObjects()

            loginSources.find { it is AuthObject.GPlayAuth }?.let {
                val authData = (it.result.data as AuthData)
                GPlayHttpClient.IS_AUTH_VALID = true
                block.invoke(authData)
                Timber.d("data refreshed with new auth!")
                return it
            }
        }
        return null
    }

    private fun updateCategoryDrawable(
    private fun updateCategoryDrawable(
        category: FusedCategory,
        category: FusedCategory,
    ) {
    ) {
@@ -1190,7 +1237,8 @@ class FusedAPIImpl @Inject constructor(
        query: String,
        query: String,
        authData: AuthData
        authData: AuthData
    ): LiveData<Pair<List<FusedApp>, Boolean>> {
    ): LiveData<Pair<List<FusedApp>, Boolean>> {
        val searchResults = gPlayAPIRepository.getSearchResults(query, authData, ::replaceWithFDroid)
        val searchResults =
            gPlayAPIRepository.getSearchResults(query, authData, ::replaceWithFDroid)
        return searchResults.map {
        return searchResults.map {
            Pair(
            Pair(
                it.first,
                it.first,
@@ -1336,8 +1384,11 @@ class FusedAPIImpl @Inject constructor(
                    updateFilterLevel(authData)
                    updateFilterLevel(authData)
                }
                }
            }
            }

            if (result.isNotEmpty()) {
                list.add(FusedHome(it.key, result))
                list.add(FusedHome(it.key, result))
            }
            }
        }
        return list
        return list
    }
    }


+5 −0
Original line number Original line Diff line number Diff line
@@ -47,6 +47,7 @@ class GPlayHttpClient @Inject constructor(


    companion object {
    companion object {
        private const val TAG = "GPlayHttpClient"
        private const val TAG = "GPlayHttpClient"
        var IS_AUTH_VALID = true
    }
    }


    private val okHttpClient = OkHttpClient().newBuilder()
    private val okHttpClient = OkHttpClient().newBuilder()
@@ -177,6 +178,10 @@ class GPlayHttpClient @Inject constructor(
        return PlayResponse().apply {
        return PlayResponse().apply {
            isSuccessful = response.isSuccessful
            isSuccessful = response.isSuccessful
            code = response.code
            code = response.code
            Timber.d("GplayHttpClient: Url: ${response.request.url} \n Status: ${response.code}")
            if (response.code == 401) {
                IS_AUTH_VALID = false
            }


            if (response.body != null) {
            if (response.body != null) {
                responseBytes = response.body!!.bytes()
                responseBytes = response.body!!.bytes()
+1 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@


package foundation.e.apps.login
package foundation.e.apps.login


import com.aurora.gplayapi.data.models.AuthData
import foundation.e.apps.utils.enums.User
import foundation.e.apps.utils.enums.User
import javax.inject.Inject
import javax.inject.Inject
import javax.inject.Singleton
import javax.inject.Singleton
Loading