Updated on 2026-08-14
This commit is contained in:
parent
9d062102b9
commit
c642d211b1
10 changed files with 206 additions and 48 deletions
|
|
@ -0,0 +1,19 @@
|
|||
package com.tangem.datasource.api.tangemTech
|
||||
|
||||
import com.tangem.datasource.config.models.ProviderModel
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Header
|
||||
|
||||
/**
|
||||
* Tangem Tech API for app services
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface TangemTechServiceApi {
|
||||
|
||||
@GET("v1/networks")
|
||||
suspend fun getBlockchainProviders(
|
||||
@Header("card_public_key") cardPublicKey: String,
|
||||
@Header("card_id") cardId: String,
|
||||
): Map<String, List<ProviderModel>>
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import com.tangem.datasource.BuildConfig
|
|||
import com.tangem.datasource.api.common.response.ApiResponseCallAdapterFactory
|
||||
import com.tangem.datasource.api.express.TangemExpressApi
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechServiceApi
|
||||
import com.tangem.datasource.utils.RequestHeader.*
|
||||
import com.tangem.datasource.utils.addHeaders
|
||||
import com.tangem.datasource.utils.addLoggers
|
||||
|
|
@ -19,6 +20,7 @@ import dagger.hilt.components.SingletonComponent
|
|||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.moshi.MoshiConverterFactory
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
|
|
@ -96,6 +98,33 @@ class NetworkModule {
|
|||
.create(TangemTechApi::class.java)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideTangemTechServiceApi(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
@ApplicationContext context: Context,
|
||||
appVersionProvider: AppVersionProvider,
|
||||
): TangemTechServiceApi {
|
||||
return Retrofit.Builder()
|
||||
.addConverterFactory(MoshiConverterFactory.create(moshi))
|
||||
.addCallAdapterFactory(ApiResponseCallAdapterFactory.create())
|
||||
.baseUrl(PROD_TANGEM_TECH_BASE_URL)
|
||||
.client(
|
||||
OkHttpClient.Builder()
|
||||
.callTimeout(timeout = 5, unit = TimeUnit.SECONDS)
|
||||
.addHeaders(
|
||||
CacheControlHeader,
|
||||
AppVersionPlatformHeaders(appVersionProvider),
|
||||
// TODO("refactor header init") get auth data after biometric auth to avoid race condition
|
||||
// AuthenticationHeader(authProvider),
|
||||
)
|
||||
.addLoggers(context)
|
||||
.build(),
|
||||
)
|
||||
.build()
|
||||
.create(TangemTechServiceApi::class.java)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val PROD_EXPRESS_BASE_URL = "https://express.tangem.com/v1/"
|
||||
const val DEV_EXPRESS_BASE_URL = "[REDACTED_ENV_URL]"
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ leakcanary = "2.13"
|
|||
# endregion Other libraries
|
||||
|
||||
# region Tangem
|
||||
tangemBlockchainSdk = "develop-593"
|
||||
tangemBlockchainSdk = "develop-598"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "develop-344"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.blockchainsdk
|
||||
|
||||
import com.tangem.blockchain.common.WalletManagerFactory
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
* Blockchain SDK components factory
|
||||
|
|
@ -10,9 +9,6 @@ import kotlinx.coroutines.flow.Flow
|
|||
*/
|
||||
interface BlockchainSDKFactory {
|
||||
|
||||
/** Flow of [WalletManagerFactory] */
|
||||
val walletManagerFactory: Flow<WalletManagerFactory>
|
||||
|
||||
/** Initialize components */
|
||||
suspend fun init()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +1,21 @@
|
|||
package com.tangem.blockchainsdk
|
||||
|
||||
import com.tangem.blockchain.common.AccountCreator
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.BlockchainSdkConfig
|
||||
import com.tangem.blockchain.common.WalletManagerFactory
|
||||
import com.tangem.blockchain.common.datastorage.BlockchainDataStorage
|
||||
import com.tangem.blockchain.common.logging.BlockchainSDKLogger
|
||||
import com.tangem.blockchain.common.network.providers.ProviderType
|
||||
import com.tangem.blockchainsdk.converters.BlockchainProviderTypesConverter
|
||||
import com.tangem.blockchainsdk.converters.BlockchainSDKConfigConverter
|
||||
import com.tangem.blockchainsdk.storage.RuntimeStore
|
||||
import com.tangem.blockchainsdk.loader.BlockchainProvidersResponseLoader
|
||||
import com.tangem.blockchainsdk.store.RuntimeStore
|
||||
import com.tangem.datasource.asset.loader.AssetLoader
|
||||
import com.tangem.datasource.config.models.ConfigValueModel
|
||||
import com.tangem.datasource.config.models.ProviderModel
|
||||
import com.tangem.libs.blockchain_sdk.BuildConfig
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.launch
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import timber.log.Timber
|
||||
|
||||
internal typealias BlockchainProvidersResponse = Map<String, List<ProviderModel>>
|
||||
internal typealias BlockchainProviderTypes = Map<Blockchain, List<ProviderType>>
|
||||
|
|
@ -27,25 +23,26 @@ internal typealias BlockchainProviderTypes = Map<Blockchain, List<ProviderType>>
|
|||
/**
|
||||
* Implementation of Blockchain SDK components factory
|
||||
*
|
||||
* @property assetLoader asset loader
|
||||
* @property configStore blockchain sdk config store
|
||||
* @property blockchainProviderTypesStore blockchain provider types store
|
||||
* @property accountCreator account creator
|
||||
* @property blockchainDataStorage blockchain data storage
|
||||
* @property blockchainSDKLogger blockchain SDK logger
|
||||
* @property assetLoader asset loader
|
||||
* @property blockchainProvidersResponseLoader blockchain providers response loader
|
||||
* @property configStore blockchain sdk config store
|
||||
* @property blockchainProviderTypesStore blockchain provider types store
|
||||
* @property walletManagerFactoryCreator wallet manager factory creator
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultBlockchainSDKFactory(
|
||||
private val assetLoader: AssetLoader,
|
||||
private val blockchainProvidersResponseLoader: BlockchainProvidersResponseLoader,
|
||||
private val configStore: RuntimeStore<BlockchainSdkConfig>,
|
||||
private val blockchainProviderTypesStore: RuntimeStore<BlockchainProviderTypes>,
|
||||
private val accountCreator: AccountCreator,
|
||||
private val blockchainDataStorage: BlockchainDataStorage,
|
||||
private val blockchainSDKLogger: BlockchainSDKLogger,
|
||||
private val walletManagerFactoryCreator: WalletManagerFactoryCreator,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
) : BlockchainSDKFactory {
|
||||
|
||||
override val walletManagerFactory: Flow<WalletManagerFactory> by lazy(::createWalletManagerFactory)
|
||||
private val walletManagerFactory: Flow<WalletManagerFactory?> by lazy(::createWalletManagerFactory)
|
||||
|
||||
private val mainScope = CoroutineScope(dispatchers.main)
|
||||
|
||||
override suspend fun init() {
|
||||
coroutineScope {
|
||||
|
|
@ -56,24 +53,25 @@ internal class DefaultBlockchainSDKFactory(
|
|||
|
||||
override suspend fun getWalletManagerFactorySync(): WalletManagerFactory? = walletManagerFactory.firstOrNull()
|
||||
|
||||
private fun createWalletManagerFactory(): Flow<WalletManagerFactory> {
|
||||
private fun createWalletManagerFactory(): Flow<WalletManagerFactory?> {
|
||||
return combine(
|
||||
flow = configStore.get(),
|
||||
flow2 = blockchainProviderTypesStore.get(),
|
||||
) { config, blockchainProviderTypes ->
|
||||
WalletManagerFactory(
|
||||
config = config,
|
||||
blockchainProviderTypes = blockchainProviderTypes,
|
||||
accountCreator = accountCreator,
|
||||
blockchainDataStorage = blockchainDataStorage,
|
||||
loggers = listOf(blockchainSDKLogger),
|
||||
)
|
||||
}
|
||||
transform = walletManagerFactoryCreator::create,
|
||||
)
|
||||
.stateIn(scope = mainScope, started = SharingStarted.Eagerly, initialValue = null)
|
||||
}
|
||||
|
||||
private fun CoroutineScope.updateBlockchainSDKConfig() {
|
||||
launch {
|
||||
val config = assetLoader.load<ConfigValueModel>(fileName = CONFIG_FILE_NAME) ?: return@launch
|
||||
val config = assetLoader.load<ConfigValueModel>(fileName = CONFIG_FILE_NAME)
|
||||
|
||||
if (config == null) {
|
||||
Timber.e("Error loading BlockchainSDKConfig")
|
||||
return@launch
|
||||
}
|
||||
|
||||
Timber.d("Update BlockchainSDKConfig")
|
||||
|
||||
configStore.store(
|
||||
value = BlockchainSDKConfigConverter.convert(value = config),
|
||||
|
|
@ -83,17 +81,22 @@ internal class DefaultBlockchainSDKFactory(
|
|||
|
||||
private fun CoroutineScope.updateBlockchainProviderTypes() {
|
||||
launch {
|
||||
val providerTypes = assetLoader.load<BlockchainProvidersResponse>(fileName = PROVIDER_TYPES_FILE_NAME)
|
||||
?: return@launch
|
||||
val response = blockchainProvidersResponseLoader.load()
|
||||
|
||||
if (response == null) {
|
||||
Timber.e("Error loading BlockchainProviderTypes")
|
||||
return@launch
|
||||
}
|
||||
|
||||
Timber.d("Update BlockchainProviderTypes")
|
||||
|
||||
blockchainProviderTypesStore.store(
|
||||
value = BlockchainProviderTypesConverter.convert(providerTypes),
|
||||
value = BlockchainProviderTypesConverter.convert(response),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val CONFIG_FILE_NAME = "tangem-app-config/config_${BuildConfig.ENVIRONMENT}"
|
||||
const val PROVIDER_TYPES_FILE_NAME = "tangem-app-config/providers_order"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.tangem.blockchainsdk
|
||||
|
||||
import com.tangem.blockchain.common.AccountCreator
|
||||
import com.tangem.blockchain.common.BlockchainSdkConfig
|
||||
import com.tangem.blockchain.common.WalletManagerFactory
|
||||
import com.tangem.blockchain.common.datastorage.BlockchainDataStorage
|
||||
import com.tangem.blockchain.common.logging.BlockchainSDKLogger
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Creator of [WalletManagerFactory]
|
||||
*
|
||||
* @property accountCreator account creator
|
||||
* @property blockchainDataStorage blockchain data storage
|
||||
* @property blockchainSDKLogger blockchain SDK logger
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class WalletManagerFactoryCreator @Inject constructor(
|
||||
private val accountCreator: AccountCreator,
|
||||
private val blockchainDataStorage: BlockchainDataStorage,
|
||||
private val blockchainSDKLogger: BlockchainSDKLogger,
|
||||
) {
|
||||
|
||||
fun create(config: BlockchainSdkConfig, blockchainProviderTypes: BlockchainProviderTypes): WalletManagerFactory {
|
||||
Timber.d("Create WalletManagerFactory")
|
||||
|
||||
return WalletManagerFactory(
|
||||
config = config,
|
||||
blockchainProviderTypes = blockchainProviderTypes,
|
||||
accountCreator = accountCreator,
|
||||
blockchainDataStorage = blockchainDataStorage,
|
||||
loggers = listOf(blockchainSDKLogger),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,13 +4,16 @@ import com.tangem.blockchain.common.BlockchainSdkConfig
|
|||
import com.tangem.blockchain.common.logging.BlockchainSDKLogger
|
||||
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
||||
import com.tangem.blockchainsdk.DefaultBlockchainSDKFactory
|
||||
import com.tangem.blockchainsdk.WalletManagerFactoryCreator
|
||||
import com.tangem.blockchainsdk.accountcreator.DefaultAccountCreator
|
||||
import com.tangem.blockchainsdk.datastorage.DefaultBlockchainDataStorage
|
||||
import com.tangem.blockchainsdk.storage.DefaultRuntimeStore
|
||||
import com.tangem.blockchainsdk.loader.BlockchainProvidersResponseLoader
|
||||
import com.tangem.blockchainsdk.store.DefaultRuntimeStore
|
||||
import com.tangem.datasource.api.common.AuthProvider
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.asset.loader.AssetLoader
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -25,15 +28,29 @@ internal object BlockchainSDKFactoryModule {
|
|||
@Singleton
|
||||
fun provideBlockchainSDKFactory(
|
||||
assetLoader: AssetLoader,
|
||||
blockchainProvidersResponseLoader: BlockchainProvidersResponseLoader,
|
||||
walletManagerFactoryCreator: WalletManagerFactoryCreator,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): BlockchainSDKFactory {
|
||||
return DefaultBlockchainSDKFactory(
|
||||
assetLoader = assetLoader,
|
||||
blockchainProvidersResponseLoader = blockchainProvidersResponseLoader,
|
||||
configStore = DefaultRuntimeStore(defaultValue = BlockchainSdkConfig()),
|
||||
blockchainProviderTypesStore = DefaultRuntimeStore(defaultValue = emptyMap()),
|
||||
walletManagerFactoryCreator = walletManagerFactoryCreator,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideWalletManagerFactoryCreator(
|
||||
authProvider: AuthProvider,
|
||||
tangemTechApi: TangemTechApi,
|
||||
appPreferencesStore: AppPreferencesStore,
|
||||
blockchainSDKLogger: BlockchainSDKLogger,
|
||||
): BlockchainSDKFactory {
|
||||
return DefaultBlockchainSDKFactory(
|
||||
assetLoader = assetLoader,
|
||||
configStore = DefaultRuntimeStore(defaultValue = BlockchainSdkConfig()),
|
||||
blockchainProviderTypesStore = DefaultRuntimeStore(defaultValue = emptyMap()),
|
||||
): WalletManagerFactoryCreator {
|
||||
return WalletManagerFactoryCreator(
|
||||
accountCreator = DefaultAccountCreator(authProvider, tangemTechApi),
|
||||
blockchainDataStorage = DefaultBlockchainDataStorage(appPreferencesStore),
|
||||
blockchainSDKLogger = blockchainSDKLogger,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
package com.tangem.blockchainsdk.loader
|
||||
|
||||
import com.tangem.blockchainsdk.BlockchainProvidersResponse
|
||||
import com.tangem.datasource.api.common.AuthProvider
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechServiceApi
|
||||
import com.tangem.datasource.asset.loader.AssetLoader
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.runCatching
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Loader of [BlockchainProvidersResponse]
|
||||
*
|
||||
* @property tangemTechServiceApi tangem tech api
|
||||
* @property authProvider auth provider
|
||||
* @property assetLoader asset loader for local config loading
|
||||
* @property dispatchers dispatchers
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Singleton
|
||||
internal class BlockchainProvidersResponseLoader @Inject constructor(
|
||||
private val tangemTechServiceApi: TangemTechServiceApi,
|
||||
private val authProvider: AuthProvider,
|
||||
private val assetLoader: AssetLoader,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) {
|
||||
|
||||
/** Load [BlockchainProvidersResponse] */
|
||||
suspend fun load(): BlockchainProvidersResponse? {
|
||||
return runCatching(dispatcher = dispatchers.io, block = ::loadRemote)
|
||||
.fold(
|
||||
onSuccess = { it },
|
||||
onFailure = {
|
||||
Timber.e(it, "Failed to load blockchain provider types from backend")
|
||||
loadLocal()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun loadRemote(): BlockchainProvidersResponse {
|
||||
return tangemTechServiceApi.getBlockchainProviders(
|
||||
cardPublicKey = authProvider.getCardPublicKey(),
|
||||
cardId = authProvider.getCardId(),
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun loadLocal(): BlockchainProvidersResponse? {
|
||||
return assetLoader.load<BlockchainProvidersResponse>(fileName = PROVIDER_TYPES_FILE_NAME)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val PROVIDER_TYPES_FILE_NAME = "tangem-app-config/providers_order"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.blockchainsdk.storage
|
||||
package com.tangem.blockchainsdk.store
|
||||
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.blockchainsdk.storage
|
||||
package com.tangem.blockchainsdk.store
|
||||
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue