diff --git a/Cargo.toml b/Cargo.toml index e2db0b33..0a13d9e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ easy-hasher = "2.2.1" lightning-invoice = "0.22.0" log = "0.4.17" nostr-sdk = "0.24.0" -pretty_env_logger = "0.4.0" serde = { version = "1.0.149" } serde_json = "1.0.89" sqlx = { version = "0.6.2", features = [ @@ -37,5 +36,6 @@ reqwest = { version = "0.11", features = ["json"] } mostro-core = "0.2.8" tokio-cron-scheduler = "*" tracing = "0.1.37" -tracing-subscriber = "0.3.16" +tracing-subscriber = { version = "0.3.16", features =["env-filter"] } config = "0.13.3" +clap = { version = "4.4.4" , features = ["derive"] } diff --git a/src/app/order.rs b/src/app/order.rs index d1f6a59b..390cf2a9 100644 --- a/src/app/order.rs +++ b/src/app/order.rs @@ -1,4 +1,4 @@ -use crate::settings::Settings; +use crate::cli::settings::Settings; use crate::util::{get_market_quote, publish_order, send_dm}; use anyhow::Result; diff --git a/src/app/rate_user.rs b/src/app/rate_user.rs index c615d2b5..e0b8a964 100644 --- a/src/app/rate_user.rs +++ b/src/app/rate_user.rs @@ -3,7 +3,7 @@ use crate::util::{send_dm, update_user_rating_event}; use anyhow::Result; use log::{error, info}; use mostro_core::order::Order; -use mostro_core::{Action, Content, Message, Rating,NOSTR_REPLACEABLE_EVENT_KIND}; +use mostro_core::{Action, Content, Message, Rating, NOSTR_REPLACEABLE_EVENT_KIND}; use nostr_sdk::prelude::*; use sqlx::{Pool, Sqlite}; use sqlx_crud::Crud; diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 00000000..1a4aefc3 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,41 @@ +pub mod settings; + +use crate::cli::settings::init_default_dir; + +use anyhow::Result; +use clap::Parser; +use std::path::PathBuf; + +#[derive(Parser)] +#[command( + name = "mostro p2p", + about = "A P2P lightning exchange over Nostr", + author, + help_template = "\ +{before-help}{name} + +{about-with-newline} +{author-with-newline} +{usage-heading} {usage} + +{all-args}{after-help} +", + version +)] +#[command(propagate_version = true)] +#[command(arg_required_else_help(false))] +pub struct Cli { + /// Set folder for Mostro settings file - default is HOME/.mostro + #[arg(short, long)] + dirsettings: Option, +} + +pub fn settings_init() -> Result { + let cli = Cli::parse(); + + if let Some(path) = cli.dirsettings.as_deref() { + init_default_dir(Some(path.to_string())) + } else { + init_default_dir(None) + } +} diff --git a/src/settings.rs b/src/cli/settings.rs similarity index 98% rename from src/settings.rs rename to src/cli/settings.rs index b5fa5e08..641fd935 100644 --- a/src/settings.rs +++ b/src/cli/settings.rs @@ -164,7 +164,7 @@ impl Settings { } } -pub fn init_default_dir(config_path: Option<&String>) -> Result { +pub fn init_default_dir(config_path: Option) -> Result { // , final_path : &mut PathBuf) -> Result<()> { // Dir prefix let home_dir: OsString; diff --git a/src/db.rs b/src/db.rs index c2ca0791..6145033a 100644 --- a/src/db.rs +++ b/src/db.rs @@ -7,7 +7,7 @@ use sqlx::Sqlite; use sqlx::SqlitePool; use uuid::Uuid; -use crate::settings::Settings; +use crate::cli::settings::Settings; pub async fn connect() -> Result, sqlx::Error> { let db_settings = Settings::get_db(); diff --git a/src/flow.rs b/src/flow.rs index 16a9d1c8..83930702 100644 --- a/src/flow.rs +++ b/src/flow.rs @@ -1,4 +1,4 @@ -use crate::settings::Settings; +use crate::cli::settings::Settings; use crate::util::send_dm; use log::info; diff --git a/src/lightning/invoice.rs b/src/lightning/invoice.rs index 65192dda..9c4cd223 100644 --- a/src/lightning/invoice.rs +++ b/src/lightning/invoice.rs @@ -1,5 +1,5 @@ +use crate::cli::settings::Settings; use crate::error::MostroError; -use crate::settings::Settings; use chrono::prelude::*; use chrono::Duration; @@ -60,13 +60,17 @@ mod tests { use std::path::PathBuf; use super::is_valid_invoice; - use crate::{ - error::MostroError, - settings::{init_global_settings, Settings}, - }; + use crate::{cli::settings::Settings, error::MostroError, MOSTRO_CONFIG}; + + fn init_settings_test() { + let test_path = PathBuf::from("./"); + set_var("RUN_MODE", "tpl"); + MOSTRO_CONFIG.get_or_init(|| Settings::new(test_path).unwrap()); + } #[test] fn test_wrong_amount_invoice() { + init_settings_test(); let payment_request = "lnbcrt500u1p3l8zyapp5nc0ctxjt98xq9tgdgk9m8fepnp0kv6mnj6a83mfsannw46awdp4sdqqcqzpgxqyz5vqsp5a3axmz77s5vafmheq56uh49rmy59r9a3d0dm0220l8lzdp5jrtxs9qyyssqu0ft47j0r4lu997zuqgf92y8mppatwgzhrl0hzte7mzmwrqzf2238ylch82ehhv7pfcq6qcyu070dg85vu55het2edyljuezvcw5pzgqfncf3d"; let wrong_amount_err = is_valid_invoice(payment_request, Some(23), None); assert_eq!(Err(MostroError::WrongAmountError), wrong_amount_err); @@ -74,6 +78,7 @@ mod tests { #[test] fn test_is_expired_invoice() { + init_settings_test(); let payment_request = "lnbcrt500u1p3lzwdzpp5t9kgwgwd07y2lrwdscdnkqu4scrcgpm5pt9uwx0rxn5rxawlxlvqdqqcqzpgxqyz5vqsp5a6k7syfxeg8jy63rteywwjla5rrg2pvhedx8ajr2ltm4seydhsqq9qyyssq0n2uwlumsx4d0mtjm8tp7jw3y4da6p6z9gyyjac0d9xugf72lhh4snxpugek6n83geafue9ndgrhuhzk98xcecu2t3z56ut35mkammsqscqp0n"; let expired_err = is_valid_invoice(payment_request, None, None); assert_eq!(Err(MostroError::InvoiceExpiredError), expired_err); @@ -81,9 +86,7 @@ mod tests { #[test] fn test_min_amount_invoice() { - let test_path = PathBuf::from("./"); - set_var("RUN_MODE", "tpl"); - init_global_settings(Settings::new(test_path).unwrap()); + init_settings_test(); let payment_request = "lnbcrt10n1pjwqagdpp5qwa89czezks35s73fkjspxdssh7h4mmfs4643ey7fgxlng4d3jxqdqqcqzpgxqyz5vqsp5jjlmj6hlq0zxsg5t7n6h6a95ux3ej2w3w2csvdgcpndyvut3aaqs9qyyssqg6py7mmjlcgrscvvq4x3c6kr6f6reqanwkk7rjajm4wepggh4lnku3msrjt3045l0fsl4trh3ctg8ew756wq86mz72mguusey7m0a5qq83t8n6"; let min_amount_err = is_valid_invoice(payment_request, None, None); assert_eq!(Err(MostroError::MinAmountError), min_amount_err); diff --git a/src/lightning/mod.rs b/src/lightning/mod.rs index 7fac5b24..ee976867 100644 --- a/src/lightning/mod.rs +++ b/src/lightning/mod.rs @@ -1,8 +1,8 @@ pub mod invoice; use std::cmp::Ordering; +use crate::cli::settings::Settings; use crate::lightning::invoice::decode_invoice; -use crate::settings::Settings; use anyhow::Result; use easy_hasher::easy_hasher::*; diff --git a/src/main.rs b/src/main.rs index 597149cc..3d249b19 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ pub mod app; +pub mod cli; pub mod db; pub mod error; pub mod flow; @@ -6,47 +7,37 @@ pub mod lightning; pub mod messages; pub mod models; pub mod scheduler; -pub mod settings; pub mod util; use crate::app::run; +use crate::cli::settings::{init_global_settings, Settings}; +use crate::cli::settings_init; use anyhow::Result; use lightning::LndConnector; use nostr_sdk::prelude::*; use scheduler::start_scheduler; -use settings::Settings; -use settings::{init_default_dir, init_global_settings}; +use std::env; use std::sync::Arc; -use std::{env::args, path::PathBuf, sync::OnceLock}; +use std::sync::OnceLock; use tokio::sync::Mutex; +use tracing_subscriber::{fmt, prelude::*, EnvFilter}; static MOSTRO_CONFIG: OnceLock = OnceLock::new(); #[tokio::main] async fn main() -> Result<()> { - pretty_env_logger::init(); + env::set_var("RUST_LOG", "none,mostro=info"); - let rate_list: Arc>> = Arc::new(Mutex::new(vec![])); + // Tracing using RUST_LOG + tracing_subscriber::registry() + .with(fmt::layer()) + .with(EnvFilter::from_default_env()) + .init(); - // File settings path - let mut config_path = PathBuf::new(); + let rate_list: Arc>> = Arc::new(Mutex::new(vec![])); - let args: Vec = args().collect(); - // Create install path string - match args.len() { - 1 => { - // No dir parameter on cli - config_path = init_default_dir(None)?; - } - 3 => { - if args[1] == "--dir" { - config_path = init_default_dir(Some(&args[2]))?; - } - } - _ => { - println!("Can't get what you're sayin! Run mostro or mostro --dir /path/to_config_file") - } - } + // Init path from cli + let config_path = settings_init()?; // Create config global var init_global_settings(Settings::new(config_path)?); diff --git a/src/scheduler.rs b/src/scheduler.rs index 0af10286..85ab2689 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -1,6 +1,6 @@ +use crate::cli::settings::Settings; use crate::db::*; use crate::lightning::LndConnector; -use crate::settings::Settings; use crate::util::update_order_event; use anyhow::Result; @@ -10,16 +10,11 @@ use std::error::Error; use std::sync::Arc; use tokio::sync::Mutex; use tokio_cron_scheduler::{Job, JobScheduler}; -use tracing::{info, warn, Level}; -use tracing_subscriber::FmtSubscriber; +use tracing::{info, warn}; pub async fn start_scheduler( rate_list: Arc>>, ) -> Result> { - let subscriber = FmtSubscriber::builder() - .with_max_level(Level::INFO) - .finish(); - tracing::subscriber::set_global_default(subscriber).expect("Setting default subscriber failed"); info!("Creating scheduler"); let sched = JobScheduler::new().await?; cron_scheduler(&sched, rate_list).await?; diff --git a/src/util.rs b/src/util.rs index 75d2f3f8..8d294d28 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,15 +1,17 @@ +use crate::cli::settings::Settings; use crate::error::MostroError; use crate::lightning; use crate::lightning::LndConnector; use crate::messages; use crate::models::Yadio; -use crate::settings::Settings; use crate::{db, flow}; use anyhow::{Context, Result}; use log::{error, info}; use mostro_core::order::{NewOrder, Order, SmallOrder}; -use mostro_core::{Action, Content, Kind as OrderKind, Message, Status, NOSTR_REPLACEABLE_EVENT_KIND}; +use mostro_core::{ + Action, Content, Kind as OrderKind, Message, Status, NOSTR_REPLACEABLE_EVENT_KIND, +}; use nostr_sdk::prelude::*; use sqlx::SqlitePool; use sqlx::{Pool, Sqlite}; @@ -195,7 +197,12 @@ pub async fn update_user_rating_event( // let reputation = reput // nip33 kind and d tag let d_tag = Tag::Generic(TagKind::Custom("d".to_string()), vec![user.to_string()]); - let event = EventBuilder::new(Kind::Custom(NOSTR_REPLACEABLE_EVENT_KIND), reputation, &[d_tag]).to_event(keys)?; + let event = EventBuilder::new( + Kind::Custom(NOSTR_REPLACEABLE_EVENT_KIND), + reputation, + &[d_tag], + ) + .to_event(keys)?; info!("Sending replaceable event: {event:#?}"); // We update the order vote status if buyer_sent_rate { @@ -238,8 +245,12 @@ pub async fn update_order_event( let order_string = publish_order.as_json()?; // nip33 kind and d tag let d_tag = Tag::Generic(TagKind::Custom("d".to_string()), vec![order.id.to_string()]); - let event = - EventBuilder::new(Kind::Custom(NOSTR_REPLACEABLE_EVENT_KIND), &order_string, &[d_tag]).to_event(keys)?; + let event = EventBuilder::new( + Kind::Custom(NOSTR_REPLACEABLE_EVENT_KIND), + &order_string, + &[d_tag], + ) + .to_event(keys)?; let event_id = event.id.to_string(); let status_str = status.to_string(); info!("Sending replaceable event: {event:#?}");