Updated on 2026-08-14
This commit is contained in:
commit
85423227c4
390 changed files with 11140 additions and 1722 deletions
|
|
@ -33,6 +33,7 @@ dependencies {
|
|||
|
||||
// region Others dependencies
|
||||
implementation(deps.kotlin.coroutines)
|
||||
implementation(deps.jodatime)
|
||||
implementation(deps.moshi)
|
||||
implementation(deps.moshi.kotlin)
|
||||
implementation(deps.timber)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.tangem.blockchainsdk.compatibility.applyL2Compatibility
|
|||
import com.tangem.blockchainsdk.compatibility.getTokenIdIfL2Network
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.data.common.cache.CacheRegistry
|
||||
import com.tangem.data.common.currency.CryptoCurrencyFactory
|
||||
import com.tangem.data.common.currency.getNetwork
|
||||
import com.tangem.data.common.utils.retryOnError
|
||||
|
|
@ -13,8 +14,10 @@ import com.tangem.data.markets.converters.*
|
|||
import com.tangem.datasource.api.common.response.ApiResponseError
|
||||
import com.tangem.datasource.api.common.response.getOrThrow
|
||||
import com.tangem.datasource.api.markets.TangemTechMarketsApi
|
||||
import com.tangem.datasource.api.markets.models.response.TokenMarketExchangesResponse
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi.Companion.marketsQuoteFields
|
||||
import com.tangem.datasource.local.datastore.RuntimeStateStore
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.markets.*
|
||||
import com.tangem.domain.markets.repositories.MarketsTokenRepository
|
||||
|
|
@ -27,12 +30,15 @@ import kotlinx.coroutines.withContext
|
|||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class DefaultMarketsTokenRepository(
|
||||
private val marketsApi: TangemTechMarketsApi,
|
||||
private val tangemTechApi: TangemTechApi,
|
||||
private val userWalletsStore: UserWalletsStore,
|
||||
private val dispatcherProvider: CoroutineDispatcherProvider,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val cacheRegistry: CacheRegistry,
|
||||
private val tokenExchangesStore: RuntimeStateStore<List<TokenMarketExchangesResponse.Exchange>>,
|
||||
) : MarketsTokenRepository {
|
||||
|
||||
private fun createTokenMarketsFetcher(firstBatchSize: Int, nextBatchSize: Int) = LimitOffsetBatchFetcher(
|
||||
|
|
@ -253,9 +259,13 @@ internal class DefaultMarketsTokenRepository(
|
|||
|
||||
override suspend fun getTokenExchanges(tokenId: String): List<TokenMarketExchange> {
|
||||
return withContext(dispatcherProvider.io) {
|
||||
val response = marketsApi.getCoinExchanges(coinId = tokenId).getOrThrow()
|
||||
cacheRegistry.invokeOnExpire(key = "coins/$tokenId/exchanges", skipCache = false) {
|
||||
val response = marketsApi.getCoinExchanges(coinId = tokenId).getOrThrow()
|
||||
|
||||
TokenMarketExchangeConverter.convertList(input = response.exchanges)
|
||||
tokenExchangesStore.store(value = response.exchanges)
|
||||
}
|
||||
|
||||
TokenMarketExchangeConverter.convertList(input = tokenExchangesStore.get().value)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package com.tangem.data.markets.converters
|
||||
|
||||
import android.net.Uri
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.blockchainsdk.utils.isSupportedInApp
|
||||
import com.tangem.datasource.api.markets.models.response.TokenMarketInfoResponse
|
||||
import com.tangem.domain.markets.BuildConfig
|
||||
import com.tangem.domain.markets.TokenMarketInfo
|
||||
import com.tangem.domain.markets.TokenQuotes
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
|
@ -11,6 +13,9 @@ import java.math.BigDecimal
|
|||
|
||||
internal object TokenMarketInfoConverter : Converter<TokenMarketInfoResponse, TokenMarketInfo> {
|
||||
|
||||
private const val PROD_IMAGE_HOST = "https://s3.eu-central-1.amazonaws.com/tangem.api/security_provider/"
|
||||
private const val DEV_IMAGE_HOST = "https://s3.eu-central-1.amazonaws.com/tangem.api.dev/security_provider/"
|
||||
|
||||
override fun convert(value: TokenMarketInfoResponse): TokenMarketInfo {
|
||||
return with(value) {
|
||||
TokenMarketInfo(
|
||||
|
|
@ -23,6 +28,7 @@ internal object TokenMarketInfoConverter : Converter<TokenMarketInfoResponse, To
|
|||
fullDescription = fullDescription,
|
||||
insights = insights?.convert(),
|
||||
metrics = metrics?.convert(),
|
||||
securityData = securityData?.convert(),
|
||||
links = links?.convert(),
|
||||
pricePerformance = pricePerformance?.convert(),
|
||||
exchangesAmount = exchangesAmount,
|
||||
|
|
@ -105,6 +111,31 @@ internal object TokenMarketInfoConverter : Converter<TokenMarketInfoResponse, To
|
|||
)
|
||||
}
|
||||
|
||||
private fun TokenMarketInfoResponse.SecurityData.convert(): TokenMarketInfo.SecurityData {
|
||||
return TokenMarketInfo.SecurityData(
|
||||
totalSecurityScore = totalSecurityScore,
|
||||
securityScoreProviderData = providerData.map { it.convert() },
|
||||
)
|
||||
}
|
||||
|
||||
private fun TokenMarketInfoResponse.ProviderData.convert(): TokenMarketInfo.SecurityScoreProvider {
|
||||
return TokenMarketInfo.SecurityScoreProvider(
|
||||
providerId = providerId,
|
||||
providerName = providerName,
|
||||
urlData = link?.convertToUrlData(),
|
||||
securityScore = securityScore,
|
||||
lastAuditDate = lastAuditDate,
|
||||
iconUrl = "${getImageHost()}large/$providerId.png",
|
||||
)
|
||||
}
|
||||
|
||||
private fun String.convertToUrlData(): TokenMarketInfo.SecurityScoreProvider.UrlData {
|
||||
return TokenMarketInfo.SecurityScoreProvider.UrlData(
|
||||
fullUrl = this,
|
||||
rootHost = this.extractMainDomainOrNull(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun TokenMarketInfoResponse.Links.convert(): TokenMarketInfo.Links {
|
||||
return TokenMarketInfo.Links(
|
||||
officialLinks = officialLinks?.convert(),
|
||||
|
|
@ -139,4 +170,27 @@ internal object TokenMarketInfoConverter : Converter<TokenMarketInfoResponse, To
|
|||
high = high,
|
||||
)
|
||||
}
|
||||
|
||||
private fun String.extractMainDomainOrNull(): String? {
|
||||
return runCatching {
|
||||
val uri = Uri.parse(this)
|
||||
val host = uri.host ?: return null
|
||||
|
||||
val parts = host.split(".")
|
||||
|
||||
if (parts.size >= 2) {
|
||||
parts.takeLast(2).joinToString(".")
|
||||
} else {
|
||||
host
|
||||
}
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
private fun getImageHost(): String {
|
||||
return if (BuildConfig.TESTER_MENU_ENABLED) {
|
||||
DEV_IMAGE_HOST
|
||||
} else {
|
||||
PROD_IMAGE_HOST
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
package com.tangem.data.markets.di
|
||||
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.data.common.cache.CacheRegistry
|
||||
import com.tangem.data.markets.DefaultMarketsTokenRepository
|
||||
import com.tangem.datasource.api.markets.TangemTechMarketsApi
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.local.datastore.RuntimeStateStore
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.markets.repositories.MarketsTokenRepository
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -25,6 +27,7 @@ internal object MarketsDataModule {
|
|||
userWalletsStore: UserWalletsStore,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
analyticsEventHandler: AnalyticsEventHandler,
|
||||
cacheRegistry: CacheRegistry,
|
||||
): MarketsTokenRepository {
|
||||
return DefaultMarketsTokenRepository(
|
||||
marketsApi = marketsApi,
|
||||
|
|
@ -32,6 +35,8 @@ internal object MarketsDataModule {
|
|||
dispatcherProvider = dispatchers,
|
||||
userWalletsStore = userWalletsStore,
|
||||
analyticsEventHandler = analyticsEventHandler,
|
||||
cacheRegistry = cacheRegistry,
|
||||
tokenExchangesStore = RuntimeStateStore(defaultValue = emptyList()),
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue