Loading app/src/main/java/foundation/e/apps/AppLoungeApplication.kt +6 −0 Original line number Original line Diff line number Diff line Loading @@ -30,6 +30,7 @@ import foundation.e.apps.data.Constants.TAG_APP_INSTALL_STATE import foundation.e.apps.data.Constants.TAG_AUTHDATA_DUMP import foundation.e.apps.data.Constants.TAG_AUTHDATA_DUMP import foundation.e.apps.data.preference.AppLoungeDataStore import foundation.e.apps.data.preference.AppLoungeDataStore import foundation.e.apps.data.preference.AppLoungePreference import foundation.e.apps.data.preference.AppLoungePreference import foundation.e.apps.domain.usecases.ReportFaultyGPlayUser import foundation.e.apps.install.pkg.AppLoungePackageManager import foundation.e.apps.install.pkg.AppLoungePackageManager import foundation.e.apps.install.pkg.PkgManagerBR import foundation.e.apps.install.pkg.PkgManagerBR import foundation.e.apps.install.updates.UpdatesWorkManager import foundation.e.apps.install.updates.UpdatesWorkManager Loading Loading @@ -66,6 +67,9 @@ class AppLoungeApplication : Application(), Configuration.Provider { @Inject @Inject lateinit var uncaughtExceptionHandler: CustomUncaughtExceptionHandler lateinit var uncaughtExceptionHandler: CustomUncaughtExceptionHandler @Inject lateinit var reportFaultyGPlayUser: ReportFaultyGPlayUser @RequiresApi(Build.VERSION_CODES.TIRAMISU) @RequiresApi(Build.VERSION_CODES.TIRAMISU) override fun onCreate() { override fun onCreate() { super.onCreate() super.onCreate() Loading Loading @@ -109,6 +113,8 @@ class AppLoungeApplication : Application(), Configuration.Provider { appLoungePreference.getUpdateInterval(), appLoungePreference.getUpdateInterval(), ExistingPeriodicWorkPolicy.KEEP ExistingPeriodicWorkPolicy.KEEP ) ) reportFaultyGPlayUser.listen() } } override val workManagerConfiguration: Configuration override val workManagerConfiguration: Configuration Loading app/src/main/java/foundation/e/apps/data/login/AuthObject.kt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -42,6 +42,7 @@ sealed class AuthObject { abstract fun createInvalidAuthObject(): AuthObject abstract fun createInvalidAuthObject(): AuthObject class GPlayAuth(override val result: ResultSupreme<AuthData?>, override val user: User) : AuthObject() { class GPlayAuth(override val result: ResultSupreme<AuthData?>, override val user: User) : AuthObject() { // Seule création de GPlayValidationException override fun createInvalidAuthObject(): AuthObject { override fun createInvalidAuthObject(): AuthObject { val message = "Validating AuthData failed.\nNetwork code: 401" val message = "Validating AuthData failed.\nNetwork code: 401" Loading app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepository.kt +21 −1 Original line number Original line Diff line number Diff line Loading @@ -57,6 +57,8 @@ import foundation.e.apps.utils.exponentialBackoffRetry import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first Loading Loading @@ -89,6 +91,9 @@ class PlayStoreRepository @Inject constructor( private val gPlayHttpClientPukedExceptionWaitDuration: Duration = 10.milliseconds private val gPlayHttpClientPukedExceptionWaitDuration: Duration = 10.milliseconds } } private val _faultyEmail = MutableSharedFlow<String>() val faultyEmail: Flow<String> = _faultyEmail suspend fun updateToken(): AuthData { suspend fun updateToken(): AuthData { val userType = appLoungeDataStore.getUser() val userType = appLoungeDataStore.getUser() Loading Loading @@ -409,13 +414,28 @@ class PlayStoreRepository @Inject constructor( } } private suspend fun <T> doAuthenticatedRequest(request: suspend (AuthData) -> T): T { private suspend fun <T> doAuthenticatedRequest(request: suspend (AuthData) -> T): T { val authData = appLoungeDataStore.getAuthData() return try { gPlayRequestWithUnswallowedException { request(authData) } } catch(e: HttpUnauthorizedException) { _faultyEmail.emit(authData.email) throw e } } private suspend fun <T> doAuthenticatedRequestAutoRefreshToken(request: suspend (AuthData) -> T): T { return exponentialBackoffRetry( return exponentialBackoffRetry( initialDelay = 100.milliseconds, initialDelay = 100.milliseconds, maxDelay = 15.seconds, // exp: 0,2, 0,4, 0,8, 1,6, 3,2, 6,4 ; 12,8 . maxDelay = 15.seconds, // exp: 0,2, 0,4, 0,8, 1,6, 3,2, 6,4 ; 12,8 . work = { work = { gPlayRequestWithUnswallowedException { request(appLoungeDataStore.getAuthData()) } gPlayRequestWithUnswallowedException { request(appLoungeDataStore.getAuthData()) } }, }, predicate = { exception -> exception is HttpUnauthorizedException }, predicate = { exception -> if (exception is HttpUnauthorizedException) { _faultyEmail.emit(appLoungeDataStore.getAuthData().email) true } else false }, doBeforeRetry = { refreshPlayStoreAuthentication() } doBeforeRetry = { refreshPlayStoreAuthentication() } ) ) } } Loading app/src/main/java/foundation/e/apps/domain/usecases/LoginUseCase.kt +0 −1 Original line number Original line Diff line number Diff line Loading @@ -74,7 +74,6 @@ class LoginUseCase @Inject constructor( status = ResultStatus.OK, status = ResultStatus.OK, data = gPlayloginResult.getOrNull() data = gPlayloginResult.getOrNull() ) ) result.otherPayload = gPlayloginResult.getOrNull()?.email } else { } else { result = ResultSupreme.create( result = ResultSupreme.create( status = ResultStatus.UNKNOWN, status = ResultStatus.UNKNOWN, Loading app/src/main/java/foundation/e/apps/domain/usecases/ReportFaultyGPlayUser.kt 0 → 100644 +38 −0 Original line number Original line Diff line number Diff line package foundation.e.apps.domain.usecases import foundation.e.apps.data.ecloud.EcloudRepository import foundation.e.apps.data.enums.User import foundation.e.apps.data.playstore.PlayStoreRepository import foundation.e.apps.data.preference.AppLoungeDataStore import foundation.e.apps.di.qualifiers.IoCoroutineScope import foundation.e.apps.utils.SystemInfoProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import timber.log.Timber import javax.inject.Inject import javax.inject.Singleton @Singleton class ReportFaultyGPlayUser @Inject constructor( private val playStoreRepository: PlayStoreRepository, private val ecloudRepository: EcloudRepository, private val appLoungeDataStore: AppLoungeDataStore, @IoCoroutineScope private val ioCoroutineScope: CoroutineScope ) { fun listen() { playStoreRepository.faultyEmail.map(::report).launchIn(ioCoroutineScope) } private suspend fun report(email: String) { if (appLoungeDataStore.getUser() != User.ANONYMOUS) { return } runCatching { ecloudRepository.uploadFaultyEmail(email,SystemInfoProvider.getAppBuildInfo()) }.onFailure { Timber.w(it, "Can't report faulty anonymous email: $email") } } } Loading
app/src/main/java/foundation/e/apps/AppLoungeApplication.kt +6 −0 Original line number Original line Diff line number Diff line Loading @@ -30,6 +30,7 @@ import foundation.e.apps.data.Constants.TAG_APP_INSTALL_STATE import foundation.e.apps.data.Constants.TAG_AUTHDATA_DUMP import foundation.e.apps.data.Constants.TAG_AUTHDATA_DUMP import foundation.e.apps.data.preference.AppLoungeDataStore import foundation.e.apps.data.preference.AppLoungeDataStore import foundation.e.apps.data.preference.AppLoungePreference import foundation.e.apps.data.preference.AppLoungePreference import foundation.e.apps.domain.usecases.ReportFaultyGPlayUser import foundation.e.apps.install.pkg.AppLoungePackageManager import foundation.e.apps.install.pkg.AppLoungePackageManager import foundation.e.apps.install.pkg.PkgManagerBR import foundation.e.apps.install.pkg.PkgManagerBR import foundation.e.apps.install.updates.UpdatesWorkManager import foundation.e.apps.install.updates.UpdatesWorkManager Loading Loading @@ -66,6 +67,9 @@ class AppLoungeApplication : Application(), Configuration.Provider { @Inject @Inject lateinit var uncaughtExceptionHandler: CustomUncaughtExceptionHandler lateinit var uncaughtExceptionHandler: CustomUncaughtExceptionHandler @Inject lateinit var reportFaultyGPlayUser: ReportFaultyGPlayUser @RequiresApi(Build.VERSION_CODES.TIRAMISU) @RequiresApi(Build.VERSION_CODES.TIRAMISU) override fun onCreate() { override fun onCreate() { super.onCreate() super.onCreate() Loading Loading @@ -109,6 +113,8 @@ class AppLoungeApplication : Application(), Configuration.Provider { appLoungePreference.getUpdateInterval(), appLoungePreference.getUpdateInterval(), ExistingPeriodicWorkPolicy.KEEP ExistingPeriodicWorkPolicy.KEEP ) ) reportFaultyGPlayUser.listen() } } override val workManagerConfiguration: Configuration override val workManagerConfiguration: Configuration Loading
app/src/main/java/foundation/e/apps/data/login/AuthObject.kt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -42,6 +42,7 @@ sealed class AuthObject { abstract fun createInvalidAuthObject(): AuthObject abstract fun createInvalidAuthObject(): AuthObject class GPlayAuth(override val result: ResultSupreme<AuthData?>, override val user: User) : AuthObject() { class GPlayAuth(override val result: ResultSupreme<AuthData?>, override val user: User) : AuthObject() { // Seule création de GPlayValidationException override fun createInvalidAuthObject(): AuthObject { override fun createInvalidAuthObject(): AuthObject { val message = "Validating AuthData failed.\nNetwork code: 401" val message = "Validating AuthData failed.\nNetwork code: 401" Loading
app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepository.kt +21 −1 Original line number Original line Diff line number Diff line Loading @@ -57,6 +57,8 @@ import foundation.e.apps.utils.exponentialBackoffRetry import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first Loading Loading @@ -89,6 +91,9 @@ class PlayStoreRepository @Inject constructor( private val gPlayHttpClientPukedExceptionWaitDuration: Duration = 10.milliseconds private val gPlayHttpClientPukedExceptionWaitDuration: Duration = 10.milliseconds } } private val _faultyEmail = MutableSharedFlow<String>() val faultyEmail: Flow<String> = _faultyEmail suspend fun updateToken(): AuthData { suspend fun updateToken(): AuthData { val userType = appLoungeDataStore.getUser() val userType = appLoungeDataStore.getUser() Loading Loading @@ -409,13 +414,28 @@ class PlayStoreRepository @Inject constructor( } } private suspend fun <T> doAuthenticatedRequest(request: suspend (AuthData) -> T): T { private suspend fun <T> doAuthenticatedRequest(request: suspend (AuthData) -> T): T { val authData = appLoungeDataStore.getAuthData() return try { gPlayRequestWithUnswallowedException { request(authData) } } catch(e: HttpUnauthorizedException) { _faultyEmail.emit(authData.email) throw e } } private suspend fun <T> doAuthenticatedRequestAutoRefreshToken(request: suspend (AuthData) -> T): T { return exponentialBackoffRetry( return exponentialBackoffRetry( initialDelay = 100.milliseconds, initialDelay = 100.milliseconds, maxDelay = 15.seconds, // exp: 0,2, 0,4, 0,8, 1,6, 3,2, 6,4 ; 12,8 . maxDelay = 15.seconds, // exp: 0,2, 0,4, 0,8, 1,6, 3,2, 6,4 ; 12,8 . work = { work = { gPlayRequestWithUnswallowedException { request(appLoungeDataStore.getAuthData()) } gPlayRequestWithUnswallowedException { request(appLoungeDataStore.getAuthData()) } }, }, predicate = { exception -> exception is HttpUnauthorizedException }, predicate = { exception -> if (exception is HttpUnauthorizedException) { _faultyEmail.emit(appLoungeDataStore.getAuthData().email) true } else false }, doBeforeRetry = { refreshPlayStoreAuthentication() } doBeforeRetry = { refreshPlayStoreAuthentication() } ) ) } } Loading
app/src/main/java/foundation/e/apps/domain/usecases/LoginUseCase.kt +0 −1 Original line number Original line Diff line number Diff line Loading @@ -74,7 +74,6 @@ class LoginUseCase @Inject constructor( status = ResultStatus.OK, status = ResultStatus.OK, data = gPlayloginResult.getOrNull() data = gPlayloginResult.getOrNull() ) ) result.otherPayload = gPlayloginResult.getOrNull()?.email } else { } else { result = ResultSupreme.create( result = ResultSupreme.create( status = ResultStatus.UNKNOWN, status = ResultStatus.UNKNOWN, Loading
app/src/main/java/foundation/e/apps/domain/usecases/ReportFaultyGPlayUser.kt 0 → 100644 +38 −0 Original line number Original line Diff line number Diff line package foundation.e.apps.domain.usecases import foundation.e.apps.data.ecloud.EcloudRepository import foundation.e.apps.data.enums.User import foundation.e.apps.data.playstore.PlayStoreRepository import foundation.e.apps.data.preference.AppLoungeDataStore import foundation.e.apps.di.qualifiers.IoCoroutineScope import foundation.e.apps.utils.SystemInfoProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import timber.log.Timber import javax.inject.Inject import javax.inject.Singleton @Singleton class ReportFaultyGPlayUser @Inject constructor( private val playStoreRepository: PlayStoreRepository, private val ecloudRepository: EcloudRepository, private val appLoungeDataStore: AppLoungeDataStore, @IoCoroutineScope private val ioCoroutineScope: CoroutineScope ) { fun listen() { playStoreRepository.faultyEmail.map(::report).launchIn(ioCoroutineScope) } private suspend fun report(email: String) { if (appLoungeDataStore.getUser() != User.ANONYMOUS) { return } runCatching { ecloudRepository.uploadFaultyEmail(email,SystemInfoProvider.getAppBuildInfo()) }.onFailure { Timber.w(it, "Can't report faulty anonymous email: $email") } } }