Updated on 2026-08-14
This commit is contained in:
parent
3b269e6f6a
commit
c40326c1c9
12 changed files with 128 additions and 58 deletions
|
|
@ -8,6 +8,7 @@ import coil.ImageLoaderFactory
|
|||
import com.chuckerteam.chucker.api.ChuckerInterceptor
|
||||
import com.tangem.Log
|
||||
import com.tangem.TangemSdkLogger
|
||||
import com.tangem.blockchain.common.ExceptionHandler
|
||||
import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder
|
||||
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
|
|
@ -55,6 +56,7 @@ import com.tangem.features.onramp.OnrampFeatureToggles
|
|||
import com.tangem.operations.attestation.OnlineCardVerifier
|
||||
import com.tangem.tap.common.analytics.AnalyticsFactory
|
||||
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
|
||||
import com.tangem.tap.common.analytics.handlers.BlockchainExceptionHandler
|
||||
import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeAnalyticsHandler
|
||||
import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler
|
||||
import com.tangem.tap.common.images.createCoilImageLoader
|
||||
|
|
@ -206,6 +208,9 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
|
|||
private val uiMessageSender: UiMessageSender
|
||||
get() = entryPoint.getUiMessageSender()
|
||||
|
||||
private val blockchainExceptionHandler: BlockchainExceptionHandler
|
||||
get() = entryPoint.getBlockchainExceptionHandler()
|
||||
|
||||
private val workerFactory: HiltWorkerFactory
|
||||
get() = entryPoint.getWorkerFactory()
|
||||
|
||||
|
|
@ -219,6 +224,7 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
|
|||
|
||||
private val userWalletBuilderFactory: UserWalletBuilder.Factory
|
||||
get() = entryPoint.getUserWalletBuilderFactory()
|
||||
|
||||
// endregion
|
||||
|
||||
override fun onCreate() {
|
||||
|
|
@ -264,7 +270,7 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
|
|||
}
|
||||
|
||||
loadNativeLibraries()
|
||||
// ExceptionHandler.append(blockchainExceptionHandler) // TODO [REDACTED_TASK_KEY] Send only to Firebase
|
||||
ExceptionHandler.append(blockchainExceptionHandler)
|
||||
if (LogConfig.network.blockchainSdkNetwork) {
|
||||
BlockchainSdkRetrofitBuilder.interceptors = listOf(
|
||||
createNetworkLoggingInterceptor(),
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
package com.tangem.tap.common.analytics.handlers
|
||||
|
||||
import com.tangem.blockchain.common.ExceptionHandlerOutput
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.api.AnalyticsErrorHandler
|
||||
import com.tangem.tap.common.analytics.events.BlockchainExceptionEvent
|
||||
import javax.inject.Inject
|
||||
|
||||
class BlockchainExceptionHandler @Inject constructor(
|
||||
private val analyticsHandler: AnalyticsEventHandler,
|
||||
private val analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
) : ExceptionHandlerOutput {
|
||||
override fun handleApiSwitch(currentHost: String, nextHost: String, message: String) {
|
||||
analyticsHandler.send(
|
||||
analyticsErrorHandler.sendErrorEvent(
|
||||
BlockchainExceptionEvent(
|
||||
selectedHost = nextHost,
|
||||
exceptionHost = currentHost,
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
package com.tangem.datasource.api.common.response
|
||||
|
||||
import com.tangem.core.analytics.api.AnalyticsErrorHandler
|
||||
import retrofit2.Call
|
||||
import retrofit2.CallAdapter
|
||||
import java.lang.reflect.Type
|
||||
|
||||
internal class ApiResponseCallAdapter(
|
||||
private val resultType: Type,
|
||||
private val analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
) : CallAdapter<Type, Call<ApiResponse<Type>>> {
|
||||
|
||||
override fun responseType(): Type = resultType
|
||||
|
||||
override fun adapt(call: Call<Type>): Call<ApiResponse<Type>> {
|
||||
return ApiResponseCallDelegate(call)
|
||||
return ApiResponseCallDelegate(call, analyticsErrorHandler)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,15 @@
|
|||
package com.tangem.datasource.api.common.response
|
||||
|
||||
import com.tangem.core.analytics.api.AnalyticsErrorHandler
|
||||
import retrofit2.Call
|
||||
import retrofit2.CallAdapter
|
||||
import retrofit2.Retrofit
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.Type
|
||||
|
||||
class ApiResponseCallAdapterFactory private constructor() : CallAdapter.Factory() {
|
||||
class ApiResponseCallAdapterFactory private constructor(
|
||||
private val analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
) : CallAdapter.Factory() {
|
||||
|
||||
override fun get(returnType: Type, annotations: Array<out Annotation>, retrofit: Retrofit): CallAdapter<*, *>? {
|
||||
if (getRawType(returnType) != Call::class.java) {
|
||||
|
|
@ -19,11 +22,11 @@ class ApiResponseCallAdapterFactory private constructor() : CallAdapter.Factory(
|
|||
}
|
||||
|
||||
val resultType = getParameterUpperBound(0, callType as ParameterizedType)
|
||||
return ApiResponseCallAdapter(resultType)
|
||||
return ApiResponseCallAdapter(resultType, analyticsErrorHandler)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun create() = ApiResponseCallAdapterFactory()
|
||||
fun create(analyticsErrorHandler: AnalyticsErrorHandler) = ApiResponseCallAdapterFactory(analyticsErrorHandler)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.datasource.api.common.response
|
||||
|
||||
import com.tangem.core.analytics.api.AnalyticsErrorHandler
|
||||
import okhttp3.Request
|
||||
import okio.Timeout
|
||||
import retrofit2.Call
|
||||
|
|
@ -9,6 +10,7 @@ import timber.log.Timber
|
|||
|
||||
internal class ApiResponseCallDelegate<T : Any>(
|
||||
private val wrappedCall: Call<T>,
|
||||
private val analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
) : Call<ApiResponse<T>> {
|
||||
|
||||
override fun enqueue(callback: Callback<ApiResponse<T>>) {
|
||||
|
|
@ -16,7 +18,7 @@ internal class ApiResponseCallDelegate<T : Any>(
|
|||
}
|
||||
|
||||
override fun execute(): Response<ApiResponse<T>> = throw NotImplementedError()
|
||||
override fun clone(): Call<ApiResponse<T>> = ApiResponseCallDelegate(wrappedCall.clone())
|
||||
override fun clone(): Call<ApiResponse<T>> = ApiResponseCallDelegate(wrappedCall.clone(), analyticsErrorHandler)
|
||||
override fun request(): Request = wrappedCall.request()
|
||||
override fun timeout(): Timeout = wrappedCall.timeout()
|
||||
override fun isExecuted(): Boolean = wrappedCall.isExecuted
|
||||
|
|
@ -30,7 +32,7 @@ internal class ApiResponseCallDelegate<T : Any>(
|
|||
) : Callback<T> {
|
||||
|
||||
override fun onResponse(call: Call<T>, response: Response<T>) {
|
||||
val safeResponse = response.toSafeApiResponse()
|
||||
val safeResponse = response.toSafeApiResponse(analyticsErrorHandler)
|
||||
|
||||
responseCallback.onResponse(this@ApiResponseCallDelegate, Response.success(safeResponse))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,51 +19,51 @@ sealed class ApiResponseError : Exception() {
|
|||
) : ApiResponseError() {
|
||||
|
||||
// region Error Codes
|
||||
enum class Code(val code: Int) {
|
||||
enum class Code(val numericCode: Int) {
|
||||
// 4xx Server Errors
|
||||
BAD_REQUEST(code = 400),
|
||||
UNAUTHORIZED(code = 401),
|
||||
PAYMENT_REQUIRED(code = 402),
|
||||
FORBIDDEN(code = 403),
|
||||
NOT_FOUND(code = 404),
|
||||
METHOD_NOT_ALLOWED(code = 405),
|
||||
NOT_ACCEPTABLE(code = 406),
|
||||
PROXY_AUTHENTICATION_REQUIRED(code = 407),
|
||||
REQUEST_TIMEOUT(code = 408),
|
||||
CONFLICT(code = 409),
|
||||
GONE(code = 410),
|
||||
LENGTH_REQUIRED(code = 411),
|
||||
PRECONDITION_FAILED(code = 412),
|
||||
PAYLOAD_TOO_LARGE(code = 413),
|
||||
URI_TOO_LONG(code = 414),
|
||||
UNSUPPORTED_MEDIA_TYPE(code = 415),
|
||||
RANGE_NOT_SATISFIABLE(code = 416),
|
||||
EXPECTATION_FAILED(code = 417),
|
||||
IM_A_TEAPOT(code = 418), // Not an error, but an April Fools' joke from RFC 2324
|
||||
UNPROCESSABLE_ENTITY(code = 422),
|
||||
LOCKED(code = 423),
|
||||
FAILED_DEPENDENCY(code = 424),
|
||||
TOO_EARLY(code = 425),
|
||||
UPGRADE_REQUIRED(code = 426),
|
||||
PRECONDITION_REQUIRED(code = 428),
|
||||
TOO_MANY_REQUESTS(code = 429),
|
||||
REQUEST_HEADER_FIELDS_TOO_LARGE(code = 431),
|
||||
UNAVAILABLE_FOR_LEGAL_REASONS(code = 451),
|
||||
BAD_REQUEST(numericCode = 400),
|
||||
UNAUTHORIZED(numericCode = 401),
|
||||
PAYMENT_REQUIRED(numericCode = 402),
|
||||
FORBIDDEN(numericCode = 403),
|
||||
NOT_FOUND(numericCode = 404),
|
||||
METHOD_NOT_ALLOWED(numericCode = 405),
|
||||
NOT_ACCEPTABLE(numericCode = 406),
|
||||
PROXY_AUTHENTICATION_REQUIRED(numericCode = 407),
|
||||
REQUEST_TIMEOUT(numericCode = 408),
|
||||
CONFLICT(numericCode = 409),
|
||||
GONE(numericCode = 410),
|
||||
LENGTH_REQUIRED(numericCode = 411),
|
||||
PRECONDITION_FAILED(numericCode = 412),
|
||||
PAYLOAD_TOO_LARGE(numericCode = 413),
|
||||
URI_TOO_LONG(numericCode = 414),
|
||||
UNSUPPORTED_MEDIA_TYPE(numericCode = 415),
|
||||
RANGE_NOT_SATISFIABLE(numericCode = 416),
|
||||
EXPECTATION_FAILED(numericCode = 417),
|
||||
IM_A_TEAPOT(numericCode = 418), // Not an error, but an April Fools' joke from RFC 2324
|
||||
UNPROCESSABLE_ENTITY(numericCode = 422),
|
||||
LOCKED(numericCode = 423),
|
||||
FAILED_DEPENDENCY(numericCode = 424),
|
||||
TOO_EARLY(numericCode = 425),
|
||||
UPGRADE_REQUIRED(numericCode = 426),
|
||||
PRECONDITION_REQUIRED(numericCode = 428),
|
||||
TOO_MANY_REQUESTS(numericCode = 429),
|
||||
REQUEST_HEADER_FIELDS_TOO_LARGE(numericCode = 431),
|
||||
UNAVAILABLE_FOR_LEGAL_REASONS(numericCode = 451),
|
||||
// 5xx Server Errors
|
||||
INTERNAL_SERVER_ERROR(code = 500),
|
||||
NOT_IMPLEMENTED(code = 501),
|
||||
BAD_GATEWAY(code = 502),
|
||||
SERVICE_UNAVAILABLE(code = 503),
|
||||
GATEWAY_TIMEOUT(code = 504),
|
||||
HTTP_VERSION_NOT_SUPPORTED(code = 505),
|
||||
VARIANT_ALSO_NEGOTIATES(code = 506),
|
||||
INSUFFICIENT_STORAGE(code = 507),
|
||||
LOOP_DETECTED(code = 508),
|
||||
NOT_EXTENDED(code = 510),
|
||||
NETWORK_AUTHENTICATION_REQUIRED(code = 511),
|
||||
INTERNAL_SERVER_ERROR(numericCode = 500),
|
||||
NOT_IMPLEMENTED(numericCode = 501),
|
||||
BAD_GATEWAY(numericCode = 502),
|
||||
SERVICE_UNAVAILABLE(numericCode = 503),
|
||||
GATEWAY_TIMEOUT(numericCode = 504),
|
||||
HTTP_VERSION_NOT_SUPPORTED(numericCode = 505),
|
||||
VARIANT_ALSO_NEGOTIATES(numericCode = 506),
|
||||
INSUFFICIENT_STORAGE(numericCode = 507),
|
||||
LOOP_DETECTED(numericCode = 508),
|
||||
NOT_EXTENDED(numericCode = 510),
|
||||
NETWORK_AUTHENTICATION_REQUIRED(numericCode = 511),
|
||||
;
|
||||
|
||||
override fun toString(): String = "$code - $name"
|
||||
override fun toString(): String = "$numericCode - $name"
|
||||
|
||||
companion object {
|
||||
val values = values()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.tangem.datasource.api.common.response
|
||||
|
||||
import com.tangem.core.analytics.api.AnalyticsErrorHandler
|
||||
import com.tangem.datasource.api.common.response.analytics.ApiErrorEvent
|
||||
import kotlinx.coroutines.TimeoutCancellationException
|
||||
import retrofit2.Response
|
||||
import timber.log.Timber
|
||||
|
|
@ -9,18 +11,20 @@ import java.net.UnknownHostException
|
|||
import java.util.concurrent.TimeoutException
|
||||
import javax.net.ssl.SSLHandshakeException
|
||||
|
||||
internal fun <T : Any> Response<T>.toSafeApiResponse(): ApiResponse<T> {
|
||||
internal fun <T : Any> Response<T>.toSafeApiResponse(analyticsErrorHandler: AnalyticsErrorHandler): ApiResponse<T> {
|
||||
val body = body()
|
||||
|
||||
return if (isSuccessful && body != null) {
|
||||
apiSuccess(body)
|
||||
} else {
|
||||
val code = ApiResponseError.HttpException.Code.values
|
||||
.firstOrNull { it.code == code() }
|
||||
.firstOrNull { it.numericCode == code() }
|
||||
val e = try {
|
||||
if (code == null) {
|
||||
ApiResponseError.UnknownException(IllegalArgumentException("Unknown error status code: ${code()}"))
|
||||
} else {
|
||||
sendHttpError(code, analyticsErrorHandler)
|
||||
|
||||
ApiResponseError.HttpException(code, message(), errorBody()?.string())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
|
@ -32,6 +36,21 @@ internal fun <T : Any> Response<T>.toSafeApiResponse(): ApiResponse<T> {
|
|||
}
|
||||
}
|
||||
|
||||
private fun <T : Any> Response<T>.sendHttpError(
|
||||
code: ApiResponseError.HttpException.Code,
|
||||
analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
) {
|
||||
val fullRequestUrl = raw().request.url.toUrl()
|
||||
val shortUrl = fullRequestUrl.authority + fullRequestUrl.path
|
||||
analyticsErrorHandler.sendErrorEvent(
|
||||
ApiErrorEvent(
|
||||
endpoint = shortUrl,
|
||||
code = code.numericCode,
|
||||
message = errorBody()?.string().orEmpty(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
internal fun Throwable.toApiError(): ApiResponseError = when (this) {
|
||||
is ConnectException,
|
||||
is UnknownHostException,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.datasource.api.common.response.analytics
|
||||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
||||
internal data class ApiErrorEvent(
|
||||
val endpoint: String,
|
||||
val code: Int,
|
||||
val message: String,
|
||||
) : AnalyticsEvent(
|
||||
category = "Tangem API Service",
|
||||
event = "Exception",
|
||||
params = mapOf(
|
||||
"Endpoint" to endpoint,
|
||||
"Code" to code.toString(),
|
||||
"Message" to message,
|
||||
),
|
||||
)
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.datasource.di
|
|||
|
||||
import android.content.Context
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.core.analytics.api.AnalyticsErrorHandler
|
||||
import com.tangem.datasource.BuildConfig
|
||||
import com.tangem.datasource.api.common.config.ApiConfig
|
||||
import com.tangem.datasource.api.common.config.ApiConfigs
|
||||
|
|
@ -61,6 +62,7 @@ internal object NetworkModule {
|
|||
fun provideExpressApi(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
@ApplicationContext context: Context,
|
||||
analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
appLogsStore: AppLogsStore,
|
||||
): TangemExpressApi {
|
||||
|
|
@ -69,6 +71,7 @@ internal object NetworkModule {
|
|||
moshi = moshi,
|
||||
context = context,
|
||||
apiConfigsManager = apiConfigsManager,
|
||||
analyticsErrorHandler = analyticsErrorHandler,
|
||||
clientBuilder = {
|
||||
addInterceptor(
|
||||
NetworkLogsSaveInterceptor(appLogsStore),
|
||||
|
|
@ -83,6 +86,7 @@ internal object NetworkModule {
|
|||
@NetworkMoshi moshi: Moshi,
|
||||
@ApplicationContext context: Context,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
appLogsStore: AppLogsStore,
|
||||
): StakeKitApi {
|
||||
return createApi(
|
||||
|
|
@ -90,6 +94,7 @@ internal object NetworkModule {
|
|||
moshi = moshi,
|
||||
context = context,
|
||||
apiConfigsManager = apiConfigsManager,
|
||||
analyticsErrorHandler = analyticsErrorHandler,
|
||||
timeouts = Timeouts(
|
||||
callTimeoutSeconds = STAKE_KIT_API_TIMEOUT_SECONDS,
|
||||
connectTimeoutSeconds = STAKE_KIT_API_TIMEOUT_SECONDS,
|
||||
|
|
@ -109,6 +114,7 @@ internal object NetworkModule {
|
|||
fun provideOnrampApi(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
@ApplicationContext context: Context,
|
||||
analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
appLogsStore: AppLogsStore,
|
||||
): OnrampApi {
|
||||
|
|
@ -117,6 +123,7 @@ internal object NetworkModule {
|
|||
moshi = moshi,
|
||||
context = context,
|
||||
apiConfigsManager = apiConfigsManager,
|
||||
analyticsErrorHandler = analyticsErrorHandler,
|
||||
clientBuilder = {
|
||||
addInterceptor(
|
||||
NetworkLogsSaveInterceptor(appLogsStore),
|
||||
|
|
@ -130,6 +137,7 @@ internal object NetworkModule {
|
|||
fun provideTangemTechApi(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
@ApplicationContext context: Context,
|
||||
analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
): TangemTechApi {
|
||||
return createApi(
|
||||
|
|
@ -137,6 +145,7 @@ internal object NetworkModule {
|
|||
moshi = moshi,
|
||||
context = context,
|
||||
apiConfigsManager = apiConfigsManager,
|
||||
analyticsErrorHandler = analyticsErrorHandler,
|
||||
clientBuilder = { applyTimeoutAnnotations() },
|
||||
)
|
||||
}
|
||||
|
|
@ -147,6 +156,7 @@ internal object NetworkModule {
|
|||
fun provideTangemTechApiV2(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
@ApplicationContext context: Context,
|
||||
analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
appVersionProvider: AppVersionProvider,
|
||||
): TangemTechApiV2 {
|
||||
return provideTangemTechApiInternal(
|
||||
|
|
@ -154,6 +164,7 @@ internal object NetworkModule {
|
|||
context = context,
|
||||
appVersionProvider = appVersionProvider,
|
||||
baseUrl = PROD_V2_TANGEM_TECH_BASE_URL,
|
||||
analyticsErrorHandler = analyticsErrorHandler,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -162,6 +173,7 @@ internal object NetworkModule {
|
|||
fun provideTangemTechMarketsApi(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
@ApplicationContext context: Context,
|
||||
analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
): TangemTechMarketsApi {
|
||||
return createApi(
|
||||
|
|
@ -169,6 +181,7 @@ internal object NetworkModule {
|
|||
moshi = moshi,
|
||||
context = context,
|
||||
apiConfigsManager = apiConfigsManager,
|
||||
analyticsErrorHandler = analyticsErrorHandler,
|
||||
clientBuilder = {
|
||||
this.callTimeout(TANGEM_TECH_MARKETS_SERVICE_TIMEOUT_SECONDS, TimeUnit.SECONDS)
|
||||
.connectTimeout(TANGEM_TECH_MARKETS_SERVICE_TIMEOUT_SECONDS, TimeUnit.SECONDS)
|
||||
|
|
@ -183,6 +196,7 @@ internal object NetworkModule {
|
|||
fun provideTangemVisaAuthApi(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
@ApplicationContext context: Context,
|
||||
analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
appLogsStore: AppLogsStore,
|
||||
): TangemVisaAuthApi {
|
||||
|
|
@ -191,6 +205,7 @@ internal object NetworkModule {
|
|||
moshi = moshi,
|
||||
context = context,
|
||||
apiConfigsManager = apiConfigsManager,
|
||||
analyticsErrorHandler = analyticsErrorHandler,
|
||||
clientBuilder = {
|
||||
addInterceptor(
|
||||
NetworkLogsSaveInterceptor(appLogsStore),
|
||||
|
|
@ -204,6 +219,7 @@ internal object NetworkModule {
|
|||
fun provideTangemVisaApi(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
@ApplicationContext context: Context,
|
||||
analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
appLogsStore: AppLogsStore,
|
||||
): TangemVisaApi {
|
||||
|
|
@ -212,6 +228,7 @@ internal object NetworkModule {
|
|||
moshi = moshi,
|
||||
context = context,
|
||||
apiConfigsManager = apiConfigsManager,
|
||||
analyticsErrorHandler = analyticsErrorHandler,
|
||||
clientBuilder = {
|
||||
addInterceptor(
|
||||
NetworkLogsSaveInterceptor(appLogsStore),
|
||||
|
|
@ -226,6 +243,7 @@ internal object NetworkModule {
|
|||
context: Context,
|
||||
appVersionProvider: AppVersionProvider,
|
||||
baseUrl: String,
|
||||
analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
timeouts: Timeouts = Timeouts(),
|
||||
requestHeaders: List<RequestHeader> = listOf(AppVersionPlatformHeaders(appVersionProvider)),
|
||||
): T {
|
||||
|
|
@ -257,7 +275,7 @@ internal object NetworkModule {
|
|||
|
||||
return Retrofit.Builder()
|
||||
.addConverterFactory(MoshiConverterFactory.create(moshi))
|
||||
.addCallAdapterFactory(ApiResponseCallAdapterFactory.create())
|
||||
.addCallAdapterFactory(ApiResponseCallAdapterFactory.create(analyticsErrorHandler))
|
||||
.baseUrl(baseUrl)
|
||||
.client(client)
|
||||
.build()
|
||||
|
|
@ -269,6 +287,7 @@ internal object NetworkModule {
|
|||
moshi: Moshi,
|
||||
context: Context,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
timeouts: Timeouts = Timeouts(),
|
||||
clientBuilder: OkHttpClient.Builder.() -> OkHttpClient.Builder = { this },
|
||||
): T {
|
||||
|
|
@ -276,7 +295,7 @@ internal object NetworkModule {
|
|||
|
||||
return Retrofit.Builder()
|
||||
.addConverterFactory(MoshiConverterFactory.create(moshi))
|
||||
.addCallAdapterFactory(ApiResponseCallAdapterFactory.create())
|
||||
.addCallAdapterFactory(ApiResponseCallAdapterFactory.create(analyticsErrorHandler))
|
||||
.baseUrl(environmentConfig.baseUrl)
|
||||
.client(
|
||||
OkHttpClient.Builder()
|
||||
|
|
|
|||
|
|
@ -335,7 +335,7 @@ internal class DefaultMarketsTokenRepository(
|
|||
): T {
|
||||
return when (error) {
|
||||
is ApiResponseError.HttpException -> {
|
||||
createEvent(MarketsDataAnalyticsEvent.Type.Http, error.code.code, error.message.orEmpty())
|
||||
createEvent(MarketsDataAnalyticsEvent.Type.Http, error.code.numericCode, error.message.orEmpty())
|
||||
}
|
||||
is ApiResponseError.TimeoutException -> {
|
||||
createEvent(MarketsDataAnalyticsEvent.Type.Timeout, null, error.message.orEmpty())
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ internal class DefaultHotCryptoRepository(
|
|||
|
||||
analyticsEventHandler.send(
|
||||
event = MainScreenAnalyticsEvent.HotTokenError(
|
||||
errorCode = (it as? ApiResponseError.HttpException)?.code?.code?.toString().orEmpty(),
|
||||
errorCode = (it as? ApiResponseError.HttpException)?.code?.numericCode?.toString().orEmpty(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import arrow.core.getOrElse
|
|||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.ui.bottomsheet.permission.state.ApproveType
|
||||
import com.tangem.common.ui.bottomsheet.permission.state.GiveTxPermissionState.InProgress.getApproveTypeOrNull
|
||||
import com.tangem.core.analytics.api.AnalyticsErrorHandler
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
|
|
@ -82,6 +83,7 @@ internal class SwapModel @Inject constructor(
|
|||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val blockchainInteractor: BlockchainInteractor,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val analyticsErrorEventHandler: AnalyticsErrorHandler,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusSyncUseCase,
|
||||
private val updateDelayedCurrencyStatusUseCase: UpdateDelayedNetworkStatusUseCase,
|
||||
|
|
@ -483,7 +485,7 @@ internal class SwapModel @Inject constructor(
|
|||
val receiveToken = dataState.toCryptoCurrency?.currency?.let {
|
||||
"${it.network.backendId}:${it.symbol}"
|
||||
}
|
||||
analyticsEventHandler.send(
|
||||
analyticsErrorEventHandler.sendErrorEvent(
|
||||
SwapEvents.NoticeProviderError(
|
||||
sendToken = "${initialCurrencyFrom.network.backendId}:${initialCurrencyFrom.symbol}",
|
||||
receiveToken = receiveToken ?: "",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue