Updated on 2026-08-14

This commit is contained in:
Tangem 2025-02-01 18:59:23 +04:00
parent 950dc41662
commit dfa6798f07
16 changed files with 220 additions and 82 deletions

View file

@ -3,7 +3,6 @@ package com.tangem.blockchainsdk.providers
import androidx.core.util.PatternsCompat
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.tangem.blockchainsdk.BlockchainProvidersResponse
import com.tangem.blockchainsdk.utils.createPrivateProviderType
import com.tangem.datasource.local.config.providers.models.ProviderModel
import timber.log.Timber
@ -48,11 +47,11 @@ internal object BlockchainProvidersResponseMerger {
return result.guaranteeUrlsEndWithSlash()
}
private fun List<ProviderModel>.filterUnsupportedProviders() = filter {
val isSupportedType = it !is ProviderModel.UnsupportedType
private fun List<ProviderModel>.filterUnsupportedProviders() = filter { model ->
val isSupportedType = model !is ProviderModel.UnsupportedType
val isSupportedPrivateType = if (it is ProviderModel.Private) {
createPrivateProviderType(it.name) != null
val isSupportedPrivateType = if (model is ProviderModel.Private) {
ProviderTypeIdMapping.entries.any { it.id == model.name }
} else {
true
}

View file

@ -1,11 +1,11 @@
package com.tangem.blockchainsdk.providers
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.Flow
/** Blockchain providers types manager */
interface BlockchainProvidersTypesManager {
fun get(): StateFlow<BlockchainProviderTypes>
fun get(): Flow<BlockchainProviderTypes>
suspend fun update()
}

View file

@ -1,45 +1,68 @@
package com.tangem.blockchainsdk.providers
import androidx.datastore.core.DataStore
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.network.providers.ProviderType
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.properties.Delegates.notNull
import com.tangem.blockchainsdk.BlockchainProvidersResponse
import com.tangem.blockchainsdk.converters.BlockchainProviderTypesConverter
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.map
import timber.log.Timber
/**
* Implementation of [BlockchainProvidersTypesManager] in DEV environment
*
* @property prodBlockchainProvidersTypesManager prod manager
* @property blockchainProviderTypesStore blockchain provider types store
* @property changedBlockchainProvidersStore changed blockchain providers store
*
[REDACTED_AUTHOR]
*/
@Singleton
internal class DevBlockchainProvidersTypesManager @Inject constructor(
internal class DevBlockchainProvidersTypesManager(
private val prodBlockchainProvidersTypesManager: ProdBlockchainProvidersTypesManager,
private val blockchainProviderTypesStore: BlockchainProviderTypesStore,
) : BlockchainProvidersTypesManager by prodBlockchainProvidersTypesManager,
MutableBlockchainProvidersTypesManager {
private val changedBlockchainProvidersStore: DataStore<BlockchainProvidersResponse>,
) : MutableBlockchainProvidersTypesManager {
private var primaryResponse: BlockchainProviderTypes by notNull()
override fun get(): Flow<BlockchainProviderTypes> = changedBlockchainProvidersStore.data
.map(BlockchainProviderTypesConverter::convert)
override suspend fun update() {
prodBlockchainProvidersTypesManager.update()
primaryResponse = blockchainProviderTypesStore.get().value
val initial = blockchainProviderTypesStore.get().value
val changed = changedBlockchainProvidersStore.data.firstOrNull().orEmpty()
if (changed.isEmpty()) {
Timber.i("Initialize ChangedBlockchainProvidersStore")
changedBlockchainProvidersStore.updateData {
BlockchainProviderTypesConverter.convertBack(initial)
}
}
}
override suspend fun recoverInitialState() {
val initial = blockchainProviderTypesStore.get().value
changedBlockchainProvidersStore.updateData {
BlockchainProviderTypesConverter.convertBack(initial)
}
}
override suspend fun update(blockchain: Blockchain, providers: List<ProviderType>) {
val currentTypes = blockchainProviderTypesStore.get().value
changedBlockchainProvidersStore.updateData {
val providerModels = BlockchainProviderTypesConverter.convertBack(value = mapOf(blockchain to providers))
val updatedTypes = currentTypes + (blockchain to providers)
blockchainProviderTypesStore.store(value = updatedTypes)
it + providerModels
}
}
override suspend fun isMatchWithMerged(): Boolean {
val current = blockchainProviderTypesStore.get().value
val initial = blockchainProviderTypesStore.get().value
val changed = changedBlockchainProvidersStore.data.firstOrNull().orEmpty()
return current == primaryResponse
return initial == BlockchainProviderTypesConverter.convert(changed)
}
}

View file

@ -13,6 +13,9 @@ interface MutableBlockchainProvidersTypesManager : BlockchainProvidersTypesManag
/** Update [providers] for [blockchain] */
suspend fun update(blockchain: Blockchain, providers: List<ProviderType>)
/** Recover initial state */
suspend fun recoverInitialState()
/** Checks that current [BlockchainProviderTypes] was changed */
suspend fun isMatchWithMerged(): Boolean
}

View file

@ -1,7 +1,7 @@
package com.tangem.blockchainsdk.providers
import com.tangem.blockchainsdk.converters.BlockchainProviderTypesConverter
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.Flow
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
@ -20,7 +20,7 @@ internal class ProdBlockchainProvidersTypesManager @Inject constructor(
private val blockchainProviderTypesStore: BlockchainProviderTypesStore,
) : BlockchainProvidersTypesManager {
override fun get(): StateFlow<BlockchainProviderTypes> = blockchainProviderTypesStore.get()
override fun get(): Flow<BlockchainProviderTypes> = blockchainProviderTypesStore.get()
override suspend fun update() {
val response = blockchainProvidersResponseLoader.load()

View file

@ -0,0 +1,27 @@
package com.tangem.blockchainsdk.providers
import com.tangem.blockchain.common.network.providers.ProviderType
/** Mapping of [providerType] with [id] */
internal enum class ProviderTypeIdMapping(val id: String, val providerType: ProviderType) {
NowNodes(id = "nownodes", providerType = ProviderType.NowNodes),
GetBlock(id = "getblock", providerType = ProviderType.GetBlock),
QuickNode(id = "quicknode", providerType = ProviderType.QuickNode),
BitcoinBlockchair(id = "blockchair", providerType = ProviderType.BitcoinLike.Blockchair),
BitcoinBlockcypher(id = "blockcypher", providerType = ProviderType.BitcoinLike.Blockcypher),
CardanoAdalite(id = "adalite", providerType = ProviderType.Cardano.Adalite),
CardanoRosetta(id = "tangemRosetta", providerType = ProviderType.Cardano.Rosetta),
ChiaFireAcademy(id = "fireAcademy", providerType = ProviderType.Chia.FireAcademy),
ChiaTangem(id = "tangemChia", providerType = ProviderType.Chia.Tangem),
ChiaTangemNew(id = "tangemChia3", providerType = ProviderType.Chia.TangemNew),
EthereumInfura(id = "infura", providerType = ProviderType.EthereumLike.Infura),
HederaArkhia(id = "arkhiaHedera", providerType = ProviderType.Hedera.Arkhia),
KaspaSecondary(id = "kaspa", providerType = ProviderType.Kaspa.SecondaryAPI),
SolanaOfficial(id = "solana", providerType = ProviderType.Solana.Official),
TonCentral(id = "ton", providerType = ProviderType.Ton.TonCentral),
TronGrid(id = "tron", providerType = ProviderType.Tron.TronGrid),
BittensorDwellir(id = "dwellirBittensor", providerType = ProviderType.Bittensor.Dwellir),
BittensorOnfinality(id = "onfinalityBittensor", providerType = ProviderType.Bittensor.Onfinality),
KoinosPro(id = "koinospro", providerType = ProviderType.Koinos.KoinosPro),
;
}

View file

@ -0,0 +1,34 @@
package com.tangem.blockchainsdk.providers.dev
import androidx.datastore.core.Serializer
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import com.tangem.blockchainsdk.BlockchainProvidersResponse
import com.tangem.datasource.local.config.providers.models.ProviderModel
import java.io.InputStream
import java.io.OutputStream
/** DataStore serializer for [BlockchainProvidersResponse]. Implemented by [Moshi]. */
internal class BlockchainProvidersResponseSerializer(moshi: Moshi) : Serializer<BlockchainProvidersResponse> {
private val adapter by lazy {
val providersType = Types.newParameterizedType(List::class.java, ProviderModel::class.java)
val type = Types.newParameterizedType(Map::class.java, String::class.java, providersType)
moshi.adapter<BlockchainProvidersResponse>(type)
}
override val defaultValue: BlockchainProvidersResponse = emptyMap()
override suspend fun readFrom(input: InputStream): BlockchainProvidersResponse {
return input.bufferedReader().use { reader ->
adapter.fromJson(reader.readText()) ?: defaultValue
}
}
override suspend fun writeTo(t: BlockchainProvidersResponse, output: OutputStream) {
output.bufferedWriter().use { writer ->
writer.write(adapter.toJson(t))
}
}
}