Updated on 2026-08-14
This commit is contained in:
parent
ba36b7d26d
commit
dfcfce392a
5 changed files with 76 additions and 6 deletions
|
|
@ -6,6 +6,8 @@ import java.math.BigDecimal
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class TokenMarketChartResponse(
|
data class TokenMarketChartResponse(
|
||||||
|
// There is a bug in the API, it returns null values.
|
||||||
|
// We need to filter them out.
|
||||||
@Json(name = "prices")
|
@Json(name = "prices")
|
||||||
val prices: Map<Long, BigDecimal>,
|
val prices: Map<Long, BigDecimal?>,
|
||||||
)
|
)
|
||||||
|
|
@ -103,6 +103,7 @@ internal class DefaultMarketsTokenRepository(
|
||||||
val tokenMarketsUpdateFetcher = MarketsBatchUpdateFetcher(
|
val tokenMarketsUpdateFetcher = MarketsBatchUpdateFetcher(
|
||||||
tangemTechApi = tangemTechApi,
|
tangemTechApi = tangemTechApi,
|
||||||
marketsApi = marketsApi,
|
marketsApi = marketsApi,
|
||||||
|
analyticsEventHandler = analyticsEventHandler,
|
||||||
onApiError = {
|
onApiError = {
|
||||||
analyticsEventHandler.send(MarketsDataAnalyticsEvent.List.Error.toEvent())
|
analyticsEventHandler.send(MarketsDataAnalyticsEvent.List.Error.toEvent())
|
||||||
},
|
},
|
||||||
|
|
@ -141,7 +142,19 @@ internal class DefaultMarketsTokenRepository(
|
||||||
response.getOrThrow()
|
response.getOrThrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
return TokenChartConverter.convert(interval, result)
|
return TokenChartConverter.convert(
|
||||||
|
interval = interval,
|
||||||
|
value = result,
|
||||||
|
|
||||||
|
// === Analytics ===
|
||||||
|
onNullPresented = {
|
||||||
|
analyticsEventHandler.send(
|
||||||
|
MarketsDataAnalyticsEvent.ChartNullValuesError(
|
||||||
|
requestPath = "coins/history",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getChartPreview(
|
override suspend fun getChartPreview(
|
||||||
|
|
@ -163,7 +176,19 @@ internal class DefaultMarketsTokenRepository(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return TokenChartConverter.convert(interval, chart)
|
return TokenChartConverter.convert(
|
||||||
|
interval = interval,
|
||||||
|
value = chart,
|
||||||
|
|
||||||
|
// === Analytics ===
|
||||||
|
onNullPresented = {
|
||||||
|
analyticsEventHandler.send(
|
||||||
|
MarketsDataAnalyticsEvent.ChartNullValuesError(
|
||||||
|
requestPath = "coins/history_preview",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getTokenInfo(
|
override suspend fun getTokenInfo(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package com.tangem.data.markets
|
package com.tangem.data.markets
|
||||||
|
|
||||||
|
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||||
import com.tangem.data.common.utils.retryOnError
|
import com.tangem.data.common.utils.retryOnError
|
||||||
|
import com.tangem.data.markets.analytics.MarketsDataAnalyticsEvent
|
||||||
import com.tangem.data.markets.converters.TokenMarketChartsConverter
|
import com.tangem.data.markets.converters.TokenMarketChartsConverter
|
||||||
import com.tangem.data.markets.converters.TokenQuotesShortConverter
|
import com.tangem.data.markets.converters.TokenQuotesShortConverter
|
||||||
import com.tangem.data.markets.converters.toRequestParam
|
import com.tangem.data.markets.converters.toRequestParam
|
||||||
|
|
@ -22,6 +24,7 @@ import kotlinx.coroutines.launch
|
||||||
internal class MarketsBatchUpdateFetcher(
|
internal class MarketsBatchUpdateFetcher(
|
||||||
private val marketsApi: TangemTechMarketsApi,
|
private val marketsApi: TangemTechMarketsApi,
|
||||||
private val tangemTechApi: TangemTechApi,
|
private val tangemTechApi: TangemTechApi,
|
||||||
|
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||||
private val onApiError: () -> Unit,
|
private val onApiError: () -> Unit,
|
||||||
) : BatchUpdateFetcher<Int, List<TokenMarket>, TokenMarketUpdateRequest> {
|
) : BatchUpdateFetcher<Int, List<TokenMarket>, TokenMarketUpdateRequest> {
|
||||||
|
|
||||||
|
|
@ -52,6 +55,7 @@ internal class MarketsBatchUpdateFetcher(
|
||||||
updateTasks.forEachIndexed { index, deferred ->
|
updateTasks.forEachIndexed { index, deferred ->
|
||||||
launch {
|
launch {
|
||||||
val res = deferred.await()
|
val res = deferred.await()
|
||||||
|
checkForNulls(res)
|
||||||
val batchToUpdate = toUpdate[index]
|
val batchToUpdate = toUpdate[index]
|
||||||
|
|
||||||
update {
|
update {
|
||||||
|
|
@ -113,6 +117,22 @@ internal class MarketsBatchUpdateFetcher(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkForNulls(response: TokenMarketChartListResponse) {
|
||||||
|
response.values.forEach { chart ->
|
||||||
|
chart.prices.forEach { (_, price) ->
|
||||||
|
if (price == null) {
|
||||||
|
analyticsEventHandler.send(
|
||||||
|
MarketsDataAnalyticsEvent.ChartNullValuesError(
|
||||||
|
requestPath = "coins/history_preview",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private inline fun <T> catchApiError(onError: () -> Unit, block: () -> T): T {
|
private inline fun <T> catchApiError(onError: () -> Unit, block: () -> T): T {
|
||||||
return try {
|
return try {
|
||||||
block()
|
block()
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,20 @@ sealed interface MarketsDataAnalyticsEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toEvent(): AnalyticsEvent = when (this) {
|
fun toEvent(): AnalyticsEvent = when (this) {
|
||||||
|
is ChartNullValuesError -> this
|
||||||
is List -> this
|
is List -> this
|
||||||
is Details -> this
|
is Details -> this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class ChartNullValuesError(
|
||||||
|
val requestPath: String,
|
||||||
|
) : AnalyticsEvent(
|
||||||
|
category = "Markets / Chart",
|
||||||
|
event = "Data Error",
|
||||||
|
params = mapOf("Request path" to requestPath),
|
||||||
|
error = IllegalStateException(
|
||||||
|
"Chart data contains null values from the API",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
MarketsDataAnalyticsEvent
|
||||||
}
|
}
|
||||||
|
|
@ -6,11 +6,21 @@ import com.tangem.domain.markets.TokenChart
|
||||||
|
|
||||||
internal object TokenChartConverter {
|
internal object TokenChartConverter {
|
||||||
|
|
||||||
fun convert(interval: PriceChangeInterval, value: TokenMarketChartResponse): TokenChart {
|
fun convert(
|
||||||
|
interval: PriceChangeInterval,
|
||||||
|
value: TokenMarketChartResponse,
|
||||||
|
onNullPresented: () -> Unit = {},
|
||||||
|
): TokenChart {
|
||||||
|
val points = value.prices.mapNotNull { p -> p.value?.let { p.key to it } }.toMap()
|
||||||
|
|
||||||
|
if (points.size < points.values.size) {
|
||||||
|
onNullPresented()
|
||||||
|
}
|
||||||
|
|
||||||
return TokenChart(
|
return TokenChart(
|
||||||
interval = interval,
|
interval = interval,
|
||||||
priceY = value.prices.values.toList(),
|
priceY = points.values.toList(),
|
||||||
timeStamps = value.prices.keys.toList(),
|
timeStamps = points.keys.toList(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue