diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultTangemPayCardDetailsRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultTangemPayCardDetailsRepository.kt index 12c3438e17..09a67952da 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultTangemPayCardDetailsRepository.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultTangemPayCardDetailsRepository.kt @@ -15,13 +15,19 @@ import com.tangem.datasource.api.pay.models.response.FreezeUnfreezeCardResponse import com.tangem.datasource.local.visa.TangemPayCardFrozenStateStore import com.tangem.datasource.local.visa.TangemPayStorage import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.pay.model.OrderStatus import com.tangem.domain.pay.model.SetPinResult import com.tangem.domain.pay.model.TangemPayCardBalance import com.tangem.domain.pay.model.TangemPayCardDetails import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository import com.tangem.domain.visa.model.TangemPayCardFrozenState +import kotlinx.coroutines.* import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import timber.log.Timber import javax.inject.Inject +import kotlin.time.Duration.Companion.seconds private const val TAG = "TangemPay: CardDetailsRepository" @@ -36,6 +42,10 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor( private val cardFrozenStateStore: TangemPayCardFrozenStateStore, ) : TangemPayCardDetailsRepository { + private val pollingScope = CoroutineScope(Dispatchers.IO + SupervisorJob()) + private val pollingJobs = mutableMapOf() + private val storePollingMutex = Mutex() + override suspend fun getCardBalance(userWalletId: UserWalletId): Either { return requestHelper.runWithErrorLogs(TAG) { val result = requestHelper.request(userWalletId) { authHeader -> @@ -143,6 +153,14 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor( null, -> TangemPayCardFrozenState.Unfrozen } + if (state == TangemPayCardFrozenState.Pending) { + startOrderIdPolling( + userWalletId = userWalletId, + cardId = cardId, + orderId = response.result?.orderId, + isFreeze = true, + ) + } cardFrozenStateStore.store(cardId, state) state @@ -168,12 +186,68 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor( null, -> TangemPayCardFrozenState.Frozen } + if (state == TangemPayCardFrozenState.Pending) { + startOrderIdPolling( + userWalletId = userWalletId, + cardId = cardId, + orderId = response.result?.orderId, + isFreeze = false, + ) + } cardFrozenStateStore.store(cardId, state) state } } + private suspend fun startOrderIdPolling( + userWalletId: UserWalletId, + cardId: String, + orderId: String?, + isFreeze: Boolean, + ) { + if (orderId.isNullOrEmpty()) return + storePollingMutex.withLock { + if (pollingJobs.containsKey(orderId)) return + val pollingJob = pollingScope.launch { + try { + while (isActive && pollingJobs.containsKey(orderId)) { + delay(duration = 5.seconds) + + val orderStatus = requestHelper.makeSafeRequest(userWalletId) { authHeader -> + tangemPayApi.getOrder(authHeader, orderId) + } + + orderStatus.onRight { response -> + val status = response.result?.status + if (status == OrderStatus.COMPLETED.apiName || status == OrderStatus.CANCELED.apiName) { + // Remove from jobs + pollingJobs.remove(key = orderId) + + // Final card state + val finalState = when { + status == OrderStatus.COMPLETED.apiName && isFreeze + -> TangemPayCardFrozenState.Frozen + status == OrderStatus.COMPLETED.apiName && !isFreeze + -> TangemPayCardFrozenState.Unfrozen + else -> return@launch + } + + cardFrozenStateStore.store(cardId, finalState) + } + } + } + } catch (e: Exception) { + Timber.e(e) + storePollingMutex.withLock { + pollingJobs.remove(orderId) + } + } + } + pollingJobs[orderId] = pollingJob + } + } + override fun cardFrozenState(cardId: String): Flow { return cardFrozenStateStore.get(cardId) }