Skip to content

Commit 2041f54

Browse files
committed
Refactor send::WellKnownError to use ErrorCode
The types are directly related and the send/receive separation is no longer part of our feature distinctions so it makes sense to combine them.
1 parent 28f41b3 commit 2041f54

File tree

2 files changed

+46
-52
lines changed

2 files changed

+46
-52
lines changed

payjoin/src/send/error.rs

Lines changed: 41 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -266,46 +266,38 @@ pub enum ResponseError {
266266
}
267267

268268
impl ResponseError {
269-
fn from_json(json: serde_json::Value) -> Self {
270-
// we try to find the errorCode field and
271-
// if it exists we try to parse it as a well known error
272-
// if its an unknown error we return the error code and message
273-
// from original response
274-
// if errorCode field doesn't exist we return parse error
269+
pub(crate) fn from_json(json: serde_json::Value) -> Self {
275270
let message = json
276271
.as_object()
277272
.and_then(|v| v.get("message"))
278273
.and_then(|v| v.as_str())
279274
.unwrap_or_default()
280275
.to_string();
281-
if let Some(error_code) =
282-
json.as_object().and_then(|v| v.get("errorCode")).and_then(|v| v.as_str())
283-
{
284-
match ErrorCode::from_str(error_code) {
276+
277+
let error_code = json.as_object().and_then(|v| v.get("errorCode")).and_then(|v| v.as_str());
278+
279+
match error_code {
280+
Some(code) => match ErrorCode::from_str(code) {
285281
Ok(ErrorCode::VersionUnsupported) => {
286282
let supported = json
287283
.as_object()
288284
.and_then(|v| v.get("supported"))
289285
.and_then(|v| v.as_array())
290286
.map(|array| array.iter().filter_map(|v| v.as_u64()).collect::<Vec<u64>>())
291287
.unwrap_or_default();
292-
WellKnownError::VersionUnsupported { message, supported }.into()
288+
WellKnownError::version_unsupported(message, supported).into()
293289
}
294-
Ok(ErrorCode::Unavailable) => WellKnownError::Unavailable(message).into(),
295-
Ok(ErrorCode::NotEnoughMoney) => WellKnownError::NotEnoughMoney(message).into(),
296-
Ok(ErrorCode::OriginalPsbtRejected) =>
297-
WellKnownError::OriginalPsbtRejected(message).into(),
298-
_ => Self::Unrecognized { error_code: error_code.to_string(), message },
299-
}
300-
} else {
301-
InternalValidationError::Parse.into()
290+
Ok(code) => WellKnownError::new(code, message).into(),
291+
Err(_) => Self::Unrecognized { error_code: code.to_string(), message },
292+
},
293+
None => InternalValidationError::Parse.into(),
302294
}
303295
}
304296

305297
/// Parse a response from the receiver.
306298
///
307299
/// response must be valid JSON string.
308-
pub fn parse(response: &str) -> Self {
300+
pub(crate) fn parse(response: &str) -> Self {
309301
match serde_json::from_str(response) {
310302
Ok(json) => Self::from_json(json),
311303
Err(_) => InternalValidationError::Parse.into(),
@@ -346,8 +338,8 @@ impl fmt::Debug for ResponseError {
346338
match self {
347339
Self::WellKnown(e) => {
348340
let json = serde_json::json!({
349-
"errorCode": e.error_code().to_string(),
350-
"message": e.message()
341+
"errorCode": e.code.to_string(),
342+
"message": e.message
351343
});
352344
write!(f, "Well known error: {}", json)
353345
}
@@ -364,41 +356,39 @@ impl fmt::Debug for ResponseError {
364356
}
365357
}
366358

359+
/// A well-known error that can be safely displayed to end users.
367360
#[derive(Debug, Clone, PartialEq, Eq)]
368-
#[non_exhaustive]
369-
pub enum WellKnownError {
370-
Unavailable(String),
371-
NotEnoughMoney(String),
372-
VersionUnsupported { message: String, supported: Vec<u64> },
373-
OriginalPsbtRejected(String),
361+
pub struct WellKnownError {
362+
pub(crate) code: ErrorCode,
363+
pub(crate) message: String,
364+
pub(crate) supported_versions: Option<Vec<u64>>,
374365
}
375366

376367
impl WellKnownError {
377-
pub fn error_code(&self) -> ErrorCode {
378-
match self {
379-
WellKnownError::Unavailable(_) => ErrorCode::Unavailable,
380-
WellKnownError::NotEnoughMoney(_) => ErrorCode::NotEnoughMoney,
381-
WellKnownError::VersionUnsupported { .. } => ErrorCode::VersionUnsupported,
382-
WellKnownError::OriginalPsbtRejected(_) => ErrorCode::OriginalPsbtRejected,
383-
}
368+
/// Create a new well-known error with the given code and message.
369+
pub(crate) fn new(code: ErrorCode, message: String) -> Self {
370+
Self { code, message, supported_versions: None }
384371
}
385-
pub fn message(&self) -> &str {
386-
match self {
387-
WellKnownError::Unavailable(m) => m,
388-
WellKnownError::NotEnoughMoney(m) => m,
389-
WellKnownError::VersionUnsupported { message: m, .. } => m,
390-
WellKnownError::OriginalPsbtRejected(m) => m,
391-
}
372+
373+
/// Create a version unsupported error with the given message and supported versions.
374+
pub(crate) fn version_unsupported(message: String, supported: Vec<u64>) -> Self {
375+
Self { code: ErrorCode::VersionUnsupported, message, supported_versions: Some(supported) }
392376
}
393377
}
394378

395-
impl Display for WellKnownError {
396-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
397-
match self {
398-
Self::Unavailable(_) => write!(f, "The payjoin endpoint is not available for now."),
399-
Self::NotEnoughMoney(_) => write!(f, "The receiver added some inputs but could not bump the fee of the payjoin proposal."),
400-
Self::VersionUnsupported { supported: v, .. }=> write!(f, "This version of payjoin is not supported. Use version {:?}.", v),
401-
Self::OriginalPsbtRejected(_) => write!(f, "The receiver rejected the original PSBT."),
379+
impl core::fmt::Display for WellKnownError {
380+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
381+
match self.code {
382+
ErrorCode::Unavailable => write!(f, "The payjoin endpoint is not available for now."),
383+
ErrorCode::NotEnoughMoney => write!(f, "The receiver added some inputs but could not bump the fee of the payjoin proposal."),
384+
ErrorCode::VersionUnsupported => {
385+
if let Some(supported) = &self.supported_versions {
386+
write!(f, "This version of payjoin is not supported. Use version {:?}.", supported)
387+
} else {
388+
write!(f, "This version of payjoin is not supported.")
389+
}
390+
}
391+
ErrorCode::OriginalPsbtRejected => write!(f, "The receiver rejected the original PSBT."),
402392
}
403393
}
404394
}
@@ -414,8 +404,8 @@ mod tests {
414404
let known_str_error = r#"{"errorCode":"version-unsupported", "message":"custom message here", "supported": [1, 2]}"#;
415405
match ResponseError::parse(known_str_error) {
416406
ResponseError::WellKnown(e) => {
417-
assert_eq!(e.error_code(), ErrorCode::VersionUnsupported);
418-
assert_eq!(e.message(), "custom message here");
407+
assert_eq!(e.code, ErrorCode::VersionUnsupported);
408+
assert_eq!(e.message, "custom message here");
419409
assert_eq!(
420410
e.to_string(),
421411
"This version of payjoin is not supported. Use version [1, 2]."

payjoin/src/send/v1.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ mod test {
286286
use payjoin_test_utils::{BoxError, PARSED_ORIGINAL_PSBT};
287287

288288
use super::SenderBuilder;
289+
use crate::error_codes::ErrorCode;
289290
use crate::send::error::{ResponseError, WellKnownError};
290291
use crate::send::test::create_psbt_context;
291292
use crate::{Uri, UriExt};
@@ -322,7 +323,10 @@ mod test {
322323
})
323324
.to_string();
324325
match ctx.process_response(&mut known_json_error.as_bytes()) {
325-
Err(ResponseError::WellKnown(WellKnownError::VersionUnsupported { .. })) => (),
326+
Err(ResponseError::WellKnown(WellKnownError {
327+
code: ErrorCode::VersionUnsupported,
328+
..
329+
})) => (),
326330
_ => panic!("Expected WellKnownError"),
327331
}
328332

0 commit comments

Comments
 (0)