#![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 log::LevelFilter; use crate::store::{NewGroupOptions, StoreOptions}; use crate::utils::acct_to_server; mod command; mod error; #[macro_use] mod group_handler; mod store; mod utils; #[macro_use] mod tr; #[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("quiet") .short("q") .multiple(true) .help("decrease logging, can be repeated"), ) .arg( Arg::with_name("config") .short("c") .long("config") .takes_value(true) .help("set custom config directory, defaults to the current folder"), ) .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] = [ LevelFilter::Error, LevelFilter::Warn, LevelFilter::Info, LevelFilter::Debug, LevelFilter::Trace, ]; let default_level = 3; let level = (default_level as isize + args.occurrences_of("verbose") as isize - args.occurrences_of("quiet") as isize) .clamp(0, LEVELS.len() as isize) as usize; env_logger::Builder::new() .filter_level(LEVELS[level]) .write_style(env_logger::WriteStyle::Always) .filter_module("rustls", LevelFilter::Warn) .filter_module("reqwest", LevelFilter::Warn) .filter_module("tungstenite", LevelFilter::Warn) .filter_module("tokio_tungstenite", LevelFilter::Warn) .filter_module("tokio_util", LevelFilter::Warn) .filter_module("want", LevelFilter::Warn) .filter_module("mio", LevelFilter::Warn) .init(); let mut store = store::ConfigStore::load_from_fs(StoreOptions { store_dir: args.value_of("config").unwrap_or(".").to_string(), }) .await?; if let Some(handle) = args.value_of("auth") { let handle = handle.to_lowercase(); let acct = handle.trim_start_matches('@'); if store.group_exists(acct).await { anyhow::bail!("Group already exists in config!"); } if let Some(server) = acct_to_server(acct) { store .auth_new_group(NewGroupOptions { server: format!("https://{}", server), acct: acct.to_string(), }) .await?; eprintln!("New group added to config!"); 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('@'); store.reauth_group(acct).await?; eprintln!("Group @{} re-authed!", acct); return Ok(()); } store.find_locales().await; // Start let groups = store.spawn_groups().await?; let mut handles = vec![]; for mut g in groups { handles.push(tokio::spawn(async move { match g.run().await { Ok(()) => unreachable!(), Err(e) => error!("GROUP FAILED! {}", e), } })); } futures::future::join_all(handles).await; eprintln!("Main loop ended!"); Ok(()) }