Updated on 2026-08-14
This commit is contained in:
parent
2a8e79ed67
commit
012792e586
7 changed files with 248 additions and 49 deletions
|
|
@ -46,7 +46,7 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
override suspend fun invoke(params: PaymentAccountStatusFetcher.Params): Either<Throwable, Unit> =
|
||||
Either.catchOn(dispatchers.default) {
|
||||
val account = Account.Payment(userWalletId = params.userWalletId)
|
||||
logger.i("fetch: ${params.userWalletId.stringValue}")
|
||||
logger.i("invoke() start: ${params.userWalletId.stringValue}")
|
||||
|
||||
if (deviceSecurity.isSecurityExposed()) {
|
||||
logger.i("fetch security info: rooted: ${deviceSecurity.isRooted}")
|
||||
|
|
@ -80,11 +80,14 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
userWalletId = params.userWalletId,
|
||||
status = AccountStatus.Payment(account = account, value = status),
|
||||
)
|
||||
}.onLeft {
|
||||
}.onLeft { throwable ->
|
||||
logger.e("invoke() ${params.userWalletId} threw, falling back to ONLY_CACHE", throwable)
|
||||
paymentAccountStatusesStore.updateStatusSource(
|
||||
userWalletId = params.userWalletId,
|
||||
source = StatusSource.ONLY_CACHE,
|
||||
)
|
||||
}.also { result ->
|
||||
logger.i("invoke() end ${params.userWalletId}: isRight=${result.isRight()}")
|
||||
}
|
||||
|
||||
private suspend fun proceedHasTangemPayResult(
|
||||
|
|
@ -101,7 +104,12 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
|
||||
private suspend fun fetchTangemPayAccountStatus(account: Account.Payment): PaymentAccountStatusValue {
|
||||
val prevResult = paymentAccountStatusesStore.getSyncOrNull(account.userWalletId)
|
||||
logger.i(
|
||||
"fetchTangemPayAccountStatus ${account.userWalletId}: " +
|
||||
"prevResultType=${prevResult?.value?.let { it::class.simpleName } ?: "null"}",
|
||||
)
|
||||
if (prevResult == null || prevResult.value is PaymentAccountStatusValue.Error.Unavailable) {
|
||||
logger.i("fetchTangemPayAccountStatus ${account.userWalletId}: writing Loading placeholder to store")
|
||||
paymentAccountStatusesStore.store(
|
||||
userWalletId = account.userWalletId,
|
||||
status = AccountStatus.Payment(account = account, value = PaymentAccountStatusValue.Loading),
|
||||
|
|
@ -112,10 +120,13 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
}
|
||||
|
||||
private suspend fun proceedWithOrderId(account: Account.Payment): PaymentAccountStatusValue {
|
||||
return if (!onboardingRepository.isTangemPayInitialDataProduced(account.userWalletId)) {
|
||||
val isInitial = onboardingRepository.isTangemPayInitialDataProduced(account.userWalletId)
|
||||
logger.i("proceedWithOrderId ${account.userWalletId}: isTangemPayInitialDataProduced=$isInitial")
|
||||
return if (!isInitial) {
|
||||
PaymentAccountStatusValue.Error.NotSynced
|
||||
} else {
|
||||
val orderId = onboardingRepository.getOrderId(account.userWalletId)
|
||||
logger.i("proceedWithOrderId ${account.userWalletId}: orderIdPresent=${orderId != null}")
|
||||
if (orderId != null) {
|
||||
proceedWithOrderId(account = account, orderId = orderId)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -9,12 +9,17 @@ import com.tangem.domain.models.account.AccountStatus
|
|||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||
import com.tangem.domain.pay.flow.PaymentAccountStatusProducer
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.onEmpty
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
|
||||
private const val TAG = "PaymentAccountStatusProducer"
|
||||
|
||||
internal class DefaultPaymentAccountStatusProducer @AssistedInject constructor(
|
||||
@Assisted private val params: PaymentAccountStatusProducer.Params,
|
||||
|
|
@ -24,13 +29,20 @@ internal class DefaultPaymentAccountStatusProducer @AssistedInject constructor(
|
|||
) : PaymentAccountStatusProducer {
|
||||
|
||||
private val account = Account.Payment(userWalletId = params.userWalletId)
|
||||
private val logger = TangemLogger.withTag(TAG)
|
||||
|
||||
override val fallback: Option<AccountStatus.Payment>
|
||||
get() = AccountStatus.Payment(account = account, value = PaymentAccountStatusValue.Error.Unavailable).some()
|
||||
|
||||
override fun produce(): Flow<AccountStatus.Payment> {
|
||||
logger.i("[${params.userWalletId}] produce() called")
|
||||
return paymentAccountStatusesStore.get(userWalletId = params.userWalletId)
|
||||
.onEmpty { emit(value = AccountStatus.Payment(account, PaymentAccountStatusValue.NotCreated)) }
|
||||
.onStart { logger.i("[${params.userWalletId}] flow subscribed to store") }
|
||||
.onEach { logger.i("[${params.userWalletId}] flow emits statusType=${it.value::class.simpleName}") }
|
||||
.onEmpty {
|
||||
logger.i("[${params.userWalletId}] onEmpty triggered: emitting NotCreated fallback")
|
||||
emit(value = AccountStatus.Payment(account, PaymentAccountStatusValue.NotCreated))
|
||||
}
|
||||
.flowOn(dispatchers.default)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,11 +15,15 @@ import kotlinx.coroutines.coroutineScope
|
|||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
internal typealias WalletIdWithPaymentStatus = Map<String, AccountStatus.Payment>
|
||||
internal typealias WalletIdWithPaymentStatusDM = Map<String, PaymentAccountStatusValueDM>
|
||||
|
||||
private const val TAG = "PaymentAccountStatusesStore"
|
||||
|
||||
/**
|
||||
* Store for payment account statuses with dual storage (runtime + persistence).
|
||||
*
|
||||
|
|
@ -32,10 +36,18 @@ internal class PaymentAccountStatusesStore(
|
|||
scope: AppCoroutineScope,
|
||||
) {
|
||||
|
||||
private val logger = TangemLogger.withTag(TAG)
|
||||
|
||||
init {
|
||||
scope.launch {
|
||||
logger.i("init: loading cached payment statuses from persistence")
|
||||
try {
|
||||
val cachedStatuses = persistenceDataStore.data.firstOrNull() ?: return@launch
|
||||
val cachedStatuses = persistenceDataStore.data.firstOrNull()
|
||||
if (cachedStatuses == null) {
|
||||
logger.i("init: persistence empty (firstOrNull == null), runtimeStore stays empty")
|
||||
return@launch
|
||||
}
|
||||
logger.i("init: loaded ${cachedStatuses.size} cached entries; populating runtimeStore")
|
||||
runtimeStore.store(
|
||||
value = cachedStatuses.mapValues { (rawUserWalletId, statusDM) ->
|
||||
val account = Account.Payment(userWalletId = UserWalletId(rawUserWalletId))
|
||||
|
|
@ -43,18 +55,32 @@ internal class PaymentAccountStatusesStore(
|
|||
AccountStatus.Payment(account = account, value = statusValue)
|
||||
},
|
||||
)
|
||||
logger.i("init: runtimeStore populated with ${cachedStatuses.size} entries")
|
||||
} catch (e: Exception) {
|
||||
TangemLogger.e("Error while loading cached payment account statuses", e)
|
||||
logger.e("Error while loading cached payment account statuses", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun get(userWalletId: UserWalletId): Flow<AccountStatus.Payment> {
|
||||
return runtimeStore.get().mapNotNull { it[userWalletId.stringValue] }
|
||||
return runtimeStore.get()
|
||||
.onStart { logger.i("get($userWalletId): subscribed to runtimeStore") }
|
||||
.onEach { map ->
|
||||
logger.i(
|
||||
"get($userWalletId): runtimeStore emitted map size=${map.size}, " +
|
||||
"hasEntry=${map.containsKey(userWalletId.stringValue)}",
|
||||
)
|
||||
}
|
||||
.mapNotNull { it[userWalletId.stringValue] }
|
||||
.onEach { status ->
|
||||
logger.i("get($userWalletId): emitting statusType=${status.value::class.simpleName}")
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getSyncOrNull(userWalletId: UserWalletId): AccountStatus.Payment? {
|
||||
return runtimeStore.getSyncOrNull()?.get(userWalletId.stringValue)
|
||||
val result = runtimeStore.getSyncOrNull()?.get(userWalletId.stringValue)
|
||||
logger.i("getSyncOrNull($userWalletId) valueType=${result?.value?.let { it::class.simpleName } ?: "null"}")
|
||||
return result
|
||||
}
|
||||
|
||||
suspend fun updateStatusSource(userWalletId: UserWalletId, source: StatusSource) {
|
||||
|
|
@ -68,6 +94,7 @@ internal class PaymentAccountStatusesStore(
|
|||
}
|
||||
|
||||
suspend fun store(userWalletId: UserWalletId, status: AccountStatus.Payment) {
|
||||
logger.i("store($userWalletId): valueType=${status.value::class.simpleName}")
|
||||
coroutineScope {
|
||||
launch { storeInRuntime(userWalletId = userWalletId, status = status) }
|
||||
launch { storeInPersistence(userWalletId = userWalletId, status = status.value) }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue