Updated on 2026-08-14
This commit is contained in:
parent
9b5bc7bdff
commit
608121ab50
9 changed files with 277 additions and 1 deletions
1
network/.gitignore
vendored
Normal file
1
network/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
23
network/build.gradle
Normal file
23
network/build.gradle
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
plugins {
|
||||
id 'java-library'
|
||||
id 'org.jetbrains.kotlin.jvm'
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Tangem sdk's
|
||||
implementation 'com.tangem.tangem-sdk-kotlin:core:develop-140'
|
||||
|
||||
// Network
|
||||
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.3"))
|
||||
implementation("com.squareup.okhttp3:okhttp")
|
||||
implementation("com.squareup.okhttp3:logging-interceptor")
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.8.1'
|
||||
implementation 'com.squareup.retrofit2:converter-moshi:2.6.0'
|
||||
implementation 'com.squareup.moshi:moshi:1.13.0'
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.tangem.network.api.tangemTech
|
||||
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
data class CoinsPricesResponse(
|
||||
val prices: List<CoinPrice>
|
||||
)
|
||||
|
||||
data class CoinPrice(
|
||||
val name: String,
|
||||
val price: BigDecimal,
|
||||
)
|
||||
|
||||
data class CoinsCheckAddressResponse(
|
||||
val imageHost: String,
|
||||
val tokens: List<Token>,
|
||||
val total: Int,
|
||||
) {
|
||||
data class Token(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val symbol: String,
|
||||
val active: Boolean,
|
||||
val contracts: List<Contract>
|
||||
) {
|
||||
data class Contract(
|
||||
val networkId: String,
|
||||
val address: String,
|
||||
val decimalCount: BigDecimal,
|
||||
val active: Boolean
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class CoinsCurrenciesResponse(
|
||||
val currencies: List<Currency>,
|
||||
) {
|
||||
data class Currency(
|
||||
val id: String,
|
||||
val code: String,
|
||||
val name: String,
|
||||
val rateBTC: String,
|
||||
val unit: String,
|
||||
val type: String,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.tangem.network.api.tangemTech
|
||||
|
||||
import com.tangem.common.services.Result
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Query
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface TangemTechApi {
|
||||
|
||||
@GET("coins/prices")
|
||||
suspend fun coinsPrices(
|
||||
@Query("currency") currency: String,
|
||||
@Query("ids") ids: List<String>,
|
||||
): Result<CoinsPricesResponse>
|
||||
|
||||
@GET("coins/check-address")
|
||||
suspend fun coinsCheckAddress(
|
||||
@Query("contractAddress") contractAddress: String,
|
||||
@Query("networkId") networkId: String? = null,
|
||||
): Result<CoinsCheckAddressResponse>
|
||||
|
||||
@GET("coins/currencies")
|
||||
suspend fun coinsCurrencies(): Result<CoinsCurrenciesResponse>
|
||||
|
||||
@GET("coins/tokens")
|
||||
suspend fun coinsTokens(): Result<CoinsCurrenciesResponse>
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.tangem.network.api.tangemTech
|
||||
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.network.common.AddHeaderInterceptor
|
||||
import com.tangem.network.common.CacheHttpInterceptor
|
||||
import com.tangem.network.common.createRetrofitInstance
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class TangemTechService {
|
||||
|
||||
private val headerInterceptors = mutableListOf<AddHeaderInterceptor>(
|
||||
CacheHttpInterceptor(cacheMaxAge)
|
||||
)
|
||||
|
||||
private var api: TangemTechApi = createApi()
|
||||
|
||||
suspend fun coinsPrices(
|
||||
currency: String,
|
||||
ids: List<String>
|
||||
): Result<CoinsPricesResponse> {
|
||||
return api.coinsPrices(currency, ids)
|
||||
}
|
||||
|
||||
suspend fun coinsCheckAddress(
|
||||
contractAddress: String,
|
||||
networkId: String? = null
|
||||
): Result<CoinsCheckAddressResponse> {
|
||||
return api.coinsCheckAddress(contractAddress, networkId)
|
||||
}
|
||||
|
||||
suspend fun coinsCurrencies(): Result<CoinsCurrenciesResponse> {
|
||||
return api.coinsCurrencies()
|
||||
}
|
||||
|
||||
suspend fun coinsTokens(): Result<CoinsCurrenciesResponse> {
|
||||
return api.coinsTokens()
|
||||
}
|
||||
|
||||
fun addHeaderInterceptors(interceptors: List<AddHeaderInterceptor>) {
|
||||
headerInterceptors.removeAll(interceptors)
|
||||
headerInterceptors.addAll(interceptors)
|
||||
api = createApi()
|
||||
}
|
||||
|
||||
private fun createApi(): TangemTechApi {
|
||||
val retrofit = createRetrofitInstance(
|
||||
baseUrl = baseUrl,
|
||||
interceptors = headerInterceptors.toList()
|
||||
)
|
||||
|
||||
return retrofit.create(TangemTechApi::class.java)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val baseUrl = "https://api.tangem-tech.com/"
|
||||
const val cacheMaxAge = 600
|
||||
}
|
||||
}
|
||||
|
||||
class TangemAuthInterceptor(
|
||||
private val cardPublicKeyHex: String
|
||||
) : AddHeaderInterceptor(
|
||||
mapOf("card_public_key" to cardPublicKeyHex)
|
||||
)
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.network.common
|
||||
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
open class AddHeaderInterceptor(
|
||||
private val headers: Map<String, String>
|
||||
) : Interceptor {
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request().newBuilder().apply {
|
||||
headers.forEach {
|
||||
addHeader(it.key, it.value)
|
||||
}
|
||||
}.build()
|
||||
|
||||
return chain.proceed(request)
|
||||
}
|
||||
}
|
||||
|
||||
class CacheHttpInterceptor(
|
||||
maxAgeSeconds: Int
|
||||
) : AddHeaderInterceptor(mapOf("Cache-Control" to "max-age=$maxAgeSeconds"))
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.tangem.network.common
|
||||
|
||||
import com.squareup.moshi.FromJson
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.ToJson
|
||||
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
|
||||
import com.tangem.common.json.MoshiJsonConverter
|
||||
import com.tangem.common.json.TangemSdkAdapter
|
||||
import retrofit2.Converter
|
||||
import retrofit2.converter.moshi.MoshiConverterFactory
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class MoshiConverter {
|
||||
|
||||
companion object {
|
||||
fun createFactory(moshi: Moshi = defaultMoshi()): Converter.Factory = MoshiConverterFactory.create(moshi)
|
||||
|
||||
fun defaultMoshi(): Moshi = Moshi.Builder()
|
||||
.add(BigDecimalAdapter)
|
||||
.add(KotlinJsonAdapterFactory())
|
||||
.add(TangemSdkAdapter.DerivationPathAdapter())
|
||||
.add(TangemSdkAdapter.DerivationNodeAdapter())
|
||||
.build()
|
||||
|
||||
fun sdkMoshi(): Moshi = MoshiJsonConverter.INSTANCE.moshi
|
||||
}
|
||||
}
|
||||
|
||||
object BigDecimalAdapter {
|
||||
@FromJson
|
||||
fun fromJson(string: String) = BigDecimal(string)
|
||||
|
||||
@ToJson
|
||||
fun toJson(value: BigDecimal) = value.toString()
|
||||
}
|
||||
41
network/src/main/java/com/tangem/network/common/Retrofit.kt
Normal file
41
network/src/main/java/com/tangem/network/common/Retrofit.kt
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
package com.tangem.network.common
|
||||
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import retrofit2.Converter
|
||||
import retrofit2.Retrofit
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
// TODO: refactoring: make it better through factory
|
||||
fun createRetrofitInstance(
|
||||
baseUrl: String,
|
||||
okHttpBuilder: OkHttpClient.Builder = OkHttpClient.Builder(),
|
||||
interceptors: List<Interceptor> = emptyList(),
|
||||
converterFactory: Converter.Factory = MoshiConverter.createFactory(),
|
||||
logEnabled: Boolean = false
|
||||
): Retrofit {
|
||||
interceptors.forEach { okHttpBuilder.addInterceptor(it) }
|
||||
addTimeOuts(okHttpBuilder)
|
||||
|
||||
if (logEnabled) okHttpBuilder.addInterceptor(createHttpLoggingInterceptor())
|
||||
|
||||
return Retrofit.Builder()
|
||||
.baseUrl(baseUrl)
|
||||
.addConverterFactory(converterFactory)
|
||||
.client(okHttpBuilder.build())
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun addTimeOuts(okHttpBuilder: OkHttpClient.Builder) {
|
||||
okHttpBuilder.callTimeout(1, TimeUnit.SECONDS)
|
||||
okHttpBuilder.connectTimeout(20, TimeUnit.SECONDS)
|
||||
okHttpBuilder.readTimeout(20, TimeUnit.SECONDS)
|
||||
okHttpBuilder.writeTimeout(20, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
private fun createHttpLoggingInterceptor(): HttpLoggingInterceptor {
|
||||
return HttpLoggingInterceptor().apply {
|
||||
level = HttpLoggingInterceptor.Level.BODY
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1,2 @@
|
|||
include ':app'
|
||||
include ':app'
|
||||
include ':network'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue