Updated on 2026-08-14
This commit is contained in:
parent
11687f6368
commit
a2e602f1f1
4 changed files with 109 additions and 31 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue