X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fcli.rs;h=99a43784cb69ad55b2aabd9598f6c47d6db3a9be;hb=d5f75d82e2ba1d4bede3f5b049cc5e0890210a60;hp=7d865158e6e7e786a93b52ff99a513d766f50b08;hpb=523ca2dafd555d8b5fe49107f0c4ed9509553a51;p=ldk-sample diff --git a/src/cli.rs b/src/cli.rs index 7d86515..99a4378 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -9,12 +9,13 @@ use bitcoin::hashes::Hash; use bitcoin::network::constants::Network; use bitcoin::secp256k1::PublicKey; use lightning::chain::keysinterface::{KeysInterface, KeysManager, Recipient}; -use lightning::ln::msgs::NetAddress; +use lightning::ln::msgs::{DecodeError, NetAddress}; use lightning::ln::{PaymentHash, PaymentPreimage}; -use lightning::onion_message::Destination; +use lightning::onion_message::{CustomOnionMessageContents, Destination, OnionMessageContents}; use lightning::routing::gossip::NodeId; use lightning::util::config::{ChannelHandshakeConfig, ChannelHandshakeLimits, UserConfig}; use lightning::util::events::EventHandler; +use lightning::util::ser::{MaybeReadableArgs, Writeable, Writer}; use lightning_invoice::payment::PaymentError; use lightning_invoice::{utils, Currency, Invoice}; use std::env; @@ -140,14 +141,39 @@ pub(crate) fn parse_startup_args() -> Result { }) } +struct UserOnionMessageContents { + tlv_type: u64, + data: Vec, +} + +impl CustomOnionMessageContents for UserOnionMessageContents { + fn tlv_type(&self) -> u64 { + self.tlv_type + } +} +impl MaybeReadableArgs for UserOnionMessageContents { + fn read(_r: &mut R, _args: u64) -> Result, DecodeError> { + // UserOnionMessageContents is only ever passed to `send_onion_message`, never to an + // `OnionMessageHandler`, thus it does not need to implement the read side here. + unreachable!(); + } +} +impl Writeable for UserOnionMessageContents { + fn write(&self, w: &mut W) -> Result<(), std::io::Error> { + w.write_all(&self.data) + } +} + pub(crate) async fn poll_for_user_input( invoice_payer: Arc>, peer_manager: Arc, channel_manager: Arc, keys_manager: Arc, network_graph: Arc, onion_messenger: Arc, inbound_payments: PaymentInfoStorage, outbound_payments: PaymentInfoStorage, - ldk_data_dir: String, network: Network, + ldk_data_dir: String, network: Network, logger: Arc, ) { - println!("LDK startup successful. To view available commands: \"help\"."); + println!( + "LDK startup successful. Enter \"help\" to view available commands. Press Ctrl-D to quit." + ); println!("LDK logs are available at /.ldk/logs"); println!("Local Node ID is {}.", channel_manager.get_our_node_id()); loop { @@ -155,7 +181,12 @@ pub(crate) async fn poll_for_user_input( io::stdout().flush().unwrap(); // Without flushing, the `>` doesn't print let mut line = String::new(); if let Err(e) = io::stdin().read_line(&mut line) { - break println!("ERROR: {e:#}"); + break println!("ERROR: {}", e); + } + + if line.len() == 0 { + // We hit EOF / Ctrl-D + break; } let mut words = line.split_whitespace(); @@ -297,11 +328,12 @@ pub(crate) async fn poll_for_user_input( get_invoice( amt_msat.unwrap(), - inbound_payments.clone(), - channel_manager.clone(), - keys_manager.clone(), + Arc::clone(&inbound_payments), + &*channel_manager, + Arc::clone(&keys_manager), network, expiry_secs.unwrap(), + Arc::clone(&logger), ); } "connectpeer" => { @@ -449,16 +481,32 @@ pub(crate) async fn poll_for_user_input( if errored { continue; } + let tlv_type = match words.next().map(|ty_str| ty_str.parse()) { + Some(Ok(ty)) if ty >= 64 => ty, + _ => { + println!("Need an integral message type above 64"); + continue; + } + }; + let data = match words.next().map(|s| hex_utils::to_vec(s)) { + Some(Some(data)) => data, + _ => { + println!("Need a hex data string"); + continue; + } + }; let destination_pk = node_pks.pop().unwrap(); match onion_messenger.send_onion_message( &node_pks, Destination::Node(destination_pk), + OnionMessageContents::Custom(UserOnionMessageContents { tlv_type, data }), None, ) { Ok(()) => println!("SUCCESS: forwarded onion message to first hop"), Err(e) => println!("ERROR: failed to send onion message: {:?}", e), } } + "quit" | "exit" => break, _ => println!("Unknown command. See `\"help\" for available commands."), } } @@ -466,19 +514,35 @@ pub(crate) async fn poll_for_user_input( } fn help() { - println!("openchannel pubkey@host:port [--public]"); - println!("sendpayment "); - println!("keysend "); - println!("getinvoice "); - println!("connectpeer pubkey@host:port"); - println!("listchannels"); - println!("listpayments"); - println!("closechannel "); - println!("forceclosechannel "); - println!("nodeinfo"); - println!("listpeers"); - println!("signmessage "); - println!("sendonionmessage "); + let package_version = env!("CARGO_PKG_VERSION"); + let package_name = env!("CARGO_PKG_NAME"); + println!("\nVERSION:"); + println!(" {} v{}", package_name, package_version); + println!("\nUSAGE:"); + println!(" Command [arguments]"); + println!("\nCOMMANDS:"); + println!(" help\tShows a list of commands."); + println!(" quit\tClose the application."); + println!("\n Channels:"); + println!(" openchannel pubkey@host:port [--public]"); + println!(" closechannel "); + println!(" forceclosechannel "); + println!(" listchannels"); + println!("\n Peers:"); + println!(" connectpeer pubkey@host:port"); + println!(" listpeers"); + println!("\n Payments:"); + println!(" sendpayment "); + println!(" keysend "); + println!(" listpayments"); + println!("\n Invoices:"); + println!(" getinvoice "); + println!("\n Other:"); + println!(" signmessage "); + println!( + " sendonionmessage " + ); + println!(" nodeinfo"); } fn node_info(channel_manager: &Arc, peer_manager: &Arc) { @@ -742,8 +806,9 @@ fn keysend( } fn get_invoice( - amt_msat: u64, payment_storage: PaymentInfoStorage, channel_manager: Arc, + amt_msat: u64, payment_storage: PaymentInfoStorage, channel_manager: &ChannelManager, keys_manager: Arc, network: Network, expiry_secs: u32, + logger: Arc, ) { let mut payments = payment_storage.lock().unwrap(); let currency = match network { @@ -753,8 +818,9 @@ fn get_invoice( Network::Signet => Currency::Signet, }; let invoice = match utils::create_invoice_from_channelmanager( - &channel_manager, + channel_manager, keys_manager, + logger, currency, Some(amt_msat), "ldk-tutorial-node".to_string(),