From 5af84ab1e110ca1e58ec01fa766f4c6c5c9afeac Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 28 Mar 2023 18:36:22 +0800 Subject: [PATCH] Updated on 2026-08-14 --- .../domain/tokens/OldUserTokensRepository.kt | 138 ------------------ .../tap/domain/tokens/UserTokensRepository.kt | 109 ++++++-------- .../domain/tokens/UserTokensStorageService.kt | 22 +-- 3 files changed, 49 insertions(+), 220 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/domain/tokens/OldUserTokensRepository.kt diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/OldUserTokensRepository.kt b/app/src/main/java/com/tangem/tap/domain/tokens/OldUserTokensRepository.kt deleted file mode 100644 index b9338e42a3..0000000000 --- a/app/src/main/java/com/tangem/tap/domain/tokens/OldUserTokensRepository.kt +++ /dev/null @@ -1,138 +0,0 @@ -package com.tangem.tap.domain.tokens - -import com.squareup.moshi.JsonAdapter -import com.squareup.moshi.Types -import com.tangem.blockchain.common.Blockchain -import com.tangem.blockchain.common.DerivationStyle -import com.tangem.datasource.api.common.MoshiConverter -import com.tangem.datasource.api.tangemTech.TangemTechApi -import com.tangem.domain.common.extensions.toNetworkId -import com.tangem.tap.common.FileReader -import com.tangem.tap.domain.tokens.models.BlockchainNetwork -import com.tangem.tap.domain.tokens.models.TokenDao -import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import kotlinx.coroutines.async -import kotlinx.coroutines.withContext - -@Deprecated("Use this only for migration") -class OldUserTokensRepository( - private val fileReader: FileReader, - private val tangemTechApi: TangemTechApi, - private val dispatchers: CoroutineDispatcherProvider, -) { - private val moshi = MoshiConverter.networkMoshi - private val blockchainsAdapter: JsonAdapter> = moshi.adapter( - Types.newParameterizedType(List::class.java, Blockchain::class.java), - ) - private val tokensAdapter: JsonAdapter> = moshi.adapter( - Types.newParameterizedType(List::class.java, TokenDao::class.java), - ) - private val blockchainNetworkAdapter: JsonAdapter> = - moshi.adapter(Types.newParameterizedType(List::class.java, BlockchainNetwork::class.java)) - - @Deprecated("Use BlockchainNetwork instead") - private fun loadSavedTokens(cardId: String): List { - val json = try { - fileReader.readFile(getFileNameForTokens(cardId)) - } catch (exception: Exception) { - return emptyList() - } - - return try { - tokensAdapter.fromJson(json) ?: emptyList() - } catch (exception: Exception) { - emptyList() - } - } - - @Deprecated("Use BlockchainNetwork instead") - private fun loadSavedBlockchains(cardId: String): List { - return try { - val json = fileReader.readFile(getFileNameForBlockchains(cardId)) - blockchainsAdapter.fromJson(json)?.distinct() ?: emptyList() - } catch (exception: Exception) { - emptyList() - } - } - - @Deprecated("Use TokensRepository instead") - suspend fun loadSavedCurrencies( - cardId: String, - isHdWalletSupported: Boolean = false, - ): List { - return try { - val json = fileReader.readFile(getFileNameForBlockchains(cardId)) - blockchainNetworkAdapter.fromJson(json)?.distinct() ?: emptyList() - } catch (exception: Exception) { - tryToLoadPreviousFormatAndMigrate(cardId, isHdWalletSupported) - } - } - - private suspend fun tryToLoadPreviousFormatAndMigrate( - cardId: String, - isHdWalletSupported: Boolean = false, - ): List { - return try { - loadSavedCurrenciesOldWay( - cardId, - isHdWalletSupported, - ) - } catch (exception: Exception) { - emptyList() - } - } - - private suspend fun loadSavedCurrenciesOldWay( - cardId: String, - isHdWalletSupported: Boolean = false, - ): List { - val blockchains = loadSavedBlockchains(cardId) - val tokens = loadSavedTokens(cardId) - val ids = getTokensIds(tokens) - val derivationStyle = if (isHdWalletSupported) DerivationStyle.LEGACY else null - val blockchainNetworks = blockchains.map { blockchain -> - BlockchainNetwork( - blockchain = blockchain, - derivationPath = blockchain.derivationPath(derivationStyle)?.rawPath, - tokens = tokens - .filter { it.blockchainDao.toBlockchain() == blockchain } - .map { - val token = it.toToken() - token.copy(id = ids[token.contractAddress]) - }, - ) - } - return blockchainNetworks - } - - private suspend fun getTokensIds(tokens: List): Map = withContext(dispatchers.io) { - tokens.map { - async { - tangemTechApi.getCoins( - contractAddress = it.contractAddress, - networkIds = it.blockchainDao.toBlockchain().toNetworkId(), - active = true, - ) - } - } - .map { - runCatching { it.await() } - .onSuccess { return@map it.coins.firstOrNull()?.id } - .onFailure { return@map null } - - error("Unreachable code because runCatching must return result") - } - .mapIndexedNotNull { index, id -> - if (id == null) null else tokens[index].contractAddress to id - } - .toMap() - } - - companion object { - private const val FILE_NAME_PREFIX_TOKENS = "tokens" - private const val FILE_NAME_PREFIX_BLOCKCHAINS = "blockchains" - private fun getFileNameForTokens(cardId: String): String = "${FILE_NAME_PREFIX_TOKENS}_$cardId" - private fun getFileNameForBlockchains(cardId: String): String = - "${FILE_NAME_PREFIX_BLOCKCHAINS}_$cardId" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt index ee21bf9347..175f72a121 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt @@ -28,31 +28,28 @@ class UserTokensRepository( private val networkConnectionManager: NetworkConnectionManager, ) { - // TODO("After adding DI") replace with CoroutineDispatcherProvider suspend fun getUserTokens(card: CardDTO): List = withContext(dispatchers.io) { - val userId = getUserWalletId(card) ?: return@withContext emptyList() + val userWalletId = getUserWalletId(card) ?: return@withContext emptyList() + if (DemoHelper.isDemoCardId(card.cardId)) { - return@withContext loadTokensOffline(card, userId).ifEmpty(::loadDemoCurrencies) + return@withContext loadTokensOffline(userWalletId = userWalletId).ifEmpty(::loadDemoCurrencies) } - if (!networkConnectionManager.isOnline) { - return@withContext loadTokensOffline(card, userId) - } + if (!networkConnectionManager.isOnline) return@withContext loadTokensOffline(userWalletId = userWalletId) - return@withContext remoteGetUserTokens(card, userId) + return@withContext remoteGetUserTokens(userWalletId = userWalletId) } - // TODO("After adding DI") replace with CoroutineDispatcherProvider suspend fun saveUserTokens(card: CardDTO, tokens: List) = withContext(dispatchers.io) { - val userId = getUserWalletId(card) ?: return@withContext + val userWalletId = getUserWalletId(card) ?: return@withContext val userTokens = tokens.toUserTokensResponse() - remoteSaveUserTokens(userId, userTokens) - storageService.saveUserTokens(userId, userTokens) + remoteSaveUserTokens(userWalletId = userWalletId, userTokens = userTokens) + storageService.saveUserTokens(userWalletId = userWalletId, tokens = userTokens) } suspend fun loadBlockchainsToDerive(card: CardDTO): List = withContext(dispatchers.io) { - val userId = getUserWalletId(card) ?: return@withContext emptyList() - val blockchainNetworks = loadTokensOffline(card = card, userId = userId).toBlockchainNetworks() + val userWalletId = getUserWalletId(card) ?: return@withContext emptyList() + val blockchainNetworks = loadTokensOffline(userWalletId = userWalletId).toBlockchainNetworks() if (DemoHelper.isDemoCardId(card.cardId)) { return@withContext blockchainNetworks.ifEmpty(loadDemoCurrencies()::toBlockchainNetworks) @@ -61,8 +58,8 @@ class UserTokensRepository( return@withContext blockchainNetworks } - private suspend fun loadTokensOffline(card: CardDTO, userId: String): List { - return storageService.getUserTokens(userId) ?: storageService.getUserTokens(card) + private fun loadTokensOffline(userWalletId: String): List { + return storageService.getUserTokens(userWalletId = userWalletId) ?: emptyList() } private fun loadDemoCurrencies(): List { @@ -77,54 +74,49 @@ class UserTokensRepository( .flatMap(BlockchainNetwork::toCurrencies) } - private fun List.toUserTokensResponse() = UserTokensResponse( - tokens = CurrencyConverter.convertList(this), - group = GROUP_DEFAULT_VALUE, - sort = SORT_DEFAULT_VALUE, - ) + private fun List.toUserTokensResponse(): UserTokensResponse { + return UserTokensResponse( + tokens = CurrencyConverter.convertList(input = this), + group = GROUP_DEFAULT_VALUE, + sort = SORT_DEFAULT_VALUE, + ) + } - private suspend fun handleGetUserTokensFailure(card: CardDTO, userId: String, error: Throwable): List { + private suspend fun handleGetUserTokensFailure(userWalletId: String, error: Throwable): List { return when { - error is TangemSdkError.NetworkError && error.customMessage.contains(NOT_FOUND_HTTP_CODE) -> - storageService.getUserTokens(card).also { - remoteSaveUserTokens(userId = userId, userTokens = it.toUserTokensResponse()) - } + error is TangemSdkError.NetworkError && error.customMessage.contains(NOT_FOUND_HTTP_CODE) -> { + storageService + .getUserTokens(userWalletId) + ?.also { remoteSaveUserTokens(userWalletId = userWalletId, userTokens = it.toUserTokensResponse()) } + ?: emptyList() + } else -> { - val tokens = storageService.getUserTokens(userId) ?: storageService.getUserTokens(card) - tokens.distinct() + storageService.getUserTokens(userWalletId)?.distinct() ?: emptyList() } } } - private suspend fun remoteGetUserTokens(card: CardDTO, userId: String): List { - runCatching { - tangemTechApi.getUserTokens(userId) - }.onSuccess { response -> - return response.tokens - .mapNotNull(Currency.Companion::fromTokenResponse).also { - storageService.saveUserTokens(userId, it.toUserTokensResponse()) - } - .distinct() - }.onFailure { - return handleGetUserTokensFailure(card = card, userId = userId, error = it) - } - error("Unreachable code because runCatching must return result") + private suspend fun remoteGetUserTokens(userWalletId: String): List { + return runCatching { tangemTechApi.getUserTokens(userWalletId) } + .fold( + onSuccess = { response -> + response.tokens + .mapNotNull(Currency.Companion::fromTokenResponse) + .also { storageService.saveUserTokens(userWalletId, it.toUserTokensResponse()) } + .distinct() + }, + onFailure = { handleGetUserTokensFailure(userWalletId = userWalletId, error = it) }, + ) } - private suspend fun remoteSaveUserTokens(userId: String, userTokens: UserTokensResponse) { + private suspend fun remoteSaveUserTokens(userWalletId: String, userTokens: UserTokensResponse) { // it can throw okhttp3.internal.http2.StreamResetException: stream was reset: INTERNAL_ERROR // if the /user-tokens endpoint disabled - runCatching { - tangemTechApi.saveUserTokens(userId, userTokens) - }.onFailure { - Timber.e(it) - } + runCatching { tangemTechApi.saveUserTokens(userWalletId, userTokens) } + .onFailure { Timber.e(it) } } - private fun getUserWalletId(card: CardDTO): String? { - return UserWalletIdBuilder.card(card).build() - ?.stringValue - } + private fun getUserWalletId(card: CardDTO): String? = UserWalletIdBuilder.card(card).build()?.stringValue companion object { private const val GROUP_DEFAULT_VALUE = "none" @@ -137,23 +129,10 @@ class UserTokensRepository( tangemTechService: TangemTechService, networkConnectionManager: NetworkConnectionManager, ): UserTokensRepository { - val fileReader = AndroidFileReader(context) - val dispatchers = AppCoroutineDispatcherProvider() - - val oldUserTokensRepository = OldUserTokensRepository( - fileReader = fileReader, - tangemTechApi = tangemTechService.api, - dispatchers = dispatchers, - ) - val storageService = UserTokensStorageService( - oldUserTokensRepository = oldUserTokensRepository, - fileReader = fileReader, - ) - return UserTokensRepository( - storageService = storageService, + storageService = UserTokensStorageService(fileReader = AndroidFileReader(context)), tangemTechApi = tangemTechService.api, - dispatchers = dispatchers, + dispatchers = AppCoroutineDispatcherProvider(), networkConnectionManager = networkConnectionManager, ) } diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt index 9df51fb6f4..8ebee84b97 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt @@ -4,21 +4,16 @@ import com.squareup.moshi.JsonAdapter import com.tangem.Log import com.tangem.datasource.api.common.MoshiConverter import com.tangem.datasource.api.tangemTech.models.UserTokensResponse -import com.tangem.domain.common.CardDTO import com.tangem.tap.common.FileReader import com.tangem.tap.features.wallet.models.Currency -import com.tangem.tap.features.wallet.models.toCurrencies -class UserTokensStorageService( - private val oldUserTokensRepository: OldUserTokensRepository, - private val fileReader: FileReader, -) { +class UserTokensStorageService(private val fileReader: FileReader) { private val userTokensAdapter: JsonAdapter = MoshiConverter.networkMoshi.adapter(UserTokensResponse::class.java) - fun getUserTokens(userId: String): List? { + fun getUserTokens(userWalletId: String): List? { return try { - val json = fileReader.readFile(getFileNameForUserTokens(userId)) + val json = fileReader.readFile(getFileNameForUserTokens(userWalletId)) userTokensAdapter.fromJson(json)?.tokens?.mapNotNull { Currency.fromTokenResponse(it) } } catch (exception: Exception) { Log.error { exception.stackTraceToString() } @@ -26,16 +21,9 @@ class UserTokensStorageService( } } - @Deprecated("") - suspend fun getUserTokens(card: CardDTO): List { - val blockchainNetworks = - oldUserTokensRepository.loadSavedCurrencies(card.cardId, card.settings.isHDWalletAllowed) - return blockchainNetworks.flatMap { it.toCurrencies() } - } - - fun saveUserTokens(userId: String, tokens: UserTokensResponse) { + fun saveUserTokens(userWalletId: String, tokens: UserTokensResponse) { val json = userTokensAdapter.toJson(tokens) - fileReader.rewriteFile(json, getFileNameForUserTokens(userId)) + fileReader.rewriteFile(json, getFileNameForUserTokens(userWalletId)) } companion object {