From 2ea6473ae2371d7dd7f1932c7f2da4ef11d10e93 Mon Sep 17 00:00:00 2001 From: William Casarin Date: Fri, 30 Aug 2024 10:37:37 -0700 Subject: [PATCH] refactor: move args to its own file Signed-off-by: William Casarin --- src/app.rs | 230 ++-------------------------------------------------- src/args.rs | 228 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 3 files changed, 235 insertions(+), 224 deletions(-) create mode 100644 src/args.rs diff --git a/src/app.rs b/src/app.rs index 86d88ba..2ff5485 100644 --- a/src/app.rs +++ b/src/app.rs @@ -2,6 +2,7 @@ use crate::account_manager::AccountManager; use crate::actionbar::BarResult; use crate::app_creation::setup_cc; use crate::app_style::user_requested_visuals_change; +use crate::args::Args; use crate::draft::Drafts; use crate::frame_history::FrameHistory; use crate::imgcache::ImageCache; @@ -11,13 +12,13 @@ use crate::notecache::{CachedNote, NoteCache}; use crate::relay_pool_manager::RelayPoolManager; use crate::route::Route; use crate::thread::{DecrementResult, Threads}; -use crate::timeline::{ColumnKind, ListKind, PubkeySource, Timeline, TimelineSource, ViewFilter}; +use crate::timeline::{ColumnKind, Timeline, TimelineSource, ViewFilter}; use crate::ui::note::PostAction; use crate::ui::{self, AccountSelectionWidget, DesktopGlobalPopup}; use crate::ui::{DesktopSidePanel, RelayView, View}; -use crate::{Error, Result}; +use crate::Result; use egui_nav::{Nav, NavAction}; -use enostr::{ClientMessage, Keypair, Pubkey, RelayEvent, RelayMessage, RelayPool, SecretKey}; +use enostr::{ClientMessage, RelayEvent, RelayMessage, RelayPool}; use std::cell::RefCell; use std::rc::Rc; @@ -108,6 +109,7 @@ fn send_initial_filters(damus: &mut Damus, relay_url: &str) { filter.clone() } else { // TODO: handle unloaded filters + error!("TODO: handle unloaded filters"); continue; }; @@ -364,6 +366,7 @@ fn setup_initial_nostrdb_subs(damus: &mut Damus) -> Result<()> { } else { // TODO: for unloaded filters, we will need to fetch things like // the contact and relay list from remote relays. + error!("TODO: handle unloaded filters"); continue; }; @@ -535,227 +538,6 @@ fn render_damus(damus: &mut Damus, ctx: &Context) { puffin_egui::profiler_window(ctx); } -enum ArgColumn { - Column(ColumnKind), - Generic(Vec), -} - -impl ArgColumn { - pub fn into_timeline(self, ndb: &Ndb, user: Option<&[u8; 32]>) -> Timeline { - match self { - ArgColumn::Generic(filters) => Timeline::new(ColumnKind::Generic, Some(filters)), - - ArgColumn::Column(ColumnKind::Universe) => { - Timeline::new(ColumnKind::Universe, Some(vec![])) - } - - ArgColumn::Column(ColumnKind::Generic) => { - panic!("Not a valid ArgColumn") - } - - ArgColumn::Column(ColumnKind::List(ListKind::Contact(ref pk_src))) => { - let pk = match pk_src { - PubkeySource::DeckAuthor => { - if let Some(user_pk) = user { - user_pk - } else { - // No user loaded, so we have to return an unloaded - // contact list columns - return Timeline::new( - ColumnKind::contact_list(PubkeySource::DeckAuthor), - None, - ); - } - } - PubkeySource::Explicit(pk) => pk.bytes(), - }; - - let contact_filter = Filter::new().authors([pk]).kinds([3]).limit(1).build(); - let txn = Transaction::new(ndb).expect("txn"); - let results = ndb - .query(&txn, vec![contact_filter], 1) - .expect("contact query failed?"); - - if results.is_empty() { - return Timeline::new(ColumnKind::contact_list(pk_src.to_owned()), None); - } - - match Timeline::contact_list(&results[0].note) { - Err(Error::EmptyContactList) => { - Timeline::new(ColumnKind::contact_list(pk_src.to_owned()), None) - } - Err(e) => panic!("Unexpected error: {e}"), - Ok(tl) => tl, - } - } - } - } -} - -struct Args { - columns: Vec, - relays: Vec, - is_mobile: Option, - keys: Vec, - since_optimize: bool, - light: bool, - dbpath: Option, -} - -impl Args { - fn parse(args: &[String]) -> Self { - let mut res = Args { - columns: vec![], - relays: vec![], - is_mobile: None, - keys: vec![], - light: false, - since_optimize: true, - dbpath: None, - }; - - let mut i = 0; - let len = args.len(); - while i < len { - let arg = &args[i]; - - if arg == "--mobile" { - res.is_mobile = Some(true); - } else if arg == "--light" { - res.light = true; - } else if arg == "--dark" { - res.light = false; - } else if arg == "--pub" || arg == "--npub" { - i += 1; - let pubstr = if let Some(next_arg) = args.get(i) { - next_arg - } else { - error!("sec argument missing?"); - continue; - }; - - if let Ok(pk) = Pubkey::parse(pubstr) { - res.keys.push(Keypair::only_pubkey(pk)); - } else { - error!( - "failed to parse {} argument. Make sure to use hex or npub.", - arg - ); - } - } else if arg == "--sec" || arg == "--nsec" { - i += 1; - let secstr = if let Some(next_arg) = args.get(i) { - next_arg - } else { - error!("sec argument missing?"); - continue; - }; - - if let Ok(sec) = SecretKey::parse(secstr) { - res.keys.push(Keypair::from_secret(sec)); - } else { - error!( - "failed to parse {} argument. Make sure to use hex or nsec.", - arg - ); - } - } else if arg == "--no-since-optimize" { - res.since_optimize = false; - } else if arg == "--filter" { - i += 1; - let filter = if let Some(next_arg) = args.get(i) { - next_arg - } else { - error!("filter argument missing?"); - continue; - }; - - if let Ok(filter) = Filter::from_json(filter) { - res.columns.push(ArgColumn::Generic(vec![filter])); - } else { - error!("failed to parse filter '{}'", filter); - } - } else if arg == "--dbpath" { - i += 1; - let path = if let Some(next_arg) = args.get(i) { - next_arg - } else { - error!("dbpath argument missing?"); - continue; - }; - res.dbpath = Some(path.clone()); - } else if arg == "-r" || arg == "--relay" { - i += 1; - let relay = if let Some(next_arg) = args.get(i) { - next_arg - } else { - error!("relay argument missing?"); - continue; - }; - res.relays.push(relay.clone()); - } else if arg == "--column" || arg == "-c" { - i += 1; - let column_name = if let Some(next_arg) = args.get(i) { - next_arg - } else { - error!("column argument missing"); - continue; - }; - - if column_name.starts_with("contacts:") { - if let Ok(pubkey) = Pubkey::parse(&column_name[9..]) { - info!("got contact column for user {}", pubkey.hex()); - res.columns.push(ArgColumn::Column(ColumnKind::contact_list( - PubkeySource::Explicit(pubkey), - ))) - } else { - error!("error parsing contacts pubkey {}", &column_name[9..]); - continue; - } - } else if column_name == "contacts" { - res.columns.push(ArgColumn::Column(ColumnKind::contact_list( - PubkeySource::DeckAuthor, - ))) - } - } else if arg == "--filter-file" || arg == "-f" { - i += 1; - let filter_file = if let Some(next_arg) = args.get(i) { - next_arg - } else { - error!("filter file argument missing?"); - continue; - }; - - let data = if let Ok(data) = std::fs::read(filter_file) { - data - } else { - error!("failed to read filter file '{}'", filter_file); - continue; - }; - - if let Some(filter) = std::str::from_utf8(&data) - .ok() - .and_then(|s| Filter::from_json(s).ok()) - { - res.columns.push(ArgColumn::Generic(vec![filter])); - } else { - error!("failed to parse filter in '{}'", filter_file); - } - } - - i += 1; - } - - if res.columns.is_empty() { - let ck = ColumnKind::contact_list(PubkeySource::DeckAuthor); - info!("No columns set, setting up defaults: {:?}", ck); - res.columns.push(ArgColumn::Column(ck)); - } - - res - } -} - /* fn determine_key_storage_type() -> KeyStorageType { #[cfg(target_os = "macos")] diff --git a/src/args.rs b/src/args.rs new file mode 100644 index 0000000..379f3fa --- /dev/null +++ b/src/args.rs @@ -0,0 +1,228 @@ +use crate::timeline::{ColumnKind, ListKind, PubkeySource, Timeline}; +use crate::Error; +use enostr::{Filter, Keypair, Pubkey, SecretKey}; +use nostrdb::{Ndb, Transaction}; +use tracing::{error, info}; + +pub struct Args { + pub columns: Vec, + pub relays: Vec, + pub is_mobile: Option, + pub keys: Vec, + pub since_optimize: bool, + pub light: bool, + pub dbpath: Option, +} + +impl Args { + pub fn parse(args: &[String]) -> Self { + let mut res = Args { + columns: vec![], + relays: vec![], + is_mobile: None, + keys: vec![], + light: false, + since_optimize: true, + dbpath: None, + }; + + let mut i = 0; + let len = args.len(); + while i < len { + let arg = &args[i]; + + if arg == "--mobile" { + res.is_mobile = Some(true); + } else if arg == "--light" { + res.light = true; + } else if arg == "--dark" { + res.light = false; + } else if arg == "--pub" || arg == "--npub" { + i += 1; + let pubstr = if let Some(next_arg) = args.get(i) { + next_arg + } else { + error!("sec argument missing?"); + continue; + }; + + if let Ok(pk) = Pubkey::parse(pubstr) { + res.keys.push(Keypair::only_pubkey(pk)); + } else { + error!( + "failed to parse {} argument. Make sure to use hex or npub.", + arg + ); + } + } else if arg == "--sec" || arg == "--nsec" { + i += 1; + let secstr = if let Some(next_arg) = args.get(i) { + next_arg + } else { + error!("sec argument missing?"); + continue; + }; + + if let Ok(sec) = SecretKey::parse(secstr) { + res.keys.push(Keypair::from_secret(sec)); + } else { + error!( + "failed to parse {} argument. Make sure to use hex or nsec.", + arg + ); + } + } else if arg == "--no-since-optimize" { + res.since_optimize = false; + } else if arg == "--filter" { + i += 1; + let filter = if let Some(next_arg) = args.get(i) { + next_arg + } else { + error!("filter argument missing?"); + continue; + }; + + if let Ok(filter) = Filter::from_json(filter) { + res.columns.push(ArgColumn::Generic(vec![filter])); + } else { + error!("failed to parse filter '{}'", filter); + } + } else if arg == "--dbpath" { + i += 1; + let path = if let Some(next_arg) = args.get(i) { + next_arg + } else { + error!("dbpath argument missing?"); + continue; + }; + res.dbpath = Some(path.clone()); + } else if arg == "-r" || arg == "--relay" { + i += 1; + let relay = if let Some(next_arg) = args.get(i) { + next_arg + } else { + error!("relay argument missing?"); + continue; + }; + res.relays.push(relay.clone()); + } else if arg == "--column" || arg == "-c" { + i += 1; + let column_name = if let Some(next_arg) = args.get(i) { + next_arg + } else { + error!("column argument missing"); + continue; + }; + + if let Some(rest) = column_name.strip_prefix("contacts:") { + if let Ok(pubkey) = Pubkey::parse(rest) { + info!("got contact column for user {}", pubkey.hex()); + res.columns.push(ArgColumn::Column(ColumnKind::contact_list( + PubkeySource::Explicit(pubkey), + ))) + } else { + error!("error parsing contacts pubkey {}", &column_name[9..]); + continue; + } + } else if column_name == "contacts" { + res.columns.push(ArgColumn::Column(ColumnKind::contact_list( + PubkeySource::DeckAuthor, + ))) + } + } else if arg == "--filter-file" || arg == "-f" { + i += 1; + let filter_file = if let Some(next_arg) = args.get(i) { + next_arg + } else { + error!("filter file argument missing?"); + continue; + }; + + let data = if let Ok(data) = std::fs::read(filter_file) { + data + } else { + error!("failed to read filter file '{}'", filter_file); + continue; + }; + + if let Some(filter) = std::str::from_utf8(&data) + .ok() + .and_then(|s| Filter::from_json(s).ok()) + { + res.columns.push(ArgColumn::Generic(vec![filter])); + } else { + error!("failed to parse filter in '{}'", filter_file); + } + } + + i += 1; + } + + if res.columns.is_empty() { + let ck = ColumnKind::contact_list(PubkeySource::DeckAuthor); + info!("No columns set, setting up defaults: {:?}", ck); + res.columns.push(ArgColumn::Column(ck)); + } + + res + } +} + +/// A way to define columns from the commandline. Can be column kinds or +/// generic queries +pub enum ArgColumn { + Column(ColumnKind), + Generic(Vec), +} + +impl ArgColumn { + pub fn into_timeline(self, ndb: &Ndb, user: Option<&[u8; 32]>) -> Timeline { + match self { + ArgColumn::Generic(filters) => Timeline::new(ColumnKind::Generic, Some(filters)), + + ArgColumn::Column(ColumnKind::Universe) => { + Timeline::new(ColumnKind::Universe, Some(vec![])) + } + + ArgColumn::Column(ColumnKind::Generic) => { + panic!("Not a valid ArgColumn") + } + + ArgColumn::Column(ColumnKind::List(ListKind::Contact(ref pk_src))) => { + let pk = match pk_src { + PubkeySource::DeckAuthor => { + if let Some(user_pk) = user { + user_pk + } else { + // No user loaded, so we have to return an unloaded + // contact list columns + return Timeline::new( + ColumnKind::contact_list(PubkeySource::DeckAuthor), + None, + ); + } + } + PubkeySource::Explicit(pk) => pk.bytes(), + }; + + let contact_filter = Filter::new().authors([pk]).kinds([3]).limit(1).build(); + let txn = Transaction::new(ndb).expect("txn"); + let results = ndb + .query(&txn, vec![contact_filter], 1) + .expect("contact query failed?"); + + if results.is_empty() { + return Timeline::new(ColumnKind::contact_list(pk_src.to_owned()), None); + } + + match Timeline::contact_list(&results[0].note) { + Err(Error::EmptyContactList) => { + Timeline::new(ColumnKind::contact_list(pk_src.to_owned()), None) + } + Err(e) => panic!("Unexpected error: {e}"), + Ok(tl) => tl, + } + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 2b2a326..373994a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,7 @@ pub mod account_manager; mod actionbar; pub mod app_creation; mod app_style; +mod args; mod colors; mod draft; mod filter;