From d3d658fa04bb19f13f05a115802971f6db94c118 Mon Sep 17 00:00:00 2001 From: Andrei Date: Wed, 19 Jun 2024 00:00:00 +0000 Subject: [PATCH 1/3] Propagate connection timeout in LNURL withdraw flow --- libs/sdk-bindings/src/breez_sdk.udl | 1 + libs/sdk-common/src/lnurl/specs/withdraw.rs | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/libs/sdk-bindings/src/breez_sdk.udl b/libs/sdk-bindings/src/breez_sdk.udl index f7f5555c1..03cb72043 100644 --- a/libs/sdk-bindings/src/breez_sdk.udl +++ b/libs/sdk-bindings/src/breez_sdk.udl @@ -668,6 +668,7 @@ dictionary LnUrlWithdrawRequest { [Enum] interface LnUrlWithdrawResult { Ok(LnUrlWithdrawSuccessData data); + Timeout(LnUrlWithdrawSuccessData data); ErrorStatus(LnUrlErrorData data); }; diff --git a/libs/sdk-common/src/lnurl/specs/withdraw.rs b/libs/sdk-common/src/lnurl/specs/withdraw.rs index 59df57a9a..6c61cd86e 100644 --- a/libs/sdk-common/src/lnurl/specs/withdraw.rs +++ b/libs/sdk-common/src/lnurl/specs/withdraw.rs @@ -33,14 +33,15 @@ pub async fn validate_lnurl_withdraw( // Send invoice to the LNURL-w endpoint via the callback let callback_url = build_withdraw_callback_url(&req_data, &invoice)?; - let callback_res: LnUrlCallbackStatus = get_parse_and_log_response(&callback_url, false) - .await - .map_err(|e| LnUrlError::ServiceConnectivity(e.to_string()))?; - let withdraw_status = match callback_res { - LnUrlCallbackStatus::Ok => LnUrlWithdrawResult::Ok { + let withdraw_status = match get_parse_and_log_response(&callback_url, false).await { + Ok(LnUrlCallbackStatus::Ok) => LnUrlWithdrawResult::Ok { data: LnUrlWithdrawSuccessData { invoice }, }, - LnUrlCallbackStatus::ErrorStatus { data } => LnUrlWithdrawResult::ErrorStatus { data }, + Ok(LnUrlCallbackStatus::ErrorStatus { data }) => LnUrlWithdrawResult::ErrorStatus { data }, + Err(e) if e.to_string().contains("operation timed out") => LnUrlWithdrawResult::Timeout { + data: LnUrlWithdrawSuccessData { invoice }, + }, + Err(e) => return Err(LnUrlError::ServiceConnectivity(e.to_string())), }; Ok(withdraw_status) @@ -102,6 +103,7 @@ pub mod model { #[derive(Clone, Serialize)] pub enum LnUrlWithdrawResult { Ok { data: LnUrlWithdrawSuccessData }, + Timeout { data: LnUrlWithdrawSuccessData }, ErrorStatus { data: LnUrlErrorData }, } From 6b5c44a4b9b048d0b81f5dad833a1878ef94f3b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Granh=C3=A3o?= Date: Wed, 19 Jun 2024 17:42:28 +0100 Subject: [PATCH 2/3] Generate bindings --- libs/sdk-core/src/binding.rs | 1 + libs/sdk-core/src/bridge_generated.rs | 8 +- libs/sdk-flutter/lib/bridge_generated.dart | 7 + .../lib/bridge_generated.freezed.dart | 159 ++++++++++++++++++ .../main/java/com/breezsdk/BreezSDKMapper.kt | 7 + .../sdk-react-native/ios/BreezSDKMapper.swift | 16 ++ libs/sdk-react-native/src/index.ts | 4 + 7 files changed, 201 insertions(+), 1 deletion(-) diff --git a/libs/sdk-core/src/binding.rs b/libs/sdk-core/src/binding.rs index 2d0aa2c92..200c7ccb6 100644 --- a/libs/sdk-core/src/binding.rs +++ b/libs/sdk-core/src/binding.rs @@ -232,6 +232,7 @@ pub enum _LnUrlPayError { #[frb(mirror(LnUrlWithdrawResult))] pub enum _LnUrlWithdrawResult { Ok { data: LnUrlWithdrawSuccessData }, + Timeout { data: LnUrlWithdrawSuccessData }, ErrorStatus { data: LnUrlErrorData }, } diff --git a/libs/sdk-core/src/bridge_generated.rs b/libs/sdk-core/src/bridge_generated.rs index 7da92a893..00e16775a 100644 --- a/libs/sdk-core/src/bridge_generated.rs +++ b/libs/sdk-core/src/bridge_generated.rs @@ -1089,6 +1089,9 @@ const _: fn() = || { LnUrlWithdrawResult::Ok { data } => { let _: LnUrlWithdrawSuccessData = data; } + LnUrlWithdrawResult::Timeout { data } => { + let _: LnUrlWithdrawSuccessData = data; + } LnUrlWithdrawResult::ErrorStatus { data } => { let _: LnUrlErrorData = data; } @@ -1841,9 +1844,12 @@ impl support::IntoDart for mirror_LnUrlWithdrawResult { LnUrlWithdrawResult::Ok { data } => { vec![0.into_dart(), data.into_into_dart().into_dart()] } - LnUrlWithdrawResult::ErrorStatus { data } => { + LnUrlWithdrawResult::Timeout { data } => { vec![1.into_dart(), data.into_into_dart().into_dart()] } + LnUrlWithdrawResult::ErrorStatus { data } => { + vec![2.into_dart(), data.into_into_dart().into_dart()] + } } .into_dart() } diff --git a/libs/sdk-flutter/lib/bridge_generated.dart b/libs/sdk-flutter/lib/bridge_generated.dart index 625db9251..014501e95 100644 --- a/libs/sdk-flutter/lib/bridge_generated.dart +++ b/libs/sdk-flutter/lib/bridge_generated.dart @@ -933,6 +933,9 @@ sealed class LnUrlWithdrawResult with _$LnUrlWithdrawResult { const factory LnUrlWithdrawResult.ok({ required LnUrlWithdrawSuccessData data, }) = LnUrlWithdrawResult_Ok; + const factory LnUrlWithdrawResult.timeout({ + required LnUrlWithdrawSuccessData data, + }) = LnUrlWithdrawResult_Timeout; const factory LnUrlWithdrawResult.errorStatus({ required LnUrlErrorData data, }) = LnUrlWithdrawResult_ErrorStatus; @@ -3593,6 +3596,10 @@ class BreezSdkCoreImpl implements BreezSdkCore { data: _wire2api_box_autoadd_ln_url_withdraw_success_data(raw[1]), ); case 1: + return LnUrlWithdrawResult_Timeout( + data: _wire2api_box_autoadd_ln_url_withdraw_success_data(raw[1]), + ); + case 2: return LnUrlWithdrawResult_ErrorStatus( data: _wire2api_box_autoadd_ln_url_error_data(raw[1]), ); diff --git a/libs/sdk-flutter/lib/bridge_generated.freezed.dart b/libs/sdk-flutter/lib/bridge_generated.freezed.dart index 6c2272a2b..03be1dbae 100644 --- a/libs/sdk-flutter/lib/bridge_generated.freezed.dart +++ b/libs/sdk-flutter/lib/bridge_generated.freezed.dart @@ -4163,18 +4163,21 @@ mixin _$LnUrlWithdrawResult { @optionalTypeArgs TResult when({ required TResult Function(LnUrlWithdrawSuccessData data) ok, + required TResult Function(LnUrlWithdrawSuccessData data) timeout, required TResult Function(LnUrlErrorData data) errorStatus, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ TResult? Function(LnUrlWithdrawSuccessData data)? ok, + TResult? Function(LnUrlWithdrawSuccessData data)? timeout, TResult? Function(LnUrlErrorData data)? errorStatus, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ TResult Function(LnUrlWithdrawSuccessData data)? ok, + TResult Function(LnUrlWithdrawSuccessData data)? timeout, TResult Function(LnUrlErrorData data)? errorStatus, required TResult orElse(), }) => @@ -4182,18 +4185,21 @@ mixin _$LnUrlWithdrawResult { @optionalTypeArgs TResult map({ required TResult Function(LnUrlWithdrawResult_Ok value) ok, + required TResult Function(LnUrlWithdrawResult_Timeout value) timeout, required TResult Function(LnUrlWithdrawResult_ErrorStatus value) errorStatus, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? mapOrNull({ TResult? Function(LnUrlWithdrawResult_Ok value)? ok, + TResult? Function(LnUrlWithdrawResult_Timeout value)? timeout, TResult? Function(LnUrlWithdrawResult_ErrorStatus value)? errorStatus, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeMap({ TResult Function(LnUrlWithdrawResult_Ok value)? ok, + TResult Function(LnUrlWithdrawResult_Timeout value)? timeout, TResult Function(LnUrlWithdrawResult_ErrorStatus value)? errorStatus, required TResult orElse(), }) => @@ -4282,6 +4288,7 @@ class _$LnUrlWithdrawResult_OkImpl implements LnUrlWithdrawResult_Ok { @optionalTypeArgs TResult when({ required TResult Function(LnUrlWithdrawSuccessData data) ok, + required TResult Function(LnUrlWithdrawSuccessData data) timeout, required TResult Function(LnUrlErrorData data) errorStatus, }) { return ok(data); @@ -4291,6 +4298,7 @@ class _$LnUrlWithdrawResult_OkImpl implements LnUrlWithdrawResult_Ok { @optionalTypeArgs TResult? whenOrNull({ TResult? Function(LnUrlWithdrawSuccessData data)? ok, + TResult? Function(LnUrlWithdrawSuccessData data)? timeout, TResult? Function(LnUrlErrorData data)? errorStatus, }) { return ok?.call(data); @@ -4300,6 +4308,7 @@ class _$LnUrlWithdrawResult_OkImpl implements LnUrlWithdrawResult_Ok { @optionalTypeArgs TResult maybeWhen({ TResult Function(LnUrlWithdrawSuccessData data)? ok, + TResult Function(LnUrlWithdrawSuccessData data)? timeout, TResult Function(LnUrlErrorData data)? errorStatus, required TResult orElse(), }) { @@ -4313,6 +4322,7 @@ class _$LnUrlWithdrawResult_OkImpl implements LnUrlWithdrawResult_Ok { @optionalTypeArgs TResult map({ required TResult Function(LnUrlWithdrawResult_Ok value) ok, + required TResult Function(LnUrlWithdrawResult_Timeout value) timeout, required TResult Function(LnUrlWithdrawResult_ErrorStatus value) errorStatus, }) { return ok(this); @@ -4322,6 +4332,7 @@ class _$LnUrlWithdrawResult_OkImpl implements LnUrlWithdrawResult_Ok { @optionalTypeArgs TResult? mapOrNull({ TResult? Function(LnUrlWithdrawResult_Ok value)? ok, + TResult? Function(LnUrlWithdrawResult_Timeout value)? timeout, TResult? Function(LnUrlWithdrawResult_ErrorStatus value)? errorStatus, }) { return ok?.call(this); @@ -4331,6 +4342,7 @@ class _$LnUrlWithdrawResult_OkImpl implements LnUrlWithdrawResult_Ok { @optionalTypeArgs TResult maybeMap({ TResult Function(LnUrlWithdrawResult_Ok value)? ok, + TResult Function(LnUrlWithdrawResult_Timeout value)? timeout, TResult Function(LnUrlWithdrawResult_ErrorStatus value)? errorStatus, required TResult orElse(), }) { @@ -4352,6 +4364,147 @@ abstract class LnUrlWithdrawResult_Ok implements LnUrlWithdrawResult { throw _privateConstructorUsedError; } +/// @nodoc +abstract class _$$LnUrlWithdrawResult_TimeoutImplCopyWith<$Res> { + factory _$$LnUrlWithdrawResult_TimeoutImplCopyWith( + _$LnUrlWithdrawResult_TimeoutImpl value, $Res Function(_$LnUrlWithdrawResult_TimeoutImpl) then) = + __$$LnUrlWithdrawResult_TimeoutImplCopyWithImpl<$Res>; + @useResult + $Res call({LnUrlWithdrawSuccessData data}); +} + +/// @nodoc +class __$$LnUrlWithdrawResult_TimeoutImplCopyWithImpl<$Res> + extends _$LnUrlWithdrawResultCopyWithImpl<$Res, _$LnUrlWithdrawResult_TimeoutImpl> + implements _$$LnUrlWithdrawResult_TimeoutImplCopyWith<$Res> { + __$$LnUrlWithdrawResult_TimeoutImplCopyWithImpl( + _$LnUrlWithdrawResult_TimeoutImpl _value, $Res Function(_$LnUrlWithdrawResult_TimeoutImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? data = null, + }) { + return _then(_$LnUrlWithdrawResult_TimeoutImpl( + data: null == data + ? _value.data + : data // ignore: cast_nullable_to_non_nullable + as LnUrlWithdrawSuccessData, + )); + } +} + +/// @nodoc + +class _$LnUrlWithdrawResult_TimeoutImpl implements LnUrlWithdrawResult_Timeout { + const _$LnUrlWithdrawResult_TimeoutImpl({required this.data}); + + @override + final LnUrlWithdrawSuccessData data; + + @override + String toString() { + return 'LnUrlWithdrawResult.timeout(data: $data)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LnUrlWithdrawResult_TimeoutImpl && + (identical(other.data, data) || other.data == data)); + } + + @override + int get hashCode => Object.hash(runtimeType, data); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LnUrlWithdrawResult_TimeoutImplCopyWith<_$LnUrlWithdrawResult_TimeoutImpl> get copyWith => + __$$LnUrlWithdrawResult_TimeoutImplCopyWithImpl<_$LnUrlWithdrawResult_TimeoutImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(LnUrlWithdrawSuccessData data) ok, + required TResult Function(LnUrlWithdrawSuccessData data) timeout, + required TResult Function(LnUrlErrorData data) errorStatus, + }) { + return timeout(data); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(LnUrlWithdrawSuccessData data)? ok, + TResult? Function(LnUrlWithdrawSuccessData data)? timeout, + TResult? Function(LnUrlErrorData data)? errorStatus, + }) { + return timeout?.call(data); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(LnUrlWithdrawSuccessData data)? ok, + TResult Function(LnUrlWithdrawSuccessData data)? timeout, + TResult Function(LnUrlErrorData data)? errorStatus, + required TResult orElse(), + }) { + if (timeout != null) { + return timeout(data); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(LnUrlWithdrawResult_Ok value) ok, + required TResult Function(LnUrlWithdrawResult_Timeout value) timeout, + required TResult Function(LnUrlWithdrawResult_ErrorStatus value) errorStatus, + }) { + return timeout(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(LnUrlWithdrawResult_Ok value)? ok, + TResult? Function(LnUrlWithdrawResult_Timeout value)? timeout, + TResult? Function(LnUrlWithdrawResult_ErrorStatus value)? errorStatus, + }) { + return timeout?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(LnUrlWithdrawResult_Ok value)? ok, + TResult Function(LnUrlWithdrawResult_Timeout value)? timeout, + TResult Function(LnUrlWithdrawResult_ErrorStatus value)? errorStatus, + required TResult orElse(), + }) { + if (timeout != null) { + return timeout(this); + } + return orElse(); + } +} + +abstract class LnUrlWithdrawResult_Timeout implements LnUrlWithdrawResult { + const factory LnUrlWithdrawResult_Timeout({required final LnUrlWithdrawSuccessData data}) = + _$LnUrlWithdrawResult_TimeoutImpl; + + @override + LnUrlWithdrawSuccessData get data; + @JsonKey(ignore: true) + _$$LnUrlWithdrawResult_TimeoutImplCopyWith<_$LnUrlWithdrawResult_TimeoutImpl> get copyWith => + throw _privateConstructorUsedError; +} + /// @nodoc abstract class _$$LnUrlWithdrawResult_ErrorStatusImplCopyWith<$Res> { factory _$$LnUrlWithdrawResult_ErrorStatusImplCopyWith(_$LnUrlWithdrawResult_ErrorStatusImpl value, @@ -4418,6 +4571,7 @@ class _$LnUrlWithdrawResult_ErrorStatusImpl implements LnUrlWithdrawResult_Error @optionalTypeArgs TResult when({ required TResult Function(LnUrlWithdrawSuccessData data) ok, + required TResult Function(LnUrlWithdrawSuccessData data) timeout, required TResult Function(LnUrlErrorData data) errorStatus, }) { return errorStatus(data); @@ -4427,6 +4581,7 @@ class _$LnUrlWithdrawResult_ErrorStatusImpl implements LnUrlWithdrawResult_Error @optionalTypeArgs TResult? whenOrNull({ TResult? Function(LnUrlWithdrawSuccessData data)? ok, + TResult? Function(LnUrlWithdrawSuccessData data)? timeout, TResult? Function(LnUrlErrorData data)? errorStatus, }) { return errorStatus?.call(data); @@ -4436,6 +4591,7 @@ class _$LnUrlWithdrawResult_ErrorStatusImpl implements LnUrlWithdrawResult_Error @optionalTypeArgs TResult maybeWhen({ TResult Function(LnUrlWithdrawSuccessData data)? ok, + TResult Function(LnUrlWithdrawSuccessData data)? timeout, TResult Function(LnUrlErrorData data)? errorStatus, required TResult orElse(), }) { @@ -4449,6 +4605,7 @@ class _$LnUrlWithdrawResult_ErrorStatusImpl implements LnUrlWithdrawResult_Error @optionalTypeArgs TResult map({ required TResult Function(LnUrlWithdrawResult_Ok value) ok, + required TResult Function(LnUrlWithdrawResult_Timeout value) timeout, required TResult Function(LnUrlWithdrawResult_ErrorStatus value) errorStatus, }) { return errorStatus(this); @@ -4458,6 +4615,7 @@ class _$LnUrlWithdrawResult_ErrorStatusImpl implements LnUrlWithdrawResult_Error @optionalTypeArgs TResult? mapOrNull({ TResult? Function(LnUrlWithdrawResult_Ok value)? ok, + TResult? Function(LnUrlWithdrawResult_Timeout value)? timeout, TResult? Function(LnUrlWithdrawResult_ErrorStatus value)? errorStatus, }) { return errorStatus?.call(this); @@ -4467,6 +4625,7 @@ class _$LnUrlWithdrawResult_ErrorStatusImpl implements LnUrlWithdrawResult_Error @optionalTypeArgs TResult maybeMap({ TResult Function(LnUrlWithdrawResult_Ok value)? ok, + TResult Function(LnUrlWithdrawResult_Timeout value)? timeout, TResult Function(LnUrlWithdrawResult_ErrorStatus value)? errorStatus, required TResult orElse(), }) { diff --git a/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt b/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt index 29998c9c5..1355a31e1 100644 --- a/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt +++ b/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt @@ -4104,6 +4104,9 @@ fun asLnUrlWithdrawResult(lnUrlWithdrawResult: ReadableMap): LnUrlWithdrawResult if (type == "ok") { return LnUrlWithdrawResult.Ok(lnUrlWithdrawResult.getMap("data")?.let { asLnUrlWithdrawSuccessData(it) }!!) } + if (type == "timeout") { + return LnUrlWithdrawResult.Timeout(lnUrlWithdrawResult.getMap("data")?.let { asLnUrlWithdrawSuccessData(it) }!!) + } if (type == "errorStatus") { return LnUrlWithdrawResult.ErrorStatus(lnUrlWithdrawResult.getMap("data")?.let { asLnUrlErrorData(it) }!!) } @@ -4117,6 +4120,10 @@ fun readableMapOf(lnUrlWithdrawResult: LnUrlWithdrawResult): ReadableMap? { pushToMap(map, "type", "ok") pushToMap(map, "data", readableMapOf(lnUrlWithdrawResult.data)) } + is LnUrlWithdrawResult.Timeout -> { + pushToMap(map, "type", "timeout") + pushToMap(map, "data", readableMapOf(lnUrlWithdrawResult.data)) + } is LnUrlWithdrawResult.ErrorStatus -> { pushToMap(map, "type", "errorStatus") pushToMap(map, "data", readableMapOf(lnUrlWithdrawResult.data)) diff --git a/libs/sdk-react-native/ios/BreezSDKMapper.swift b/libs/sdk-react-native/ios/BreezSDKMapper.swift index ab3f5b49b..5ae9ded78 100644 --- a/libs/sdk-react-native/ios/BreezSDKMapper.swift +++ b/libs/sdk-react-native/ios/BreezSDKMapper.swift @@ -4931,6 +4931,14 @@ enum BreezSDKMapper { return LnUrlWithdrawResult.ok(data: _data) } + if type == "timeout" { + guard let dataTmp = lnUrlWithdrawResult["data"] as? [String: Any?] else { + throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "data", typeName: "LnUrlWithdrawResult")) + } + let _data = try asLnUrlWithdrawSuccessData(lnUrlWithdrawSuccessData: dataTmp) + + return LnUrlWithdrawResult.timeout(data: _data) + } if type == "errorStatus" { guard let dataTmp = lnUrlWithdrawResult["data"] as? [String: Any?] else { throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "data", typeName: "LnUrlWithdrawResult")) @@ -4953,6 +4961,14 @@ enum BreezSDKMapper { "data": dictionaryOf(lnUrlWithdrawSuccessData: data), ] + case let .timeout( + data + ): + return [ + "type": "timeout", + "data": dictionaryOf(lnUrlWithdrawSuccessData: data), + ] + case let .errorStatus( data ): diff --git a/libs/sdk-react-native/src/index.ts b/libs/sdk-react-native/src/index.ts index 38b198898..d36f32cf3 100644 --- a/libs/sdk-react-native/src/index.ts +++ b/libs/sdk-react-native/src/index.ts @@ -728,12 +728,16 @@ export type LnUrlPayResult = { export enum LnUrlWithdrawResultVariant { OK = "ok", + TIMEOUT = "timeout", ERROR_STATUS = "errorStatus" } export type LnUrlWithdrawResult = { type: LnUrlWithdrawResultVariant.OK, data: LnUrlWithdrawSuccessData +} | { + type: LnUrlWithdrawResultVariant.TIMEOUT, + data: LnUrlWithdrawSuccessData } | { type: LnUrlWithdrawResultVariant.ERROR_STATUS, data: LnUrlErrorData From 9c40a62e88b5053e4d2b70d25182a35c5da071af Mon Sep 17 00:00:00 2001 From: Andrei Date: Tue, 2 Jul 2024 00:00:00 +0000 Subject: [PATCH 3/3] Propagate reqwest error code --- libs/sdk-common/src/breez_server.rs | 24 +++++----- libs/sdk-common/src/error.rs | 49 ++++++++++++++++++--- libs/sdk-common/src/lnurl/specs/withdraw.rs | 6 ++- libs/sdk-common/src/utils/rest_client.rs | 14 +++--- 4 files changed, 71 insertions(+), 22 deletions(-) diff --git a/libs/sdk-common/src/breez_server.rs b/libs/sdk-common/src/breez_server.rs index 5702a1ff1..cc7ca0b4f 100644 --- a/libs/sdk-common/src/breez_server.rs +++ b/libs/sdk-common/src/breez_server.rs @@ -14,7 +14,7 @@ use crate::grpc::signer_client::SignerClient; use crate::grpc::support_client::SupportClient; use crate::grpc::swapper_client::SwapperClient; use crate::grpc::{ChainApiServersRequest, PingRequest}; -use crate::prelude::ServiceConnectivityError; +use crate::prelude::{ServiceConnectivityError, ServiceConnectivityErrorKind}; pub static PRODUCTION_BREEZSERVER_URL: &str = "https://bs1.breez.technology:443"; pub static STAGING_BREEZSERVER_URL: &str = "https://bs1-st.breez.technology:443"; @@ -36,10 +36,10 @@ impl BreezServer { match &self.api_key { Some(key) => Ok(Some(format!("Bearer {key}").parse().map_err( |e: InvalidMetadataValue| { - ServiceConnectivityError::new(&format!( - "(Breez: {:?}) Failed parse API key: {e}", - self.api_key - )) + ServiceConnectivityError::new( + ServiceConnectivityErrorKind::Other, + format!("(Breez: {:?}) Failed parse API key: {e}", self.api_key), + ) }, )?)), _ => Ok(None), @@ -108,9 +108,10 @@ impl BreezServer { .chain_api_servers(ChainApiServersRequest {}) .await .map_err(|e| { - ServiceConnectivityError::new(&format!( - "(Breez: {e:?}) Failed to fetch ChainApiServers" - )) + ServiceConnectivityError::new( + ServiceConnectivityErrorKind::Other, + format!("(Breez: {e:?}) Failed to fetch ChainApiServers"), + ) })? .into_inner() .servers; @@ -133,9 +134,10 @@ impl BreezServer { .chain_api_servers(ChainApiServersRequest {}) .await .map_err(|e| { - ServiceConnectivityError::new(&format!( - "(Breez: {e:?}) Failed to fetch ChainApiServers" - )) + ServiceConnectivityError::new( + ServiceConnectivityErrorKind::Other, + format!("(Breez: {e:?}) Failed to fetch ChainApiServers"), + ) })? .into_inner() .servers; diff --git a/libs/sdk-common/src/error.rs b/libs/sdk-common/src/error.rs index 24bfcfb56..8ec8bce87 100644 --- a/libs/sdk-common/src/error.rs +++ b/libs/sdk-common/src/error.rs @@ -1,20 +1,59 @@ +use std::fmt; use thiserror::Error; +#[derive(Debug)] +pub enum ServiceConnectivityErrorKind { + Builder, + Redirect, + Status, + Timeout, + Request, + Connect, + Body, + Decode, + Json, + Other, +} +impl fmt::Display for ServiceConnectivityErrorKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self:?}") + } +} + #[derive(Debug, Error)] -#[error("{err}")] +#[error("{kind}: {err}")] pub struct ServiceConnectivityError { + pub kind: ServiceConnectivityErrorKind, pub err: String, } impl ServiceConnectivityError { - pub fn new(err: &str) -> Self { - ServiceConnectivityError { - err: err.to_string(), - } + pub fn new(kind: ServiceConnectivityErrorKind, err: String) -> Self { + ServiceConnectivityError { kind, err } } } impl From for ServiceConnectivityError { fn from(err: reqwest::Error) -> Self { + let kind = if err.is_builder() { + ServiceConnectivityErrorKind::Builder + } else if err.is_redirect() { + ServiceConnectivityErrorKind::Redirect + } else if err.is_status() { + ServiceConnectivityErrorKind::Status + } else if err.is_timeout() { + ServiceConnectivityErrorKind::Timeout + } else if err.is_request() { + ServiceConnectivityErrorKind::Request + } else if err.is_connect() { + ServiceConnectivityErrorKind::Connect + } else if err.is_body() { + ServiceConnectivityErrorKind::Body + } else if err.is_decode() { + ServiceConnectivityErrorKind::Decode + } else { + ServiceConnectivityErrorKind::Other + }; Self { + kind, err: err.to_string(), } } diff --git a/libs/sdk-common/src/lnurl/specs/withdraw.rs b/libs/sdk-common/src/lnurl/specs/withdraw.rs index 6c61cd86e..5a157294f 100644 --- a/libs/sdk-common/src/lnurl/specs/withdraw.rs +++ b/libs/sdk-common/src/lnurl/specs/withdraw.rs @@ -1,5 +1,6 @@ use std::str::FromStr; +use crate::error::{ServiceConnectivityError, ServiceConnectivityErrorKind}; use crate::prelude::*; /// Validates invoice and performs the second and last step of LNURL-withdraw, as per @@ -38,7 +39,10 @@ pub async fn validate_lnurl_withdraw( data: LnUrlWithdrawSuccessData { invoice }, }, Ok(LnUrlCallbackStatus::ErrorStatus { data }) => LnUrlWithdrawResult::ErrorStatus { data }, - Err(e) if e.to_string().contains("operation timed out") => LnUrlWithdrawResult::Timeout { + Err(ServiceConnectivityError { + kind: ServiceConnectivityErrorKind::Timeout, + err: _, + }) => LnUrlWithdrawResult::Timeout { data: LnUrlWithdrawSuccessData { invoice }, }, Err(e) => return Err(LnUrlError::ServiceConnectivity(e.to_string())), diff --git a/libs/sdk-common/src/utils/rest_client.rs b/libs/sdk-common/src/utils/rest_client.rs index ddf9d54cf..8e60283ba 100644 --- a/libs/sdk-common/src/utils/rest_client.rs +++ b/libs/sdk-common/src/utils/rest_client.rs @@ -1,9 +1,8 @@ -use std::time::Duration; - use log::*; use reqwest::StatusCode; +use std::time::Duration; -use crate::error::ServiceConnectivityError; +use crate::error::{ServiceConnectivityError, ServiceConnectivityErrorKind}; /// Creates an HTTP client with a built-in connection timeout pub fn get_reqwest_client() -> Result { @@ -66,8 +65,13 @@ where if enforce_status_check && !status.is_success() { let err = format!("GET request {url} failed with status: {status}"); error!("{err}"); - return Err(ServiceConnectivityError::new(&err)); + return Err(ServiceConnectivityError::new( + ServiceConnectivityErrorKind::Status, + err, + )); } - serde_json::from_str::(&raw_body).map_err(|e| ServiceConnectivityError::new(&e.to_string())) + serde_json::from_str::(&raw_body).map_err(|e| { + ServiceConnectivityError::new(ServiceConnectivityErrorKind::Json, e.to_string()) + }) }