notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

args.rs (6116B)


      1 use notedeck::FilterState;
      2 
      3 use crate::timeline::{PubkeySource, Timeline, TimelineKind, TimelineTab};
      4 use enostr::{Filter, Pubkey};
      5 use nostrdb::Ndb;
      6 use tracing::{debug, error, info};
      7 
      8 pub struct ColumnsArgs {
      9     pub columns: Vec<ArgColumn>,
     10     pub since_optimize: bool,
     11     pub textmode: bool,
     12 }
     13 
     14 impl ColumnsArgs {
     15     pub fn parse(args: &[String]) -> Self {
     16         let mut res = Self {
     17             columns: vec![],
     18             since_optimize: true,
     19             textmode: false,
     20         };
     21 
     22         let mut i = 0;
     23         let len = args.len();
     24         while i < len {
     25             let arg = &args[i];
     26 
     27             if arg == "--textmode" {
     28                 res.textmode = true;
     29             } else if arg == "--no-since-optimize" {
     30                 res.since_optimize = false;
     31             } else if arg == "--filter" {
     32                 i += 1;
     33                 let filter = if let Some(next_arg) = args.get(i) {
     34                     next_arg
     35                 } else {
     36                     error!("filter argument missing?");
     37                     continue;
     38                 };
     39 
     40                 if let Ok(filter) = Filter::from_json(filter) {
     41                     res.columns.push(ArgColumn::Generic(vec![filter]));
     42                 } else {
     43                     error!("failed to parse filter '{}'", filter);
     44                 }
     45             } else if arg == "--column" || arg == "-c" {
     46                 i += 1;
     47                 let column_name = if let Some(next_arg) = args.get(i) {
     48                     next_arg
     49                 } else {
     50                     error!("column argument missing");
     51                     continue;
     52                 };
     53 
     54                 if let Some(rest) = column_name.strip_prefix("contacts:") {
     55                     if let Ok(pubkey) = Pubkey::parse(rest) {
     56                         info!("contact column for user {}", pubkey.hex());
     57                         res.columns
     58                             .push(ArgColumn::Timeline(TimelineKind::contact_list(
     59                                 PubkeySource::Explicit(pubkey),
     60                             )))
     61                     } else {
     62                         error!("error parsing contacts pubkey {}", rest);
     63                         continue;
     64                     }
     65                 } else if column_name == "contacts" {
     66                     res.columns
     67                         .push(ArgColumn::Timeline(TimelineKind::contact_list(
     68                             PubkeySource::DeckAuthor,
     69                         )))
     70                 } else if let Some(notif_pk_str) = column_name.strip_prefix("notifications:") {
     71                     if let Ok(pubkey) = Pubkey::parse(notif_pk_str) {
     72                         info!("got notifications column for user {}", pubkey.hex());
     73                         res.columns
     74                             .push(ArgColumn::Timeline(TimelineKind::notifications(
     75                                 PubkeySource::Explicit(pubkey),
     76                             )))
     77                     } else {
     78                         error!("error parsing notifications pubkey {}", notif_pk_str);
     79                         continue;
     80                     }
     81                 } else if column_name == "notifications" {
     82                     debug!("got notification column for default user");
     83                     res.columns
     84                         .push(ArgColumn::Timeline(TimelineKind::notifications(
     85                             PubkeySource::DeckAuthor,
     86                         )))
     87                 } else if column_name == "profile" {
     88                     debug!("got profile column for default user");
     89                     res.columns.push(ArgColumn::Timeline(TimelineKind::profile(
     90                         PubkeySource::DeckAuthor,
     91                     )))
     92                 } else if column_name == "universe" {
     93                     debug!("got universe column");
     94                     res.columns
     95                         .push(ArgColumn::Timeline(TimelineKind::Universe))
     96                 } else if let Some(profile_pk_str) = column_name.strip_prefix("profile:") {
     97                     if let Ok(pubkey) = Pubkey::parse(profile_pk_str) {
     98                         info!("got profile column for user {}", pubkey.hex());
     99                         res.columns.push(ArgColumn::Timeline(TimelineKind::profile(
    100                             PubkeySource::Explicit(pubkey),
    101                         )))
    102                     } else {
    103                         error!("error parsing profile pubkey {}", profile_pk_str);
    104                         continue;
    105                     }
    106                 }
    107             } else if arg == "--filter-file" || arg == "-f" {
    108                 i += 1;
    109                 let filter_file = if let Some(next_arg) = args.get(i) {
    110                     next_arg
    111                 } else {
    112                     error!("filter file argument missing?");
    113                     continue;
    114                 };
    115 
    116                 let data = if let Ok(data) = std::fs::read(filter_file) {
    117                     data
    118                 } else {
    119                     error!("failed to read filter file '{}'", filter_file);
    120                     continue;
    121                 };
    122 
    123                 if let Some(filter) = std::str::from_utf8(&data)
    124                     .ok()
    125                     .and_then(|s| Filter::from_json(s).ok())
    126                 {
    127                     res.columns.push(ArgColumn::Generic(vec![filter]));
    128                 } else {
    129                     error!("failed to parse filter in '{}'", filter_file);
    130                 }
    131             }
    132 
    133             i += 1;
    134         }
    135 
    136         res
    137     }
    138 }
    139 
    140 /// A way to define columns from the commandline. Can be column kinds or
    141 /// generic queries
    142 #[derive(Debug)]
    143 pub enum ArgColumn {
    144     Timeline(TimelineKind),
    145     Generic(Vec<Filter>),
    146 }
    147 
    148 impl ArgColumn {
    149     pub fn into_timeline(self, ndb: &Ndb, user: Option<&[u8; 32]>) -> Option<Timeline> {
    150         match self {
    151             ArgColumn::Generic(filters) => Some(Timeline::new(
    152                 TimelineKind::Generic,
    153                 FilterState::ready(filters),
    154                 TimelineTab::full_tabs(),
    155             )),
    156             ArgColumn::Timeline(tk) => tk.into_timeline(ndb, user),
    157         }
    158     }
    159 }