#![deny(unused_must_use)] extern crate elefren; #[macro_use] extern crate log; #[macro_use] extern crate serde; #[macro_use] extern crate smart_default; #[macro_use] extern crate thiserror; use clap::Arg; use elefren::{FediClient, Registration, Scopes, StatusBuilder}; use elefren::debug::NotificationDisplay; use elefren::entities::account::Account; use elefren::entities::event::Event; use elefren::entities::notification::NotificationType; use elefren::scopes; use elefren::status_builder::Visibility; use log::LevelFilter; use tokio_stream::{Stream, StreamExt}; use crate::store::{NewGroupOptions, StoreOptions}; use crate::utils::acct_to_server; mod store; mod group_handle; mod utils; mod command; mod error; #[tokio::main] async fn main() -> anyhow::Result<()> { let args = clap::App::new("groups") .arg(Arg::with_name("verbose") .short("v") .multiple(true) .help("increase logging, can be repeated")) .arg(Arg::with_name("config") .short("c") .long("config") .takes_value(true) .help("set custom storage file, defaults to groups.json")) .arg(Arg::with_name("auth") .short("a") .long("auth") .takes_value(true) .value_name("HANDLE") .help("authenticate to a new server (always using https)")) .arg(Arg::with_name("reauth") .short("A") .long("reauth") .takes_value(true) .value_name("HANDLE") .help("authenticate to a new server (always using https)")) .get_matches(); const LEVELS : [LevelFilter; 5] = [ /// Corresponds to the `Error` log level. LevelFilter::Error, /// Corresponds to the `Warn` log level. LevelFilter::Warn, /// Corresponds to the `Info` log level. LevelFilter::Info, /// Corresponds to the `Debug` log level. LevelFilter::Debug, /// Corresponds to the `Trace` log level. LevelFilter::Trace, ]; let default_level = 2; let level = (default_level + args.occurrences_of("verbose") as usize).min(LEVELS.len()); env_logger::Builder::new() .filter_level(LEVELS[level]) .write_style(env_logger::WriteStyle::Always) .filter_module("rustls", LevelFilter::Warn) .filter_module("reqwest", LevelFilter::Warn) .init(); let store = store::ConfigStore::new(StoreOptions { store_path: args.value_of("config").unwrap_or("groups.json").to_string(), save_pretty: true, }).await?; if let Some(handle) = args.value_of("auth") { let acct = handle.trim_start_matches('@'); if let Some(server) = acct_to_server(acct) { let g = store.auth_new_group(NewGroupOptions { server: format!("https://{}", server), acct: acct.to_string() }).await?; eprintln!("New group @{} added to config!", g.config.get_acct()); return Ok(()); } else { anyhow::bail!("--auth handle must be username@server, got: \"{}\"", handle); } } if let Some(acct) = args.value_of("reauth") { let acct = acct.trim_start_matches('@'); let _ = store.reauth_group(acct).await?; eprintln!("Group @{} re-authed!", acct); return Ok(()); } // Start let mut groups = store.spawn_groups().await; let mut handles = vec![]; for mut g in groups { handles.push(tokio::spawn(async move { g.run().await })); } futures::future::join_all(handles).await; eprintln!("Main loop ended!"); Ok(()) }