From 9c1fe6815efe380962d04df6440d95b07308a783 Mon Sep 17 00:00:00 2001 From: Arkanoider Date: Thu, 9 Mar 2023 15:51:37 +0100 Subject: [PATCH 1/3] Order preview draft --- Cargo.toml | 1 + src/cli.rs | 55 ++++++++++++++++++++++++++++++++++++-- src/main.rs | 27 +++++++++++++++++++ src/pretty_table.rs | 64 +++++++++++++++++++++++++++++++++++++++++++-- src/types.rs | 8 +++--- src/util.rs | 2 ++ 6 files changed, 149 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index af2cb0a..455735c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,3 +31,4 @@ uuid = { version = "1.3.0", features = [ ] } dotenvy = "0.15.6" lightning-invoice = "0.21.0" + diff --git a/src/cli.rs b/src/cli.rs index 7d701a1..f0849a8 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -3,6 +3,56 @@ use clap::{Parser, Subcommand}; use crate::types::{Kind, Status}; use uuid::Uuid; +/// Check range simple version for just a single value +fn check_fiat_range(s: &str) -> Result { + match s.parse::() { + Ok(val) => Ok(val), + Err(_e) => Err(String::from("Error on parsing sats value")), + } +} + +// // Check range with two values value +// fn check_fiat_range(s: &str) -> Result { +// if s.contains('-') { + +// let min : u32; +// let max : u32; + +// // Get values from CLI +// let values : Vec<&str> = s.split('-').collect(); + +// // Check if more than two values +// if values.len() > 2 { return Err( String::from("Error")) }; + +// // Get ranged command +// if let Err(e) = values[0].parse::() { +// return Err(String::from("Error on parsing, check if you write a digit!")) +// } else { +// min = values[0].parse().unwrap(); +// } + +// if let Err(e) = values[1].parse::() { +// return Err(String::from("Error on parsing, check if you write a digit!")) +// } else { +// max = values[1].parse().unwrap(); +// } + +// // Check min below max +// if min >= max { return Err( String::from("Range of values must be 100-200 for example...")) }; + +// println!("{},{}",min,max); + +// Ok(s.to_string()) +// } +// else{ +// match s.parse::(){ +// Ok(_) => Ok(s.to_string()), +// Err(e) => Err(String::from("Error on parsing sats value")), +// } +// } + +// } + #[derive(Parser)] #[command( name = "mostro-cli", @@ -51,14 +101,15 @@ pub enum Commands { #[arg(value_enum)] #[arg(short, long)] kind: Option, - /// Sats amount + /// Sats amount - leave empty for market price #[arg(short, long)] - amount: u32, + amount: Option, /// Currency selected #[arg(short = 'c', long)] fiat_code: String, /// Fiat amount #[arg(short, long)] + #[clap(value_parser=check_fiat_range)] fiat_amount: u32, /// Payment method #[arg(short = 'm', long)] diff --git a/src/main.rs b/src/main.rs index 902da7d..9f3c6f2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ use clap::Parser; use dotenvy::{dotenv, var}; use nostr_sdk::prelude::*; use std::env::set_var; +use std::io::{stdin, BufRead}; pub mod cli; pub mod error; @@ -171,6 +172,14 @@ async fn main() -> Result<()> { }) => { let mostro_key = XOnlyPublicKey::from_bech32(pubkey)?; + // let mut yadio_API_exchange = String::from("https://api.yadio.io/exrates/"); + // yadio_API_exchange.push_str(&fiat_code); + + // //Request quotation in selected currency + // let yadio_ans = reqwest::blocking::get(yadio_API_exchange).unwrap().json()?; + + // println!("{:?}",yadio_ans); + let order_content = Content::Order(Order::new( None, kind.unwrap(), @@ -184,6 +193,24 @@ async fn main() -> Result<()> { None, )); + // Print order preview + let ord_preview = print_order_preview(order_content.clone()).unwrap(); + println!("{ord_preview}"); + let mut user_input = String::new(); + let _input = stdin(); + println!("Check your order! Is it correct? (Yes/No)"); + + let mut answer = stdin().lock(); + answer.read_line(&mut user_input)?; + + match user_input.as_str() { + "Yes" => {} + _ => { + println!("Try again!"); + std::process::exit(0); + } + } + // Create fiat sent message let message = Message::new(0, None, Action::Order, Some(order_content)) .as_json() diff --git a/src/pretty_table.rs b/src/pretty_table.rs index 6a04aeb..acb6095 100644 --- a/src/pretty_table.rs +++ b/src/pretty_table.rs @@ -1,9 +1,68 @@ -use crate::types::Order; +use crate::types::{Content, Order}; use anyhow::Result; use chrono::NaiveDateTime; use comfy_table::presets::UTF8_FULL; use comfy_table::*; +pub fn print_order_preview(ord: Content) -> Result { + let single_order = match ord { + Content::Order(o) => o, + _ => return Err("Error".to_string()), + }; + + let mut table = Table::new(); + + table + .load_preset(UTF8_FULL) + .set_content_arrangement(ContentArrangement::Dynamic) + .set_width(160) + .set_header(vec![ + Cell::new("Buy/Sell") + .add_attribute(Attribute::Bold) + .set_alignment(CellAlignment::Center), + Cell::new("Sats Amount") + .add_attribute(Attribute::Bold) + .set_alignment(CellAlignment::Center), + Cell::new("Fiat Code") + .add_attribute(Attribute::Bold) + .set_alignment(CellAlignment::Center), + Cell::new("Fiat Amount") + .add_attribute(Attribute::Bold) + .set_alignment(CellAlignment::Center), + Cell::new("Payment method") + .add_attribute(Attribute::Bold) + .set_alignment(CellAlignment::Center), + Cell::new("Premium %") + .add_attribute(Attribute::Bold) + .set_alignment(CellAlignment::Center), + ]); + + //Table rows + let r = Row::from(vec![ + match single_order.kind { + crate::types::Kind::Buy => Cell::new(single_order.kind.to_string()) + .fg(Color::Green) + .set_alignment(CellAlignment::Center), + crate::types::Kind::Sell => Cell::new(single_order.kind.to_string()) + .fg(Color::Red) + .set_alignment(CellAlignment::Center), + }, + if single_order.amount.is_none() { + Cell::new("market price").set_alignment(CellAlignment::Center) + } else { + Cell::new(single_order.amount.unwrap()).set_alignment(CellAlignment::Center) + }, + Cell::new(single_order.fiat_code.to_string()).set_alignment(CellAlignment::Center), + Cell::new(single_order.fiat_amount.to_string()).set_alignment(CellAlignment::Center), + Cell::new(single_order.payment_method.to_string()).set_alignment(CellAlignment::Center), + Cell::new(single_order.prime.to_string()).set_alignment(CellAlignment::Center), + ]); + + table.add_row(r); + + Ok(table.to_string()) +} + pub fn print_message_list(dm_list: Vec<(String, String)>) -> Result { let mut table = Table::new(); @@ -111,7 +170,8 @@ pub fn print_orders_table(orders_table: Vec) -> Result { }, Cell::new(single_order.id.unwrap()).set_alignment(CellAlignment::Center), Cell::new(single_order.status.to_string()).set_alignment(CellAlignment::Center), - Cell::new(single_order.amount.to_string()).set_alignment(CellAlignment::Center), + Cell::new(single_order.amount.unwrap().to_string()) + .set_alignment(CellAlignment::Center), Cell::new(single_order.fiat_code.to_string()).set_alignment(CellAlignment::Center), Cell::new(single_order.fiat_amount.to_string()) .set_alignment(CellAlignment::Center), diff --git a/src/types.rs b/src/types.rs index 5ea9a50..d591df5 100644 --- a/src/types.rs +++ b/src/types.rs @@ -96,7 +96,7 @@ pub struct Message { } /// Message content -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub enum Content { Order(Order), PaymentRequest(String), @@ -171,13 +171,13 @@ impl Message { } /// Mostro Order -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub struct Order { #[serde(skip_serializing_if = "Option::is_none")] pub id: Option, pub kind: Kind, pub status: Status, - pub amount: u32, + pub amount: Option, pub fiat_code: String, pub fiat_amount: u32, pub payment_method: String, @@ -195,7 +195,7 @@ impl Order { id: Option, kind: Kind, status: Status, - amount: u32, + amount: Option, fiat_code: String, fiat_amount: u32, payment_method: String, diff --git a/src/util.rs b/src/util.rs index a2eeb98..16b2566 100644 --- a/src/util.rs +++ b/src/util.rs @@ -71,6 +71,8 @@ pub async fn connect_nostr() -> Result { for r in relays.into_iter() { client.add_relay(r, None).await?; } + let opts = Options::new().wait_for_connection(true); + client.update_opts(opts); // Connect to relays and keep connection alive client.connect().await; From a1fb206e5acf7bff320a9ef67390daf26a117e3f Mon Sep 17 00:00:00 2001 From: Arkanoider Date: Thu, 9 Mar 2023 21:46:48 +0100 Subject: [PATCH 2/3] Missing trim at the end of the Yes/No confirm --- src/main.rs | 12 ++++++++---- src/util.rs | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index 9f3c6f2..2c54a4e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -203,13 +203,17 @@ async fn main() -> Result<()> { let mut answer = stdin().lock(); answer.read_line(&mut user_input)?; - match user_input.as_str() { - "Yes" => {} - _ => { + match user_input.as_str().trim_end() { + "Yes" => {}, + "No" => { println!("Try again!"); std::process::exit(0); + }, + &_ =>{ + println!("Can't get what you're sayin!"); + std::process::exit(0); } - } + }; // Create fiat sent message let message = Message::new(0, None, Action::Order, Some(order_content)) diff --git a/src/util.rs b/src/util.rs index 16b2566..f6a6e4c 100644 --- a/src/util.rs +++ b/src/util.rs @@ -101,7 +101,7 @@ pub async fn send_order_id_cmd( }, ) = notification { - println!("Message correctly sent to Mostro! Check messages with getdm command"); + println!("Message correctly sent to Mostro! Check messages with getdm or listorders command"); break; } } From c7dca427951c1cd28c72bda60cdc27b85b02aeee Mon Sep 17 00:00:00 2001 From: Arkanoider Date: Fri, 10 Mar 2023 16:57:10 +0100 Subject: [PATCH 3/3] Order confirm with Y or n with case insensitive. Return means Yes --- src/main.rs | 26 ++++++++++---------------- src/util.rs | 4 +++- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/main.rs b/src/main.rs index 2c54a4e..e82186c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ use clap::Parser; use dotenvy::{dotenv, var}; use nostr_sdk::prelude::*; use std::env::set_var; -use std::io::{stdin, BufRead}; +use std::io::{stdin, stdout, BufRead, Write}; pub mod cli; pub mod error; @@ -172,14 +172,7 @@ async fn main() -> Result<()> { }) => { let mostro_key = XOnlyPublicKey::from_bech32(pubkey)?; - // let mut yadio_API_exchange = String::from("https://api.yadio.io/exrates/"); - // yadio_API_exchange.push_str(&fiat_code); - - // //Request quotation in selected currency - // let yadio_ans = reqwest::blocking::get(yadio_API_exchange).unwrap().json()?; - - // println!("{:?}",yadio_ans); - + // Create new order for mostro let order_content = Content::Order(Order::new( None, kind.unwrap(), @@ -198,18 +191,19 @@ async fn main() -> Result<()> { println!("{ord_preview}"); let mut user_input = String::new(); let _input = stdin(); - println!("Check your order! Is it correct? (Yes/No)"); + print!("Check your order! Is it correct? (Y/n) > "); + stdout().flush()?; let mut answer = stdin().lock(); answer.read_line(&mut user_input)?; - match user_input.as_str().trim_end() { - "Yes" => {}, - "No" => { - println!("Try again!"); + match user_input.to_lowercase().as_str().trim_end() { + "y" | "" => {} + "n" => { + println!("Ok you have cancelled the order, create another one please"); std::process::exit(0); - }, - &_ =>{ + } + &_ => { println!("Can't get what you're sayin!"); std::process::exit(0); } diff --git a/src/util.rs b/src/util.rs index f6a6e4c..002cf9e 100644 --- a/src/util.rs +++ b/src/util.rs @@ -101,7 +101,9 @@ pub async fn send_order_id_cmd( }, ) = notification { - println!("Message correctly sent to Mostro! Check messages with getdm or listorders command"); + println!( + "Message correctly sent to Mostro! Check messages with getdm or listorders command" + ); break; } }