replace transports: Option<Vec<Transport>> with just Vec<Transport> (#999)

with a few serde directive we can get the same behaviour we had with
Option<Vec<Transport>> but only using Vec<Transport>

No need to change protocol specification
This commit is contained in:
codingpeanut157
2025-08-27 16:21:22 +02:00
committed by GitHub
parent 44cef59fe5
commit 971957b839
3 changed files with 21 additions and 29 deletions

View File

@@ -3,7 +3,6 @@
//! <https://github.com/cashubtc/nuts/blob/main/18.md>
use std::fmt;
use std::ops::Not;
use std::str::FromStr;
use bitcoin::base64::engine::{general_purpose, GeneralPurpose};
@@ -40,8 +39,8 @@ pub struct PaymentRequest {
pub description: Option<String>,
/// Transport
#[serde(rename = "t")]
#[serde(skip_serializing_if = "Option::is_none")]
pub transports: Option<Vec<Transport>>,
#[serde(skip_serializing_if = "Vec::is_empty", default = "Vec::default")]
pub transports: Vec<Transport>,
/// Nut10
#[serde(skip_serializing_if = "Option::is_none")]
pub nut10: Option<Nut10SecretRequest>,
@@ -168,8 +167,6 @@ impl PaymentRequestBuilder {
/// Build the PaymentRequest
pub fn build(self) -> PaymentRequest {
let transports = self.transports.is_empty().not().then_some(self.transports);
PaymentRequest {
payment_id: self.payment_id,
amount: self.amount,
@@ -177,7 +174,7 @@ impl PaymentRequestBuilder {
single_use: self.single_use,
mints: self.mints,
description: self.description,
transports,
transports: self.transports,
nut10: self.nut10,
}
}
@@ -224,8 +221,7 @@ mod tests {
);
assert_eq!(req.unit.unwrap(), CurrencyUnit::Sat);
let transport = req.transports.unwrap();
let transport = transport.first().unwrap();
let transport = req.transports.first().unwrap();
let expected_transport = Transport {_type: TransportType::Nostr, target: "nprofile1qy28wumn8ghj7un9d3shjtnyv9kh2uewd9hsz9mhwden5te0wfjkccte9curxven9eehqctrv5hszrthwden5te0dehhxtnvdakqqgydaqy7curk439ykptkysv7udhdhu68sucm295akqefdehkf0d495cwunl5".to_string(), tags: Some(vec![vec!["n".to_string(), "17".to_string()]])};
@@ -245,7 +241,7 @@ mod tests {
.parse()
.expect("valid mint url")]),
description: None,
transports: Some(vec![transport.clone()]),
transports: vec![transport.clone()],
nut10: None,
};
@@ -262,8 +258,7 @@ mod tests {
);
assert_eq!(req.unit.unwrap(), CurrencyUnit::Sat);
let t = req.transports.unwrap();
let t = t.first().unwrap();
let t = req.transports.first().unwrap();
assert_eq!(&transport, t);
}
@@ -293,8 +288,7 @@ mod tests {
assert_eq!(request.unit.clone().unwrap(), CurrencyUnit::Sat);
assert_eq!(request.mints.clone().unwrap(), vec![mint_url]);
let t = request.transports.clone().unwrap();
let t = t.first().unwrap();
let t = request.transports.first().clone().unwrap();
assert_eq!(&transport, t);
// Test serialization and deserialization
@@ -497,8 +491,7 @@ mod tests {
vec![MintUrl::from_str("https://8333.space:3338").unwrap()]
);
let transport = payment_request.transports.as_ref().unwrap();
let transport = transport.first().unwrap();
let transport = payment_request.transports.first().unwrap();
assert_eq!(transport._type, TransportType::Nostr);
assert_eq!(transport.target, "nprofile1qy28wumn8ghj7un9d3shjtnyv9kh2uewd9hsz9mhwden5te0wfjkccte9curxven9eehqctrv5hszrthwden5te0dehhxtnvdakqqgydaqy7curk439ykptkysv7udhdhu68sucm295akqefdehkf0d495cwunl5");
assert_eq!(
@@ -562,8 +555,7 @@ mod tests {
]
);
let transport = payment_request_cloned.transports.unwrap();
let transport = transport.first().unwrap();
let transport = payment_request_cloned.transports.first().unwrap();
assert_eq!(transport._type, TransportType::Nostr);
assert_eq!(
transport.target,
@@ -614,7 +606,7 @@ mod tests {
payment_request_cloned.mints.unwrap(),
vec![MintUrl::from_str("https://mint.example.com").unwrap()]
);
assert_eq!(payment_request_cloned.transports, None);
assert_eq!(payment_request_cloned.transports, vec![]);
// Test round-trip serialization
let encoded = payment_request.to_string();

View File

@@ -100,7 +100,7 @@ pub async fn create_request(
// We'll need the Nostr keys and relays later for listening
let transport_info = Some((keys, relays, nprofile.public_key));
(Some(vec![nostr_transport]), transport_info)
(vec![nostr_transport], transport_info)
}
"http" => {
if let Some(url) = &sub_command_args.http_url {
@@ -110,18 +110,18 @@ pub async fn create_request(
tags: None,
};
(Some(vec![http_transport]), None)
(vec![http_transport], None)
} else {
println!(
"Warning: HTTP transport selected but no URL provided, skipping transport"
);
(None, None)
(vec![], None)
}
}
"none" => (None, None),
"none" => (vec![], None),
_ => {
println!("Warning: Unknown transport type '{transport_type}', defaulting to none");
(None, None)
(vec![], None)
}
};
@@ -234,7 +234,7 @@ pub async fn create_request(
let nut10 = spending_conditions.map(Nut10SecretRequest::from);
// Extract the transports option from our match result
let (transports_option, nostr_info) = transports;
let (transports, nostr_info) = transports;
let req = PaymentRequest {
payment_id: None,
@@ -243,7 +243,7 @@ pub async fn create_request(
single_use: Some(true),
mints: Some(mints),
description: sub_command_args.description.clone(),
transports: transports_option,
transports,
nut10,
};

View File

@@ -67,10 +67,10 @@ pub async fn pay_request(
let matching_wallet = matching_wallets.first().unwrap();
let transports = payment_request
.transports
.clone()
.ok_or(anyhow!("Cannot pay request without transport"))?;
if payment_request.transports.is_empty() {
return Err(anyhow!("Cannot pay request without transport"));
}
let transports = payment_request.transports.clone();
// We prefer nostr transport if it is available to hide ip.
let transport = transports