Updated on 2026-08-14

This commit is contained in:
Tangem 2023-08-11 15:03:22 +03:00
parent 11687f6368
commit a2e602f1f1
4 changed files with 109 additions and 31 deletions

View file

@ -3,8 +3,9 @@ package com.tangem.data.tokens.di
import com.tangem.data.common.cache.CacheRegistry
import com.tangem.data.tokens.repository.DefaultCurrenciesRepository
import com.tangem.data.tokens.repository.DefaultNetworksRepository
import com.tangem.data.tokens.repository.MockQuotesRepository
import com.tangem.data.tokens.repository.DefaultQuotesRepository
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.local.quote.QuotesStore
import com.tangem.datasource.local.token.UserTokensStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.tokens.repository.CurrenciesRepository
@ -36,7 +37,14 @@ internal object TokensDataModule {
@Provides
@Singleton
fun provideQuotesRepository(): QuotesRepository = MockQuotesRepository()
fun provideQuotesRepository(
tangemTechApi: TangemTechApi,
quotesStore: QuotesStore,
cacheRegistry: CacheRegistry,
dispatchers: CoroutineDispatcherProvider,
): QuotesRepository {
return DefaultQuotesRepository(tangemTechApi, quotesStore, cacheRegistry, dispatchers)
}
@Provides
@Singleton

View file

@ -0,0 +1,81 @@
package com.tangem.data.tokens.repository
import com.tangem.data.common.cache.CacheRegistry
import com.tangem.data.tokens.utils.QuotesConverter
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.local.quote.QuotesStore
import com.tangem.domain.tokens.models.CryptoCurrency
import com.tangem.domain.tokens.models.Quote
import com.tangem.domain.tokens.repository.QuotesRepository
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import timber.log.Timber
internal class DefaultQuotesRepository(
private val tangemTechApi: TangemTechApi,
private val quotesStore: QuotesStore,
private val cacheRegistry: CacheRegistry,
private val dispatchers: CoroutineDispatcherProvider,
) : QuotesRepository {
private val quotesConverter = QuotesConverter()
override fun getQuotes(currenciesIds: Set<CryptoCurrency.ID>, refresh: Boolean): Flow<Set<Quote>> {
return channelFlow {
launch(dispatchers.io) {
quotesStore.get(currenciesIds)
.map(quotesConverter::convertSet)
.collect(::send)
}
launch(dispatchers.io) {
fetchExpiredQuotes(currenciesIds, refresh)
}
}
}
private suspend fun fetchExpiredQuotes(currenciesIds: Set<CryptoCurrency.ID>, refresh: Boolean) {
val expiredCurrenciesIds = filterExpiredCurrenciesIds(currenciesIds, refresh)
if (expiredCurrenciesIds.isEmpty()) return
fetchQuotes(expiredCurrenciesIds)
}
private suspend fun fetchQuotes(rawCurrenciesIds: Set<String>) {
try {
val response = tangemTechApi.getQuotes(
currencyId = "usd", // TODO: [REDACTED_JIRA]
coinIds = rawCurrenciesIds.joinToString(separator = ","),
)
quotesStore.store(response)
} catch (e: Throwable) {
Timber.e(e, "Unable to fetch quotes for: $rawCurrenciesIds")
throw e
}
}
private suspend fun filterExpiredCurrenciesIds(
currenciesIds: Set<CryptoCurrency.ID>,
refresh: Boolean,
): Set<String> {
return currenciesIds.fold(hashSetOf()) { acc, currencyId ->
val rawCurrencyId = currencyId.rawCurrencyId
if (rawCurrencyId != null && rawCurrencyId !in acc) {
cacheRegistry.invokeOnExpire(
key = getQuoteCacheKey(rawCurrencyId),
skipCache = refresh,
block = { acc.add(rawCurrencyId) },
)
}
acc
}
}
private fun getQuoteCacheKey(rawCurrencyId: String): String = "quote_$rawCurrencyId"
}

View file

@ -1,29 +0,0 @@
package com.tangem.data.tokens.repository
import com.tangem.domain.tokens.models.CryptoCurrency
import com.tangem.domain.tokens.models.Quote
import com.tangem.domain.tokens.repository.QuotesRepository
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import java.math.BigDecimal
import kotlin.random.Random
internal class MockQuotesRepository : QuotesRepository {
override fun getQuotes(currenciesIds: Set<CryptoCurrency.ID>, refresh: Boolean): Flow<Set<Quote>> {
return channelFlow {
val quotes = currenciesIds.mapNotNullTo(hashSetOf()) { id ->
Quote(
rawCurrencyId = id.rawCurrencyId ?: return@mapNotNullTo null,
fiatRate = BigDecimal.ZERO,
priceChange = BigDecimal.ZERO,
)
}
delay(Random.nextLong(from = 200, until = 2_000))
send(quotes)
}
}
}

View file

@ -0,0 +1,18 @@
package com.tangem.data.tokens.utils
import com.tangem.datasource.local.quote.model.StoredQuote
import com.tangem.domain.tokens.models.Quote
import com.tangem.utils.converter.Converter
internal class QuotesConverter : Converter<StoredQuote, Quote> {
override fun convert(value: StoredQuote): Quote {
val (rawCurrencyId, responseQuote) = value
return Quote(
rawCurrencyId = rawCurrencyId,
fiatRate = responseQuote.price,
priceChange = responseQuote.priceChange.movePointLeft(2),
)
}
}