Updated on 2026-08-14
This commit is contained in:
parent
cba839d8f2
commit
b776c208dd
3 changed files with 164 additions and 89 deletions
|
|
@ -32,7 +32,11 @@ import javax.inject.Singleton
|
|||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
class NetworkModule {
|
||||
internal object NetworkModule {
|
||||
|
||||
private const val DEV_V1_TANGEM_TECH_BASE_URL = "https://devapi.tangem-tech.com/v1/"
|
||||
private const val PROD_V2_TANGEM_TECH_BASE_URL = "https://api.tangem-tech.com/v2/"
|
||||
private const val TANGEM_TECH_MARKETS_SERVICE_TIMEOUT_SECONDS = 60L
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
|
|
@ -55,20 +59,12 @@ class NetworkModule {
|
|||
@ApplicationContext context: Context,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
): TangemExpressApi {
|
||||
val environmentConfig = apiConfigsManager.getEnvironmentConfig(id = ApiConfig.ID.Express)
|
||||
|
||||
return Retrofit.Builder()
|
||||
.addConverterFactory(MoshiConverterFactory.create(moshi))
|
||||
.addCallAdapterFactory(ApiResponseCallAdapterFactory.create())
|
||||
.baseUrl(environmentConfig.baseUrl)
|
||||
.client(
|
||||
OkHttpClient.Builder()
|
||||
.applyApiConfig(ApiConfig.ID.Express, apiConfigsManager)
|
||||
.addLoggers(context)
|
||||
.build(),
|
||||
)
|
||||
.build()
|
||||
.create(TangemExpressApi::class.java)
|
||||
return createApi(
|
||||
id = ApiConfig.ID.Express,
|
||||
moshi = moshi,
|
||||
context = context,
|
||||
apiConfigsManager = apiConfigsManager,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
@ -78,20 +74,12 @@ class NetworkModule {
|
|||
@ApplicationContext context: Context,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
): StakeKitApi {
|
||||
val environmentConfig = apiConfigsManager.getEnvironmentConfig(id = ApiConfig.ID.StakeKit)
|
||||
|
||||
return Retrofit.Builder()
|
||||
.addConverterFactory(MoshiConverterFactory.create(moshi))
|
||||
.addCallAdapterFactory(ApiResponseCallAdapterFactory.create())
|
||||
.baseUrl(environmentConfig.baseUrl)
|
||||
.client(
|
||||
OkHttpClient.Builder()
|
||||
.applyApiConfig(id = ApiConfig.ID.StakeKit, apiConfigsManager = apiConfigsManager)
|
||||
.addLoggers(context)
|
||||
.build(),
|
||||
)
|
||||
.build()
|
||||
.create(StakeKitApi::class.java)
|
||||
return createApi(
|
||||
id = ApiConfig.ID.StakeKit,
|
||||
moshi = moshi,
|
||||
context = context,
|
||||
apiConfigsManager = apiConfigsManager,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
@ -101,36 +89,26 @@ class NetworkModule {
|
|||
@ApplicationContext context: Context,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
): TangemTechApi {
|
||||
val environmentConfig = apiConfigsManager.getEnvironmentConfig(id = ApiConfig.ID.TangemTech)
|
||||
|
||||
return Retrofit.Builder()
|
||||
.addConverterFactory(MoshiConverterFactory.create(moshi))
|
||||
.addCallAdapterFactory(ApiResponseCallAdapterFactory.create())
|
||||
.baseUrl(environmentConfig.baseUrl)
|
||||
.client(
|
||||
OkHttpClient.Builder()
|
||||
.applyApiConfig(id = ApiConfig.ID.TangemTech, apiConfigsManager = apiConfigsManager)
|
||||
.applyTimeoutAnnotations()
|
||||
.addLoggers(context)
|
||||
.build(),
|
||||
)
|
||||
.build()
|
||||
.create(TangemTechApi::class.java)
|
||||
return createApi(
|
||||
id = ApiConfig.ID.TangemTech,
|
||||
moshi = moshi,
|
||||
context = context,
|
||||
apiConfigsManager = apiConfigsManager,
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: It will be deleted in the future or refactored using ApiConfig
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideTangemTechApiV2(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
@ApplicationContext context: Context,
|
||||
appVersionProvider: AppVersionProvider,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
): TangemTechApiV2 {
|
||||
return provideTangemTechApiInternal(
|
||||
moshi = moshi,
|
||||
context = context,
|
||||
appVersionProvider = appVersionProvider,
|
||||
apiConfigsManager = apiConfigsManager,
|
||||
baseUrl = PROD_V2_TANGEM_TECH_BASE_URL,
|
||||
)
|
||||
}
|
||||
|
|
@ -142,17 +120,16 @@ class NetworkModule {
|
|||
@NetworkMoshi moshi: Moshi,
|
||||
@ApplicationContext context: Context,
|
||||
appVersionProvider: AppVersionProvider,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
): TangemTechApi {
|
||||
return provideTangemTechApiInternal(
|
||||
moshi = moshi,
|
||||
context = context,
|
||||
appVersionProvider = appVersionProvider,
|
||||
apiConfigsManager = apiConfigsManager,
|
||||
baseUrl = DEV_V1_TANGEM_TECH_BASE_URL,
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: [REDACTED_JIRA]
|
||||
@Provides
|
||||
@DevTangemApi
|
||||
@Singleton
|
||||
|
|
@ -160,13 +137,11 @@ class NetworkModule {
|
|||
@NetworkMoshi moshi: Moshi,
|
||||
@ApplicationContext context: Context,
|
||||
appVersionProvider: AppVersionProvider,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
): TangemTechMarketsApi {
|
||||
return provideTangemTechApiInternal(
|
||||
moshi = moshi,
|
||||
context = context,
|
||||
appVersionProvider = appVersionProvider,
|
||||
apiConfigsManager = apiConfigsManager,
|
||||
baseUrl = DEV_V1_TANGEM_TECH_BASE_URL,
|
||||
timeouts = Timeouts(
|
||||
callTimeoutSeconds = TANGEM_TECH_MARKETS_SERVICE_TIMEOUT_SECONDS,
|
||||
|
|
@ -181,13 +156,11 @@ class NetworkModule {
|
|||
moshi: Moshi,
|
||||
context: Context,
|
||||
appVersionProvider: AppVersionProvider,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
baseUrl: String,
|
||||
timeouts: Timeouts = Timeouts(),
|
||||
requestHeaders: List<RequestHeader> = listOf(AppVersionPlatformHeaders(appVersionProvider)),
|
||||
): T {
|
||||
val client = OkHttpClient.Builder()
|
||||
.applyApiConfig(id = ApiConfig.ID.TangemTech, apiConfigsManager = apiConfigsManager)
|
||||
.applyTimeoutAnnotations()
|
||||
.let { builder ->
|
||||
var b = builder
|
||||
|
|
@ -222,18 +195,33 @@ class NetworkModule {
|
|||
.create(T::class.java)
|
||||
}
|
||||
|
||||
private inline fun <reified T> createApi(
|
||||
id: ApiConfig.ID,
|
||||
moshi: Moshi,
|
||||
context: Context,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
): T {
|
||||
val environmentConfig = apiConfigsManager.getEnvironmentConfig(id)
|
||||
|
||||
return Retrofit.Builder()
|
||||
.addConverterFactory(MoshiConverterFactory.create(moshi))
|
||||
.addCallAdapterFactory(ApiResponseCallAdapterFactory.create())
|
||||
.baseUrl(environmentConfig.baseUrl)
|
||||
.client(
|
||||
OkHttpClient.Builder()
|
||||
.applyApiConfig(id, apiConfigsManager)
|
||||
.applyTimeoutAnnotations()
|
||||
.addLoggers(context)
|
||||
.build(),
|
||||
)
|
||||
.build()
|
||||
.create(T::class.java)
|
||||
}
|
||||
|
||||
private data class Timeouts(
|
||||
val callTimeoutSeconds: Long? = null,
|
||||
val connectTimeoutSeconds: Long? = null,
|
||||
val readTimeoutSeconds: Long? = null,
|
||||
val writeTimeoutSeconds: Long? = null,
|
||||
)
|
||||
|
||||
private companion object {
|
||||
const val DEV_V1_TANGEM_TECH_BASE_URL = "https://devapi.tangem-tech.com/v1/"
|
||||
|
||||
const val PROD_V2_TANGEM_TECH_BASE_URL = "https://api.tangem-tech.com/v2/"
|
||||
|
||||
const val TANGEM_TECH_MARKETS_SERVICE_TIMEOUT_SECONDS = 60L
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.datasource.api.common.config.managers
|
||||
|
||||
import com.tangem.datasource.config.ConfigManager
|
||||
import com.tangem.datasource.config.Loader
|
||||
import com.tangem.datasource.config.models.Config
|
||||
import com.tangem.datasource.config.models.ConfigModel
|
||||
import com.tangem.datasource.config.models.ExpressModel
|
||||
|
||||
/**
|
||||
* Mock [ConfigManager] implementation for [ProdApiConfigsManagerTest]
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class MockConfigManager : ConfigManager {
|
||||
|
||||
override val config = Config(
|
||||
express = ExpressModel(apiKey = ProdApiConfigsManagerTest.EXPRESS_API_KEY, signVerifierPublicKey = ""),
|
||||
devExpress = ExpressModel(apiKey = ProdApiConfigsManagerTest.EXPRESS_DEV_API_KEY, signVerifierPublicKey = ""),
|
||||
)
|
||||
|
||||
override suspend fun load(configLoader: Loader<ConfigModel>, onComplete: ((config: Config) -> Unit)?) = Unit
|
||||
override fun turnOff(name: String) = Unit
|
||||
override fun resetToDefault(name: String) = Unit
|
||||
}
|
||||
|
|
@ -2,20 +2,35 @@ package com.tangem.datasource.api.common.config.managers
|
|||
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.datasource.BuildConfig
|
||||
import com.tangem.datasource.api.common.config.ApiConfig
|
||||
import com.tangem.datasource.api.common.config.*
|
||||
import com.tangem.datasource.api.common.config.ApiConfig.Companion.DEBUG_BUILD_TYPE
|
||||
import com.tangem.datasource.api.common.config.ApiConfig.Companion.EXTERNAL_BUILD_TYPE
|
||||
import com.tangem.datasource.api.common.config.ApiConfig.Companion.INTERNAL_BUILD_TYPE
|
||||
import com.tangem.datasource.api.common.config.ApiConfig.Companion.MOCKED_BUILD_TYPE
|
||||
import com.tangem.datasource.api.common.config.ApiConfig.Companion.RELEASE_BUILD_TYPE
|
||||
import com.tangem.datasource.api.common.config.Express
|
||||
import com.tangem.datasource.api.common.config.StakeKit
|
||||
import com.tangem.datasource.api.common.config.TangemTech
|
||||
import com.tangem.lib.auth.ExpressAuthProvider
|
||||
import com.tangem.lib.auth.StakeKitAuthProvider
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.version.AppVersionProvider
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
private val configManager = MockConfigManager()
|
||||
private val appVersionProvider = mockk<AppVersionProvider>()
|
||||
private val expressAuthProvider = mockk<ExpressAuthProvider>()
|
||||
private val stakeKitAuthProvider = mockk<StakeKitAuthProvider>()
|
||||
|
||||
// Don't forget to add new config !!!
|
||||
private val API_CONFIGS = setOf(
|
||||
Express(configManager, expressAuthProvider, appVersionProvider),
|
||||
TangemTech(appVersionProvider),
|
||||
StakeKit(stakeKitAuthProvider),
|
||||
)
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
|
|
@ -24,24 +39,35 @@ internal class ProdApiConfigsManagerTest(private val model: Model) {
|
|||
|
||||
private val manager = ProdApiConfigsManager(API_CONFIGS)
|
||||
|
||||
@Test
|
||||
fun test_getBaseUrl() {
|
||||
val actual = manager.getEnvironmentConfig(id = model.id).baseUrl
|
||||
|
||||
Truth.assertThat(actual).isEqualTo(model.expected)
|
||||
@Before
|
||||
fun setup() {
|
||||
every { appVersionProvider.versionName } returns VERSION_NAME
|
||||
every { expressAuthProvider.getUserId() } returns EXPRESS_USER_ID
|
||||
every { expressAuthProvider.getSessionId() } returns EXPRESS_SESSION_ID
|
||||
every { stakeKitAuthProvider.getApiKey() } returns STAKE_KIT_API_KEY
|
||||
}
|
||||
|
||||
data class Model(val id: ApiConfig.ID, val expected: String)
|
||||
@Test
|
||||
fun test_getEnvironmentConfig() {
|
||||
val actual = manager.getEnvironmentConfig(id = model.id)
|
||||
|
||||
private companion object {
|
||||
Truth.assertThat(actual.environment).isEqualTo(model.expected.environment)
|
||||
Truth.assertThat(actual.baseUrl).isEqualTo(model.expected.baseUrl)
|
||||
|
||||
val API_CONFIGS = setOf(
|
||||
Express(mockk(), mockk(), mockk()),
|
||||
TangemTech(mockk()),
|
||||
StakeKit(mockk()),
|
||||
Truth.assertThat(actual.headers.mapValues { it.value() })
|
||||
.isEqualTo(model.expected.headers.mapValues { it.value() })
|
||||
}
|
||||
|
||||
// Don't forget to add new config
|
||||
)
|
||||
data class Model(val id: ApiConfig.ID, val expected: ApiEnvironmentConfig)
|
||||
|
||||
internal companion object {
|
||||
|
||||
const val VERSION_NAME = "debug"
|
||||
const val EXPRESS_USER_ID = "express_user_id"
|
||||
const val EXPRESS_SESSION_ID = "express_session_id"
|
||||
const val EXPRESS_API_KEY = "express_api_key"
|
||||
const val EXPRESS_DEV_API_KEY = "express_dev_api_key"
|
||||
const val STAKE_KIT_API_KEY = "stake_kit_api_key"
|
||||
|
||||
@JvmStatic
|
||||
@Parameterized.Parameters
|
||||
|
|
@ -54,32 +80,69 @@ internal class ProdApiConfigsManagerTest(private val model: Model) {
|
|||
}
|
||||
|
||||
private fun createExpressModel(): Model {
|
||||
val environment = when (BuildConfig.BUILD_TYPE) {
|
||||
DEBUG_BUILD_TYPE -> ApiEnvironment.DEV
|
||||
INTERNAL_BUILD_TYPE,
|
||||
MOCKED_BUILD_TYPE,
|
||||
-> ApiEnvironment.STAGE
|
||||
EXTERNAL_BUILD_TYPE,
|
||||
RELEASE_BUILD_TYPE,
|
||||
-> ApiEnvironment.PROD
|
||||
else -> error("Unknown build type [${BuildConfig.BUILD_TYPE}]")
|
||||
}
|
||||
|
||||
return Model(
|
||||
id = ApiConfig.ID.Express,
|
||||
expected = when (BuildConfig.BUILD_TYPE) {
|
||||
DEBUG_BUILD_TYPE -> "[REDACTED_ENV_URL]"
|
||||
INTERNAL_BUILD_TYPE,
|
||||
MOCKED_BUILD_TYPE,
|
||||
-> "[REDACTED_ENV_URL]"
|
||||
EXTERNAL_BUILD_TYPE,
|
||||
RELEASE_BUILD_TYPE,
|
||||
-> "https://express.tangem.com/v1/"
|
||||
else -> error("Unknown build type [${BuildConfig.BUILD_TYPE}]")
|
||||
},
|
||||
expected = ApiEnvironmentConfig(
|
||||
environment = environment,
|
||||
baseUrl = when (BuildConfig.BUILD_TYPE) {
|
||||
DEBUG_BUILD_TYPE -> "[REDACTED_ENV_URL]"
|
||||
INTERNAL_BUILD_TYPE,
|
||||
MOCKED_BUILD_TYPE,
|
||||
-> "[REDACTED_ENV_URL]"
|
||||
EXTERNAL_BUILD_TYPE,
|
||||
RELEASE_BUILD_TYPE,
|
||||
-> "https://express.tangem.com/v1/"
|
||||
else -> error("Unknown build type [${BuildConfig.BUILD_TYPE}]")
|
||||
},
|
||||
headers = mapOf(
|
||||
"api-key" to Provider {
|
||||
if (environment == ApiEnvironment.PROD) EXPRESS_API_KEY else EXPRESS_DEV_API_KEY
|
||||
},
|
||||
"user-id" to Provider { EXPRESS_USER_ID },
|
||||
"session-id" to Provider { EXPRESS_SESSION_ID },
|
||||
"version" to Provider { VERSION_NAME },
|
||||
"platform" to Provider { "android" },
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createTangemTechModel(): Model {
|
||||
return Model(
|
||||
id = ApiConfig.ID.TangemTech,
|
||||
expected = "https://api.tangem-tech.com/v1/",
|
||||
expected = ApiEnvironmentConfig(
|
||||
environment = ApiEnvironment.PROD,
|
||||
baseUrl = "https://api.tangem-tech.com/v1/",
|
||||
headers = mapOf(
|
||||
"version" to Provider { VERSION_NAME },
|
||||
"platform" to Provider { "android" },
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createStakeKitModel(): Model {
|
||||
return Model(
|
||||
id = ApiConfig.ID.StakeKit,
|
||||
expected = "https://api.stakek.it/v1/",
|
||||
expected = ApiEnvironmentConfig(
|
||||
environment = ApiEnvironment.PROD,
|
||||
baseUrl = "https://api.stakek.it/v1/",
|
||||
headers = mapOf(
|
||||
"X-API-KEY" to Provider { STAKE_KIT_API_KEY },
|
||||
"accept" to Provider { "application/json" },
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue