Skip to content

Commit

Permalink
Merge pull request breez#1004 from andrei-21/feature/propagate-timeout
Browse files Browse the repository at this point in the history
Propagate timeout in LNURL withdraw flow
  • Loading branch information
roeierez authored Jul 3, 2024
2 parents 0530d6c + 9c40a62 commit 8c27e8b
Show file tree
Hide file tree
Showing 12 changed files with 280 additions and 28 deletions.
1 change: 1 addition & 0 deletions libs/sdk-bindings/src/breez_sdk.udl
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,7 @@ dictionary LnUrlWithdrawRequest {
[Enum]
interface LnUrlWithdrawResult {
Ok(LnUrlWithdrawSuccessData data);
Timeout(LnUrlWithdrawSuccessData data);
ErrorStatus(LnUrlErrorData data);
};

Expand Down
24 changes: 13 additions & 11 deletions libs/sdk-common/src/breez_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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),
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
49 changes: 44 additions & 5 deletions libs/sdk-common/src/error.rs
Original file line number Diff line number Diff line change
@@ -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<reqwest::Error> 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(),
}
}
Expand Down
18 changes: 12 additions & 6 deletions libs/sdk-common/src/lnurl/specs/withdraw.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -33,14 +34,18 @@ 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(ServiceConnectivityError {
kind: ServiceConnectivityErrorKind::Timeout,
err: _,
}) => LnUrlWithdrawResult::Timeout {
data: LnUrlWithdrawSuccessData { invoice },
},
Err(e) => return Err(LnUrlError::ServiceConnectivity(e.to_string())),
};

Ok(withdraw_status)
Expand Down Expand Up @@ -102,6 +107,7 @@ pub mod model {
#[derive(Clone, Serialize)]
pub enum LnUrlWithdrawResult {
Ok { data: LnUrlWithdrawSuccessData },
Timeout { data: LnUrlWithdrawSuccessData },
ErrorStatus { data: LnUrlErrorData },
}

Expand Down
14 changes: 9 additions & 5 deletions libs/sdk-common/src/utils/rest_client.rs
Original file line number Diff line number Diff line change
@@ -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<reqwest::Client, ServiceConnectivityError> {
Expand Down Expand Up @@ -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::<T>(&raw_body).map_err(|e| ServiceConnectivityError::new(&e.to_string()))
serde_json::from_str::<T>(&raw_body).map_err(|e| {
ServiceConnectivityError::new(ServiceConnectivityErrorKind::Json, e.to_string())
})
}
1 change: 1 addition & 0 deletions libs/sdk-core/src/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ pub enum _LnUrlPayError {
#[frb(mirror(LnUrlWithdrawResult))]
pub enum _LnUrlWithdrawResult {
Ok { data: LnUrlWithdrawSuccessData },
Timeout { data: LnUrlWithdrawSuccessData },
ErrorStatus { data: LnUrlErrorData },
}

Expand Down
8 changes: 7 additions & 1 deletion libs/sdk-core/src/bridge_generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,9 @@ const _: fn() = || {
LnUrlWithdrawResult::Ok { data } => {
let _: LnUrlWithdrawSuccessData = data;
}
LnUrlWithdrawResult::Timeout { data } => {
let _: LnUrlWithdrawSuccessData = data;
}
LnUrlWithdrawResult::ErrorStatus { data } => {
let _: LnUrlErrorData = data;
}
Expand Down Expand Up @@ -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()
}
Expand Down
7 changes: 7 additions & 0 deletions libs/sdk-flutter/lib/bridge_generated.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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]),
);
Expand Down
Loading

0 comments on commit 8c27e8b

Please sign in to comment.