diff --git a/ldk-server-protos/build.rs b/ldk-server-protos/build.rs index 35066fc7..46545695 100644 --- a/ldk-server-protos/build.rs +++ b/ldk-server-protos/build.rs @@ -41,6 +41,30 @@ fn generate_protos() { "#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]", ) .type_attribute(".", "#[cfg_attr(feature = \"serde\", serde(rename_all = \"snake_case\"))]") + .field_attribute( + "types.Bolt11.secret", + "#[cfg_attr(feature = \"serde\", serde(serialize_with = \"crate::serde_utils::serialize_opt_bytes_hex\"))]", + ) + .field_attribute( + "types.Bolt11Jit.secret", + "#[cfg_attr(feature = \"serde\", serde(serialize_with = \"crate::serde_utils::serialize_opt_bytes_hex\"))]", + ) + .field_attribute( + "types.Bolt12Offer.secret", + "#[cfg_attr(feature = \"serde\", serde(serialize_with = \"crate::serde_utils::serialize_opt_bytes_hex\"))]", + ) + .field_attribute( + "types.Bolt12Refund.secret", + "#[cfg_attr(feature = \"serde\", serde(serialize_with = \"crate::serde_utils::serialize_opt_bytes_hex\"))]", + ) + .field_attribute( + "types.Payment.direction", + "#[cfg_attr(feature = \"serde\", serde(serialize_with = \"crate::serde_utils::serialize_payment_direction\"))]", + ) + .field_attribute( + "types.Payment.status", + "#[cfg_attr(feature = \"serde\", serde(serialize_with = \"crate::serde_utils::serialize_payment_status\"))]", + ) .compile_protos( &[ "src/proto/api.proto", diff --git a/ldk-server-protos/src/lib.rs b/ldk-server-protos/src/lib.rs index 24a73525..f76f2f73 100644 --- a/ldk-server-protos/src/lib.rs +++ b/ldk-server-protos/src/lib.rs @@ -11,4 +11,6 @@ pub mod api; pub mod endpoints; pub mod error; pub mod events; +#[cfg(feature = "serde")] +pub mod serde_utils; pub mod types; diff --git a/ldk-server-protos/src/serde_utils.rs b/ldk-server-protos/src/serde_utils.rs new file mode 100644 index 00000000..2a32ec7e --- /dev/null +++ b/ldk-server-protos/src/serde_utils.rs @@ -0,0 +1,57 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +//! Custom serde serializers for proto types. +//! +//! These are used via `#[serde(serialize_with = "...")]` attributes on generated +//! proto fields to produce human-readable output (hex strings for bytes, enum +//! names for integer enum fields). + +use std::fmt::Write; + +use serde::Serializer; + +/// Generates a serde serializer that converts an `i32` proto enum field to its +/// string name via `from_i32()` and `as_str_name()`. +macro_rules! stringify_enum_serializer { + ($fn_name:ident, $enum_type:ty) => { + pub fn $fn_name(value: &i32, serializer: S) -> Result + where + S: serde::Serializer, + { + let name = match <$enum_type>::from_i32(*value) { + Some(v) => v.as_str_name(), + None => "UNKNOWN", + }; + serializer.serialize_str(name) + } + }; +} + +stringify_enum_serializer!(serialize_payment_direction, crate::types::PaymentDirection); +stringify_enum_serializer!(serialize_payment_status, crate::types::PaymentStatus); + +/// Serializes `Option` as a hex string (or null). +pub fn serialize_opt_bytes_hex( + value: &Option, serializer: S, +) -> Result +where + S: Serializer, +{ + match value { + Some(bytes) => { + let hex = bytes.iter().fold(String::with_capacity(bytes.len() * 2), |mut acc, b| { + let _ = write!(acc, "{b:02x}"); + acc + }); + serializer.serialize_some(&hex) + }, + None => serializer.serialize_none(), + } +} diff --git a/ldk-server-protos/src/types.rs b/ldk-server-protos/src/types.rs index 238f4b5d..07098166 100644 --- a/ldk-server-protos/src/types.rs +++ b/ldk-server-protos/src/types.rs @@ -31,9 +31,17 @@ pub struct Payment { pub fee_paid_msat: ::core::option::Option, /// The direction of the payment. #[prost(enumeration = "PaymentDirection", tag = "4")] + #[cfg_attr( + feature = "serde", + serde(serialize_with = "crate::serde_utils::serialize_payment_direction") + )] pub direction: i32, /// The status of the payment. #[prost(enumeration = "PaymentStatus", tag = "5")] + #[cfg_attr( + feature = "serde", + serde(serialize_with = "crate::serde_utils::serialize_payment_status") + )] pub status: i32, /// The timestamp, in seconds since start of the UNIX epoch, when this entry was last updated. #[prost(uint64, tag = "6")] @@ -138,6 +146,10 @@ pub struct Bolt11 { pub preimage: ::core::option::Option<::prost::alloc::string::String>, /// The secret used by the payment. #[prost(bytes = "bytes", optional, tag = "3")] + #[cfg_attr( + feature = "serde", + serde(serialize_with = "crate::serde_utils::serialize_opt_bytes_hex") + )] pub secret: ::core::option::Option<::prost::bytes::Bytes>, } /// Represents a BOLT 11 payment intended to open an LSPS 2 just-in-time channel. @@ -154,6 +166,10 @@ pub struct Bolt11Jit { pub preimage: ::core::option::Option<::prost::alloc::string::String>, /// The secret used by the payment. #[prost(bytes = "bytes", optional, tag = "3")] + #[cfg_attr( + feature = "serde", + serde(serialize_with = "crate::serde_utils::serialize_opt_bytes_hex") + )] pub secret: ::core::option::Option<::prost::bytes::Bytes>, /// Limits applying to how much fee we allow an LSP to deduct from the payment amount. /// @@ -184,6 +200,10 @@ pub struct Bolt12Offer { pub preimage: ::core::option::Option<::prost::alloc::string::String>, /// The secret used by the payment. #[prost(bytes = "bytes", optional, tag = "3")] + #[cfg_attr( + feature = "serde", + serde(serialize_with = "crate::serde_utils::serialize_opt_bytes_hex") + )] pub secret: ::core::option::Option<::prost::bytes::Bytes>, /// The hex-encoded ID of the offer this payment is for. #[prost(string, tag = "4")] @@ -213,6 +233,10 @@ pub struct Bolt12Refund { pub preimage: ::core::option::Option<::prost::alloc::string::String>, /// The secret used by the payment. #[prost(bytes = "bytes", optional, tag = "3")] + #[cfg_attr( + feature = "serde", + serde(serialize_with = "crate::serde_utils::serialize_opt_bytes_hex") + )] pub secret: ::core::option::Option<::prost::bytes::Bytes>, /// The payer's note for the payment. /// Truncated to \[PAYER_NOTE_LIMIT\]().