Updated on 2026-08-14

This commit is contained in:
Tangem 2023-01-09 15:20:29 +04:00
parent ae4c521813
commit e56e411930
6 changed files with 75 additions and 76 deletions

View file

@ -1,48 +1,49 @@
package com.tangem.tap.domain
import com.tangem.common.services.Result
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.domain.common.ThrottlerWithValues
import com.tangem.datasource.api.tangemTech.TangemTechService
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.store
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.withContext
import java.math.BigDecimal
//TODO: refactoring: move to domain
class RatesRepository {
private val tangemTechService: TangemTechService
get() = store.state.domainNetworks.tangemTechService
class RatesRepository(
private val tangemTechApi: TangemTechApi,
private val dispatchers: CoroutineDispatcherProvider,
) {
private val throttler = ThrottlerWithValues<Currency, Result<BigDecimal>?>(60000)
suspend fun loadFiatRate(currencyId: String, coinsList: List<Currency>): Result<RatesResult> {
// get and submit previous result of equivalents.
val throttledResult = coinsList.filter { throttler.isStillThrottled(it) }.map {
Pair(it, throttler.geValue(it))
}
val currenciesToUpdate = coinsList.filter { !throttler.isStillThrottled(it) }
val coinIds = currenciesToUpdate.mapNotNull { it.coinId }.distinct()
if (coinIds.isEmpty()) return handleFiatRatesResult(throttledResult.toMap())
return when (val result = tangemTechService.rates(currencyId, coinIds)) {
is Result.Success -> {
val ratesResultList: Map<String, Result<BigDecimal>> = result.data.rates.mapValues {
Result.Success(it.value.toBigDecimal())
}
val updatedCurrencies = throttledResult.toMap().toMutableMap()
coinsList.forEach { currency ->
ratesResultList[currency.coinId]?.let {
updatedCurrencies[currency] = it
throttler.updateThrottlingTo(currency)
throttler.setValue(currency, it)
}
}
handleFiatRatesResult(updatedCurrencies)
suspend fun loadFiatRate(currencyId: String, coinsList: List<Currency>): Result<RatesResult> =
withContext(dispatchers.io) {
// get and submit previous result of equivalents.
val throttledResult = coinsList.filter { throttler.isStillThrottled(it) }.map {
Pair(it, throttler.geValue(it))
}
is Result.Failure -> Result.Failure(result.error)
val currenciesToUpdate = coinsList.filter { !throttler.isStillThrottled(it) }
val coinIds = currenciesToUpdate.mapNotNull { it.coinId }.distinct()
if (coinIds.isEmpty()) return@withContext handleFiatRatesResult(throttledResult.toMap())
runCatching { tangemTechApi.getRates(currencyId.lowercase(), coinIds.joinToString(",")) }
.onSuccess { response ->
val ratesResultList: Map<String, Result<BigDecimal>> = response.rates.mapValues {
Result.Success(it.value.toBigDecimal())
}
val updatedCurrencies = throttledResult.toMap().toMutableMap()
coinsList.forEach { currency ->
ratesResultList[currency.coinId]?.let {
updatedCurrencies[currency] = it
throttler.updateThrottlingTo(currency)
throttler.setValue(currency, it)
}
}
return@withContext handleFiatRatesResult(updatedCurrencies)
}
.onFailure { Result.Failure(it) }
throw IllegalStateException("Unreachable code because runCatching must return result")
}
}
private fun handleFiatRatesResult(rates: Map<Currency, Result<BigDecimal>?>): Result.Success<RatesResult> {
val success = mutableMapOf<Currency, BigDecimal>()

View file

@ -36,6 +36,7 @@ import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
import com.tangem.tap.userTokensRepository
import com.tangem.tap.walletStoresManager
import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import timber.log.Timber
@ -43,7 +44,14 @@ import timber.log.Timber
class TapWalletManager {
val walletManagerFactory: WalletManagerFactory
by lazy { WalletManagerFactory(blockchainSdkConfig) }
val rates: RatesRepository = RatesRepository()
// TODO("After adding DI") get dependencies by DI
val rates: RatesRepository by lazy {
RatesRepository(
tangemTechApi = store.state.domainNetworks.tangemTechService.api,
dispatchers = AppCoroutineDispatcherProvider(),
)
}
private val blockchainSdkConfig by lazy {
store.state.globalState.configManager?.config?.blockchainSdkConfig ?: BlockchainSdkConfig()

View file

@ -8,6 +8,7 @@ import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository
import com.tangem.tap.domain.walletStores.repository.implementation.DefaultWalletAmountsRepository
import com.tangem.tap.domain.walletStores.repository.implementation.DefaultWalletManagersRepository
import com.tangem.tap.domain.walletStores.repository.implementation.DefaultWalletStoresRepository
import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
fun WalletStoresRepository.Companion.provideDefaultImplementation(): WalletStoresRepository {
return DefaultWalletStoresRepository()
@ -22,5 +23,9 @@ fun WalletManagersRepository.Companion.provideDefaultImplementation(
fun WalletAmountsRepository.Companion.provideDefaultImplementation(
tangemTechService: TangemTechService,
): WalletAmountsRepository {
return DefaultWalletAmountsRepository(tangemTechService)
// TODO("After adding DI") get dependencies by DI
return DefaultWalletAmountsRepository(
tangemTechApi = tangemTechService.api,
dispatchers = AppCoroutineDispatcherProvider(),
)
}

View file

@ -14,8 +14,7 @@ import com.tangem.common.flatMap
import com.tangem.common.flatMapOnFailure
import com.tangem.common.fold
import com.tangem.common.map
import com.tangem.common.services.Result
import com.tangem.datasource.api.tangemTech.TangemTechService
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.util.UserWalletId
import com.tangem.tap.common.entities.FiatCurrency
@ -34,10 +33,12 @@ import com.tangem.tap.domain.walletStores.repository.implementation.utils.update
import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithUnreachable
import com.tangem.tap.domain.walletStores.storage.WalletManagerStorage
import com.tangem.tap.domain.walletStores.storage.WalletStoresStorage
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.models.PendingTransactionType
import com.tangem.tap.features.wallet.models.filterByCoin
import com.tangem.tap.features.wallet.models.getPendingTransactions
import com.tangem.tap.network.NetworkConnectivity
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
@ -47,7 +48,8 @@ import timber.log.Timber
import java.math.BigDecimal
internal class DefaultWalletAmountsRepository(
private val tangemTechService: TangemTechService,
private val tangemTechApi: TangemTechApi,
private val dispatchers: CoroutineDispatcherProvider,
) : WalletAmountsRepository {
private val walletStoresStorage = WalletStoresStorage
private val walletManagersStorage = WalletManagerStorage
@ -119,39 +121,31 @@ internal class DefaultWalletAmountsRepository(
val coinsIds = currencies.mapNotNull { it.coinId }.distinct().toList()
val fiatRatesResult = withContext(Dispatchers.IO) {
tangemTechService.rates(
currency = fiatCurrency.code,
ids = coinsIds,
)
}
return withContext(dispatchers.io) {
runCatching { tangemTechApi.getRates(fiatCurrency.code.lowercase(), coinsIds.joinToString(",")) }
.onSuccess {
updateWalletStoresWithFiatRates(walletStores = walletStores, fiatRates = it.rates)
return@withContext CompletionResult.Success(Unit)
}
.onFailure {
val error = WalletStoresError.FetchFiatRatesError(
currencies = currencies.map(Currency::currencySymbol).toList(),
cause = it,
)
return when (fiatRatesResult) {
is Result.Success -> {
updateWalletStoresWithFiatRates(
walletStores = walletStores,
fiatRates = fiatRatesResult.data.rates,
)
CompletionResult.Success(Unit)
}
is Result.Failure -> {
val error = WalletStoresError.FetchFiatRatesError(
currencies = currencies.map { it.currencySymbol }.toList(),
cause = fiatRatesResult.error,
)
Timber.e(
error,
"""
Timber.e(
error,
"""
Unable to fetch fiat rates
|- User wallets ids: $walletsIds
|- Coins ids: $coinsIds
""".trimIndent(),
)
)
CompletionResult.Failure(error)
}
return@withContext CompletionResult.Failure(error)
}
throw IllegalStateException("Unreachable code because runCatching must return result")
}
}

View file

@ -26,7 +26,7 @@ interface TangemTechApi {
): CoinsResponse
@GET("rates")
suspend fun rates(
suspend fun getRates(
@Query("currencyId") currencyId: String,
@Query("coinIds") coinIds: String,
): RatesResponse

View file

@ -41,15 +41,6 @@ class TangemTechService(
}
}
suspend fun rates(
currency: String,
ids: List<String>,
): Result<RatesResponse> = withContext(Dispatchers.IO) {
performRequest {
api.rates(currency.lowercase(), ids.joinToString(","))
}
}
fun addHeaderInterceptors(interceptors: List<AddHeaderInterceptor>) {
headerInterceptors.removeAll(interceptors)
headerInterceptors.addAll(interceptors)