From 884a837ad525103e715119df893ac9d79885943c Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Fri, 15 May 2026 08:42:04 +0100 Subject: [PATCH 01/14] glcli: add "json" option to produce json outputs Signed-off-by: Lagrang3 --- Cargo.lock | 1 + libs/gl-cli/Cargo.toml | 1 + libs/gl-cli/src/bin/glcli.rs | 9 ++++++++- libs/gl-cli/src/lib.rs | 6 ++++++ libs/gl-cli/src/node.rs | 1 + libs/gl-cli/src/scheduler.rs | 1 + libs/gl-cli/src/signer.rs | 1 + 7 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 9f4d377b6..9bbbf55a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1522,6 +1522,7 @@ dependencies = [ "futures", "gl-client", "hex", + "serde_json", "thiserror 2.0.18", "tokio", "vls-core", diff --git a/libs/gl-cli/Cargo.toml b/libs/gl-cli/Cargo.toml index b0bd4d40f..f1babf3bf 100644 --- a/libs/gl-cli/Cargo.toml +++ b/libs/gl-cli/Cargo.toml @@ -28,6 +28,7 @@ hex = "0.4" thiserror = "2.0.11" tokio = "1.43.0" vls-core.workspace = true +serde_json = "^1.0" [badges] maintenance = { status = "actively-developed" } diff --git a/libs/gl-cli/src/bin/glcli.rs b/libs/gl-cli/src/bin/glcli.rs index d224311c6..a89ade553 100644 --- a/libs/gl-cli/src/bin/glcli.rs +++ b/libs/gl-cli/src/bin/glcli.rs @@ -1,14 +1,21 @@ use clap::Parser; use gl_cli::{run, Cli}; +use serde_json::json; #[tokio::main] async fn main() { let cli = Cli::parse(); + let json_print = cli.json; match run(cli).await { Ok(()) => (), Err(e) => { - println!("{}", e); + if json_print { + let j = json!({"error": e.to_string()}); + println!("{}", serde_json::to_string_pretty(&j).unwrap()); + } else { + println!("{}", e); + } } } } diff --git a/libs/gl-cli/src/lib.rs b/libs/gl-cli/src/lib.rs index 4a1c96f4a..c1db6664d 100644 --- a/libs/gl-cli/src/lib.rs +++ b/libs/gl-cli/src/lib.rs @@ -20,6 +20,9 @@ pub struct Cli { network: Network, #[arg(long, short, global = true, help_heading = "Global options")] verbose: bool, + /// Produce json outputs. + #[arg(long, short, global = true, help_heading = "Global options")] + pub json: bool, #[command(subcommand)] cmd: Commands, } @@ -57,6 +60,7 @@ pub async fn run(cli: Cli) -> Result<()> { scheduler::Config { data_dir, network: cli.network, + print_json: cli.json, }, ) .await? @@ -68,6 +72,7 @@ pub async fn run(cli: Cli) -> Result<()> { signer::Config { data_dir, network: cli.network, + print_json: cli.json, }, ) .await? @@ -78,6 +83,7 @@ pub async fn run(cli: Cli) -> Result<()> { node::Config { data_dir, network: cli.network, + print_json: cli.json, }, ) .await? diff --git a/libs/gl-cli/src/node.rs b/libs/gl-cli/src/node.rs index 115bfc151..5784530bc 100644 --- a/libs/gl-cli/src/node.rs +++ b/libs/gl-cli/src/node.rs @@ -10,6 +10,7 @@ use std::path::Path; pub struct Config> { pub data_dir: P, pub network: Network, + pub print_json: bool, } #[derive(Subcommand, Debug)] diff --git a/libs/gl-cli/src/scheduler.rs b/libs/gl-cli/src/scheduler.rs index ce11d90bc..775d7eb40 100644 --- a/libs/gl-cli/src/scheduler.rs +++ b/libs/gl-cli/src/scheduler.rs @@ -13,6 +13,7 @@ use util::{CREDENTIALS_FILE_NAME, SEED_FILE_NAME}; pub struct Config> { pub data_dir: P, pub network: Network, + pub print_json: bool, } #[derive(Subcommand, Debug)] diff --git a/libs/gl-cli/src/signer.rs b/libs/gl-cli/src/signer.rs index 767d30556..e1f8acbc2 100644 --- a/libs/gl-cli/src/signer.rs +++ b/libs/gl-cli/src/signer.rs @@ -13,6 +13,7 @@ use util::{CREDENTIALS_FILE_NAME, SEED_FILE_NAME}; pub struct Config> { pub data_dir: P, pub network: Network, + pub print_json: bool, } #[derive(Copy, Clone, Debug, Eq, PartialEq, ValueEnum)] From 535b8a8bc556bff52d2ad2cde12cf9e59f40588a Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Fri, 15 May 2026 11:29:18 +0100 Subject: [PATCH 02/14] gl-cli: add ToJsonHex trait ... and implemented the trait for GetinfoResponse to have nice json outputs from glcli. Signed-off-by: Lagrang3 --- libs/gl-cli/src/json_hex.rs | 46 +++++++++++++++++++++++++++++++++++++ libs/gl-cli/src/lib.rs | 1 + libs/gl-cli/src/node.rs | 12 +++++++++- 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 libs/gl-cli/src/json_hex.rs diff --git a/libs/gl-cli/src/json_hex.rs b/libs/gl-cli/src/json_hex.rs new file mode 100644 index 000000000..3e8100f76 --- /dev/null +++ b/libs/gl-cli/src/json_hex.rs @@ -0,0 +1,46 @@ +use gl_client::pb::cln; +use serde_json::json; + +pub trait ToJsonHex { + fn to_json_hex(&self) -> serde_json::Value; +} + +impl ToJsonHex for cln::GetinfoResponse { + fn to_json_hex(&self) -> serde_json::Value { + let mut j = json!({ + "id": hex::encode(&self.id), + "color": hex::encode(&self.color), + "num_peers": self.num_peers, + "num_pending_channels": self.num_pending_channels, + "num_active_channels": self.num_active_channels, + "num_inactive_channels": self.num_inactive_channels, + "address": self.address.clone(), + "binding": self.binding.clone(), + "version": self.version.clone(), + "blockheight": self.blockheight, + "network": self.network, + "lightning_dir": self.lightning_dir.clone(), + }); + if let Some(alias) = &self.alias { + j["alias"] = json!(alias); + } + if let Some(amt) = &self.fees_collected_msat { + j["fees_collected_msat"] = amt.msat.into(); + } + if let Some(feat) = &self.our_features { + j["our_features"] = json!({ + "init": hex::encode(&feat.init), + "node": hex::encode(&feat.node), + "channel": hex::encode(&feat.channel), + "invoice": hex::encode(&feat.invoice), + }); + } + if let Some(warn_bsync) = &self.warning_bitcoind_sync { + j["warning_bitcoind_sync"] = json!(warn_bsync); + } + if let Some(warn_lsync) = &self.warning_lightningd_sync { + j["warning_lightningd_sync"] = json!(warn_lsync); + } + j + } +} diff --git a/libs/gl-cli/src/lib.rs b/libs/gl-cli/src/lib.rs index c1db6664d..ddbe5b01b 100644 --- a/libs/gl-cli/src/lib.rs +++ b/libs/gl-cli/src/lib.rs @@ -3,6 +3,7 @@ use clap::{Parser, Subcommand}; use gl_client::bitcoin::Network; use std::{path::PathBuf, str::FromStr}; mod error; +mod json_hex; pub mod model; mod node; mod scheduler; diff --git a/libs/gl-cli/src/node.rs b/libs/gl-cli/src/node.rs index 5784530bc..e0aecb770 100644 --- a/libs/gl-cli/src/node.rs +++ b/libs/gl-cli/src/node.rs @@ -1,4 +1,5 @@ use crate::error::{Error, Result}; +use crate::json_hex::ToJsonHex; use crate::model; use crate::util::{self, CREDENTIALS_FILE_NAME, SEED_FILE_NAME}; use clap::Subcommand; @@ -429,13 +430,22 @@ async fn stop>(config: Config

) -> Result<()> { } async fn getinfo_handler>(config: Config

) -> Result<()> { + let print_json = config.print_json; let mut node: gl_client::node::ClnClient = get_node(config).await?; let res = node .getinfo(cln::GetinfoRequest {}) .await .map_err(|e| Error::custom(e.message()))? .into_inner(); - println!("{:?}", res); + if print_json { + let j = res.to_json_hex(); + println!( + "{}", + serde_json::to_string_pretty(&j).map_err(|e| Error::custom(e.to_string()))? + ); + } else { + println!("{:?}", res); + } Ok(()) } From 6dd6e25ab152890f0a30439e0d46b3fc45b429c2 Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Fri, 15 May 2026 13:58:25 +0100 Subject: [PATCH 03/14] gl-cli: add json serialization error type Signed-off-by: Lagrang3 --- libs/gl-cli/src/error.rs | 7 +++++++ libs/gl-cli/src/node.rs | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/libs/gl-cli/src/error.rs b/libs/gl-cli/src/error.rs index e13f4ba59..12b7162b6 100644 --- a/libs/gl-cli/src/error.rs +++ b/libs/gl-cli/src/error.rs @@ -16,6 +16,9 @@ pub enum Error { #[error(transparent)] UtilError(#[from] util::UtilsError), + + #[error("Failed to serialize response: {0}")] + JsonResponseError(String), } impl Error { @@ -31,6 +34,10 @@ impl Error { pub fn credentials_not_found(e: impl std::fmt::Display) -> Error { Error::CredentialsNotFoundError(e.to_string()) } + + pub fn failed_response_serialization(e: impl std::fmt::Display) -> Error { + Error::JsonResponseError(e.to_string()) + } } // -- Disable hints for now as it would require to get rid of thiserror. Might diff --git a/libs/gl-cli/src/node.rs b/libs/gl-cli/src/node.rs index e0aecb770..c69b0c8de 100644 --- a/libs/gl-cli/src/node.rs +++ b/libs/gl-cli/src/node.rs @@ -441,7 +441,8 @@ async fn getinfo_handler>(config: Config

) -> Result<()> { let j = res.to_json_hex(); println!( "{}", - serde_json::to_string_pretty(&j).map_err(|e| Error::custom(e.to_string()))? + serde_json::to_string_pretty(&j) + .map_err(|e| Error::failed_response_serialization(e))? ); } else { println!("{:?}", res); From 31381d5c845a5d4b6f9bc95fde19b31368996d55 Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Fri, 15 May 2026 14:05:01 +0100 Subject: [PATCH 04/14] gl-cli: add macro to print to json Sort out if we use the typical output or we print a json object. Use a macro to avoid code repetition. Signed-off-by: Lagrang3 --- libs/gl-cli/src/node.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/libs/gl-cli/src/node.rs b/libs/gl-cli/src/node.rs index c69b0c8de..ab240b7ee 100644 --- a/libs/gl-cli/src/node.rs +++ b/libs/gl-cli/src/node.rs @@ -233,6 +233,21 @@ pub async fn command_handler>(cmd: Command, config: Config

) -> } } +macro_rules! print_json_or_pb { + ($print_json: expr, $obj: expr) => { + if $print_json { + let j = $obj.to_json_hex(); + println!( + "{}", + serde_json::to_string_pretty(&j) + .map_err(|e| Error::failed_response_serialization(e))? + ); + } else { + println!("{:?}", $obj); + } + }; +} + async fn init_handler>(config: Config

, mnemonic: Option) -> Result<()> { // Check if seed already exists in the configuration path let seed_path = config.data_dir.as_ref().join(SEED_FILE_NAME); @@ -437,16 +452,7 @@ async fn getinfo_handler>(config: Config

) -> Result<()> { .await .map_err(|e| Error::custom(e.message()))? .into_inner(); - if print_json { - let j = res.to_json_hex(); - println!( - "{}", - serde_json::to_string_pretty(&j) - .map_err(|e| Error::failed_response_serialization(e))? - ); - } else { - println!("{:?}", res); - } + print_json_or_pb!(print_json, res); Ok(()) } From 7664fba4e9a1ab3b3d02b449815943eab343e188 Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Fri, 15 May 2026 14:50:37 +0100 Subject: [PATCH 05/14] gl-cli: add json output to invoice command Signed-off-by: Lagrang3 --- libs/gl-cli/src/json_hex.rs | 34 +++++++++++++++++++++++++++++++--- libs/gl-cli/src/node.rs | 3 ++- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/libs/gl-cli/src/json_hex.rs b/libs/gl-cli/src/json_hex.rs index 3e8100f76..cfea3247a 100644 --- a/libs/gl-cli/src/json_hex.rs +++ b/libs/gl-cli/src/json_hex.rs @@ -20,13 +20,11 @@ impl ToJsonHex for cln::GetinfoResponse { "blockheight": self.blockheight, "network": self.network, "lightning_dir": self.lightning_dir.clone(), + "fees_collected_msat": self.fees_collected_msat.clone().map_or(0, |amt| amt.msat), }); if let Some(alias) = &self.alias { j["alias"] = json!(alias); } - if let Some(amt) = &self.fees_collected_msat { - j["fees_collected_msat"] = amt.msat.into(); - } if let Some(feat) = &self.our_features { j["our_features"] = json!({ "init": hex::encode(&feat.init), @@ -44,3 +42,33 @@ impl ToJsonHex for cln::GetinfoResponse { j } } + +impl ToJsonHex for cln::InvoiceResponse { + fn to_json_hex(&self) -> serde_json::Value { + let mut j = json!({ + "bolt11": self.bolt11.clone(), + "payment_hash": hex::encode(&self.payment_hash), + "payment_secret": hex::encode(&self.payment_secret), + "expires_at": self.expires_at, + }); + if let Some(x) = self.created_index { + j["created_index"] = json!(x); + } + if let Some(x) = &self.warning_capacity { + j["warning_capacity"] = json!(x); + } + if let Some(x) = &self.warning_offline { + j["warning_offline"] = json!(x); + } + if let Some(x) = &self.warning_deadends { + j["warning_deadends"] = json!(x); + } + if let Some(x) = &self.warning_private_unused { + j["warning_private_unused"] = json!(x); + } + if let Some(x) = &self.warning_mpp { + j["warning_mpp"] = json!(x); + } + j + } +} diff --git a/libs/gl-cli/src/node.rs b/libs/gl-cli/src/node.rs index ab240b7ee..d0092aa74 100644 --- a/libs/gl-cli/src/node.rs +++ b/libs/gl-cli/src/node.rs @@ -467,6 +467,7 @@ async fn invoice_handler>( cltv: Option, deschashonly: Option, ) -> Result<()> { + let print_json = config.print_json; let mut node: gl_client::node::ClnClient = get_node(config).await?; let res = node .invoice(cln::InvoiceRequest { @@ -483,7 +484,7 @@ async fn invoice_handler>( .await .map_err(|e| Error::custom(e.message()))? .into_inner(); - println!("{:?}", res); + print_json_or_pb!(print_json, res); Ok(()) } From 4feba4bd1f06fe1328c9bb2d3238a28b4595331c Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Fri, 15 May 2026 15:23:40 +0100 Subject: [PATCH 06/14] gl-cli: add json output to pay command Signed-off-by: Lagrang3 --- libs/gl-cli/src/json_hex.rs | 21 +++++++++++++++++++++ libs/gl-cli/src/node.rs | 3 ++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/libs/gl-cli/src/json_hex.rs b/libs/gl-cli/src/json_hex.rs index cfea3247a..ef7afc5a0 100644 --- a/libs/gl-cli/src/json_hex.rs +++ b/libs/gl-cli/src/json_hex.rs @@ -72,3 +72,24 @@ impl ToJsonHex for cln::InvoiceResponse { j } } + +impl ToJsonHex for cln::PayResponse { + fn to_json_hex(&self) -> serde_json::Value { + let mut j = json!({ + "status": self.status, + "payment_preimage": hex::encode(&self.payment_preimage), + "payment_hash": hex::encode(&self.payment_hash), + "created_at": self.created_at, + "parts": self.parts, + "amount_msat": self.amount_msat.clone().map_or(0, |amt| amt.msat), + "amount_sent_msat": self.amount_sent_msat.clone().map_or(0, |amt| amt.msat), + }); + if let Some(x) = &self.destination { + j["destination"] = json!(hex::encode(x)); + } + if let Some(x) = &self.warning_partial_completion { + j["warning_partial_completion"] = json!(x); + } + j + } +} diff --git a/libs/gl-cli/src/node.rs b/libs/gl-cli/src/node.rs index d0092aa74..0a7415552 100644 --- a/libs/gl-cli/src/node.rs +++ b/libs/gl-cli/src/node.rs @@ -542,6 +542,7 @@ async fn pay_handler>( maxfee: Option, description: Option, ) -> Result<()> { + let print_json = config.print_json; let mut node: gl_client::node::ClnClient = get_node(config).await?; let res = node .pay(cln::PayRequest { @@ -562,6 +563,6 @@ async fn pay_handler>( .await .map_err(|e| Error::custom(e.message()))? .into_inner(); - println!("{:?}", res); + print_json_or_pb!(print_json, res); Ok(()) } From 80ce1799887716b3bc0429dab0141f16762a0b23 Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Fri, 15 May 2026 15:36:25 +0100 Subject: [PATCH 07/14] gl-cli: add json output to listpays command Signed-off-by: Lagrang3 --- libs/gl-cli/src/json_hex.rs | 52 +++++++++++++++++++++++++++++++++++++ libs/gl-cli/src/node.rs | 3 ++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/libs/gl-cli/src/json_hex.rs b/libs/gl-cli/src/json_hex.rs index ef7afc5a0..dc3a73e34 100644 --- a/libs/gl-cli/src/json_hex.rs +++ b/libs/gl-cli/src/json_hex.rs @@ -93,3 +93,55 @@ impl ToJsonHex for cln::PayResponse { j } } + +impl ToJsonHex for cln::ListpaysPays { + fn to_json_hex(&self) -> serde_json::Value { + let mut j = json!({ + "payment_hash": hex::encode(&self.payment_hash), + "status": self.status, + "created_at": self.created_at, + }); + if let Some(x) = &self.destination { + j["destination"] = json!(hex::encode(x)); + } + if let Some(x) = self.completed_at { + j["completed_at"] = json!(x); + } + if let Some(x) = &self.label { + j["label"] = json!(x); + } + if let Some(x) = &self.bolt11 { + j["bolt11"] = json!(x); + } + if let Some(x) = &self.description { + j["description"] = json!(x); + } + if let Some(x) = &self.bolt12 { + j["bolt12"] = json!(x); + } + if let Some(x) = &self.amount_msat { + j["amount_msat"] = x.msat.into(); + } + if let Some(x) = &self.amount_sent_msat { + j["amount_sent_msat"] = x.msat.into(); + } + if let Some(x) = &self.preimage { + j["preimage"] = json!(hex::encode(x)); + } + if let Some(x) = self.number_of_parts { + j["number_of_parts"] = json!(x); + } + if let Some(x) = &self.erroronion { + j["erroronion"] = json!(hex::encode(x)); + } + j + } +} + +impl ToJsonHex for cln::ListpaysResponse { + fn to_json_hex(&self) -> serde_json::Value { + json!({ + "pays": json!(self.pays.iter().map(|x| x.to_json_hex()).collect::>()) + }) + } +} diff --git a/libs/gl-cli/src/node.rs b/libs/gl-cli/src/node.rs index 0a7415552..9cbaaa2b0 100644 --- a/libs/gl-cli/src/node.rs +++ b/libs/gl-cli/src/node.rs @@ -510,6 +510,7 @@ async fn listpays_handler>( payment_hash: Option>, status: Option, ) -> Result<()> { + let print_json = config.print_json; let mut node: gl_client::node::ClnClient = get_node(config).await?; let res = node .list_pays(cln::ListpaysRequest { @@ -523,7 +524,7 @@ async fn listpays_handler>( .await .map_err(|e| Error::custom(e.message()))? .into_inner(); - println!("{:?}", res); + print_json_or_pb!(print_json, res); Ok(()) } From c0158029323ce9462216d147992fd6602c3373a4 Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Fri, 15 May 2026 15:44:09 +0100 Subject: [PATCH 08/14] gl-cli: add json output to connect command Signed-off-by: Lagrang3 --- libs/gl-cli/src/json_hex.rs | 32 ++++++++++++++++++++++++++++++++ libs/gl-cli/src/node.rs | 3 ++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/libs/gl-cli/src/json_hex.rs b/libs/gl-cli/src/json_hex.rs index dc3a73e34..1727786e0 100644 --- a/libs/gl-cli/src/json_hex.rs +++ b/libs/gl-cli/src/json_hex.rs @@ -145,3 +145,35 @@ impl ToJsonHex for cln::ListpaysResponse { }) } } + +impl ToJsonHex for cln::ConnectAddress { + fn to_json_hex(&self) -> serde_json::Value { + let mut j = json!({ + "item_type": self.item_type, + }); + if let Some(x) = &self.socket { + j["socket"] = json!(x); + } + if let Some(x) = &self.address { + j["address"] = json!(x); + } + if let Some(x) = &self.port { + j["port"] = json!(x); + } + j + } +} + +impl ToJsonHex for cln::ConnectResponse { + fn to_json_hex(&self) -> serde_json::Value { + let mut j = json!({ + "id": hex::encode(&self.id), + "features": hex::encode(&self.features), + "direction": self.direction, + }); + if let Some(x) = &self.address { + j["address"] = x.to_json_hex(); + } + j + } +} diff --git a/libs/gl-cli/src/node.rs b/libs/gl-cli/src/node.rs index 9cbaaa2b0..8bce40e2e 100644 --- a/libs/gl-cli/src/node.rs +++ b/libs/gl-cli/src/node.rs @@ -494,13 +494,14 @@ async fn connect_handler>( host: Option, port: Option, ) -> Result<()> { + let print_json = config.print_json; let mut node: gl_client::node::ClnClient = get_node(config).await?; let res = node .connect_peer(cln::ConnectRequest { id, host, port }) .await .map_err(|e| Error::custom(e.message()))? .into_inner(); - println!("{:?}", res); + print_json_or_pb!(print_json, res); Ok(()) } From b69d83f561953bd6a44cb0528cf2d6af756abafa Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Fri, 15 May 2026 15:47:32 +0100 Subject: [PATCH 09/14] gl-cli: add json output to stop command Though this implementation is trivial, notice that this command's response is always failure when it should be success. Signed-off-by: Lagrang3 --- libs/gl-cli/src/json_hex.rs | 6 ++++++ libs/gl-cli/src/node.rs | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/libs/gl-cli/src/json_hex.rs b/libs/gl-cli/src/json_hex.rs index 1727786e0..274fac448 100644 --- a/libs/gl-cli/src/json_hex.rs +++ b/libs/gl-cli/src/json_hex.rs @@ -177,3 +177,9 @@ impl ToJsonHex for cln::ConnectResponse { j } } + +impl ToJsonHex for cln::StopResponse { + fn to_json_hex(&self) -> serde_json::Value { + json!({}) + } +} diff --git a/libs/gl-cli/src/node.rs b/libs/gl-cli/src/node.rs index 8bce40e2e..8dc122df6 100644 --- a/libs/gl-cli/src/node.rs +++ b/libs/gl-cli/src/node.rs @@ -434,13 +434,14 @@ async fn close_handler>(config: Config

, id: String) -> Result< } async fn stop>(config: Config

) -> Result<()> { + let print_json = config.print_json; let mut node: gl_client::node::ClnClient = get_node(config).await?; let res = node .stop(cln::StopRequest {}) .await .map_err(|e| Error::custom(e.message()))? .into_inner(); - println!("{:?}", res); + print_json_or_pb!(print_json, res); Ok(()) } From 17eccd8eec92df678dd796b0c71a86dbd98fa986 Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Fri, 15 May 2026 15:51:42 +0100 Subject: [PATCH 10/14] gl-cli: add json output to close command Signed-off-by: Lagrang3 --- libs/gl-cli/src/json_hex.rs | 16 ++++++++++++++++ libs/gl-cli/src/node.rs | 3 ++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/libs/gl-cli/src/json_hex.rs b/libs/gl-cli/src/json_hex.rs index 274fac448..d1ae57ef3 100644 --- a/libs/gl-cli/src/json_hex.rs +++ b/libs/gl-cli/src/json_hex.rs @@ -183,3 +183,19 @@ impl ToJsonHex for cln::StopResponse { json!({}) } } + +impl ToJsonHex for cln::CloseResponse { + fn to_json_hex(&self) -> serde_json::Value { + let mut j = json!({ + "item_type": self.item_type, + }); + if let Some(x) = &self.tx { + j["tx"] = json!(hex::encode(x)); + } + if let Some(x) = &self.txid { + j["txid"] = json!(hex::encode(x)); + } + + j + } +} diff --git a/libs/gl-cli/src/node.rs b/libs/gl-cli/src/node.rs index 8dc122df6..ea126a990 100644 --- a/libs/gl-cli/src/node.rs +++ b/libs/gl-cli/src/node.rs @@ -415,6 +415,7 @@ async fn fundchannel_handler>( } async fn close_handler>(config: Config

, id: String) -> Result<()> { + let print_json = config.print_json; let mut node: gl_client::node::ClnClient = get_node(config).await?; let res = node .close(cln::CloseRequest { @@ -429,7 +430,7 @@ async fn close_handler>(config: Config

, id: String) -> Result< .await .map_err(|e| Error::custom(e.message()))? .into_inner(); - println!("{:?}", res); + print_json_or_pb!(print_json, res); Ok(()) } From 3c6412515497b1d2db5a491fa0d9517bb9d172fe Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Fri, 15 May 2026 15:57:22 +0100 Subject: [PATCH 11/14] gl-cli: add json output to fundchannel command Signed-off-by: Lagrang3 --- libs/gl-cli/src/json_hex.rs | 19 +++++++++++++++++++ libs/gl-cli/src/node.rs | 3 ++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/libs/gl-cli/src/json_hex.rs b/libs/gl-cli/src/json_hex.rs index d1ae57ef3..39e3517c0 100644 --- a/libs/gl-cli/src/json_hex.rs +++ b/libs/gl-cli/src/json_hex.rs @@ -199,3 +199,22 @@ impl ToJsonHex for cln::CloseResponse { j } } + +impl ToJsonHex for cln::FundchannelResponse { + fn to_json_hex(&self) -> serde_json::Value { + let mut j = json!({ + "tx": hex::encode(&self.tx), + "txid": hex::encode(&self.txid), + "outnum": self.outnum, + "channel_id": hex::encode(&self.channel_id), + }); + if let Some(x) = &self.close_to { + j["close_to"] = json!(hex::encode(x)); + } + if let Some(x) = &self.mindepth { + j["mindepth"] = json!(x); + } + + j + } +} diff --git a/libs/gl-cli/src/node.rs b/libs/gl-cli/src/node.rs index ea126a990..19ce6e9dd 100644 --- a/libs/gl-cli/src/node.rs +++ b/libs/gl-cli/src/node.rs @@ -388,6 +388,7 @@ async fn fundchannel_handler>( id: String, amount_sat: model::AmountSatOrAll, ) -> Result<()> { + let print_json = config.print_json; let mut node: gl_client::node::ClnClient = get_node(config).await?; let id_bytes = hex::FromHex::from_hex(&id) .map_err(|e| Error::custom(format!("Invalid hex string: {id}. {e}")))?; @@ -410,7 +411,7 @@ async fn fundchannel_handler>( .await .map_err(|e| Error::custom(e.message()))? .into_inner(); - println!("{:?}", res); + print_json_or_pb!(print_json, res); Ok(()) } From 8226431f20957f0cb00654a22ffcdbb823f496ee Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Fri, 15 May 2026 16:17:55 +0100 Subject: [PATCH 12/14] gl-cli: add json output to withdraw command Signed-off-by: Lagrang3 --- libs/gl-cli/src/json_hex.rs | 10 ++++++++++ libs/gl-cli/src/node.rs | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/libs/gl-cli/src/json_hex.rs b/libs/gl-cli/src/json_hex.rs index 39e3517c0..04f2adbef 100644 --- a/libs/gl-cli/src/json_hex.rs +++ b/libs/gl-cli/src/json_hex.rs @@ -218,3 +218,13 @@ impl ToJsonHex for cln::FundchannelResponse { j } } + +impl ToJsonHex for cln::WithdrawResponse { + fn to_json_hex(&self) -> serde_json::Value { + json!({ + "tx": hex::encode(&self.tx), + "txid": hex::encode(&self.txid), + "psbt": self.psbt.clone(), + }) + } +} diff --git a/libs/gl-cli/src/node.rs b/libs/gl-cli/src/node.rs index 19ce6e9dd..4d542528c 100644 --- a/libs/gl-cli/src/node.rs +++ b/libs/gl-cli/src/node.rs @@ -367,6 +367,7 @@ async fn withdraw_handler>( destination: String, amount_sat: model::AmountSatOrAll, ) -> Result<()> { + let print_json = config.print_json; let mut node: gl_client::node::ClnClient = get_node(config).await?; let res = node .withdraw(cln::WithdrawRequest { @@ -379,7 +380,7 @@ async fn withdraw_handler>( .await .map_err(|e| Error::custom(e.message()))? .into_inner(); - println!("{:?}", res); + print_json_or_pb!(print_json, res); Ok(()) } From 0c0364e2d59cadd0cafbb0171bf0fc4ed48b473d Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Fri, 15 May 2026 16:31:04 +0100 Subject: [PATCH 13/14] gl-cli: add json output to listfunds command Signed-off-by: Lagrang3 --- libs/gl-cli/src/json_hex.rs | 53 +++++++++++++++++++++++++++++++++++++ libs/gl-cli/src/node.rs | 3 ++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/libs/gl-cli/src/json_hex.rs b/libs/gl-cli/src/json_hex.rs index 04f2adbef..4ff74a3a8 100644 --- a/libs/gl-cli/src/json_hex.rs +++ b/libs/gl-cli/src/json_hex.rs @@ -228,3 +228,56 @@ impl ToJsonHex for cln::WithdrawResponse { }) } } + +impl ToJsonHex for cln::ListfundsOutputs { + fn to_json_hex(&self) -> serde_json::Value { + let mut j = json!({ + "txid": hex::encode(&self.txid), + "scriptpubkey": hex::encode(&self.scriptpubkey), + "output": self.output, + "amount_msat": self.amount_msat.clone().map_or(0, |amt| amt.msat), + "status": self.status, + "reserved": self.reserved + }); + if let Some(x) = &self.address { + j["address"] = json!(x); + } + if let Some(x) = &self.redeemscript { + j["redeemscript"] = json!(hex::encode(x)); + } + if let Some(x) = self.blockheight { + j["blockheight"] = json!(x); + } + j + } +} + +impl ToJsonHex for cln::ListfundsChannels { + fn to_json_hex(&self) -> serde_json::Value { + let mut j = json!({ + "peer_id": hex::encode(&self.peer_id), + "our_amount_msat": self.our_amount_msat.clone().map_or(0, |amt| amt.msat), + "amount_msat": self.amount_msat.clone().map_or(0, |amt| amt.msat), + "funding_txid": hex::encode(&self.funding_txid), + "funding_output": self.funding_output, + "connected": self.connected, + "state": self.state, + }); + if let Some(x) = &self.channel_id { + j["channel_id"] = json!(hex::encode(x)); + } + if let Some(x) = &self.short_channel_id { + j["short_channel_id"] = json!(x); + } + j + } +} + +impl ToJsonHex for cln::ListfundsResponse { + fn to_json_hex(&self) -> serde_json::Value { + json!({ + "outputs": json!(self.outputs.iter().map(|x| x.to_json_hex()).collect::>()), + "channels": json!(self.channels.iter().map(|x| x.to_json_hex()).collect::>()) + }) + } +} diff --git a/libs/gl-cli/src/node.rs b/libs/gl-cli/src/node.rs index 4d542528c..f127b752f 100644 --- a/libs/gl-cli/src/node.rs +++ b/libs/gl-cli/src/node.rs @@ -352,13 +352,14 @@ async fn newaddr_handler>(config: Config

) -> Result<()> { } async fn listfunds_handler>(config: Config

) -> Result<()> { + let print_json = config.print_json; let mut node: gl_client::node::ClnClient = get_node(config).await?; let res = node .list_funds(cln::ListfundsRequest { spent: None }) .await .map_err(|e| Error::custom(e.message()))? .into_inner(); - println!("{:?}", res); + print_json_or_pb!(print_json, res); Ok(()) } From f5ec862f7a6cbd04a3eb8e587f7a501bc31e235d Mon Sep 17 00:00:00 2001 From: Lagrang3 Date: Fri, 15 May 2026 16:34:51 +0100 Subject: [PATCH 14/14] gl-cli: add json output to newaddr Signed-off-by: Lagrang3 --- libs/gl-cli/src/json_hex.rs | 13 +++++++++++++ libs/gl-cli/src/node.rs | 3 ++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/libs/gl-cli/src/json_hex.rs b/libs/gl-cli/src/json_hex.rs index 4ff74a3a8..0360ca019 100644 --- a/libs/gl-cli/src/json_hex.rs +++ b/libs/gl-cli/src/json_hex.rs @@ -281,3 +281,16 @@ impl ToJsonHex for cln::ListfundsResponse { }) } } + +impl ToJsonHex for cln::NewaddrResponse { + fn to_json_hex(&self) -> serde_json::Value { + let mut j = json!({}); + if let Some(x) = &self.p2tr { + j["p2tr"] = json!(x); + } + if let Some(x) = &self.bech32 { + j["bech32"] = json!(x); + } + j + } +} diff --git a/libs/gl-cli/src/node.rs b/libs/gl-cli/src/node.rs index f127b752f..df71875a8 100644 --- a/libs/gl-cli/src/node.rs +++ b/libs/gl-cli/src/node.rs @@ -341,13 +341,14 @@ async fn log>(config: Config

) -> Result<()> { } async fn newaddr_handler>(config: Config

) -> Result<()> { + let print_json = config.print_json; let mut node: gl_client::node::ClnClient = get_node(config).await?; let res = node .new_addr(cln::NewaddrRequest { addresstype: None }) .await .map_err(|e| Error::custom(e.message()))? .into_inner(); - println!("{:?}", res); + print_json_or_pb!(print_json, res); Ok(()) }