|
|
|
#![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;
|
|
|
|
mod group_handler;
|
|
|
|
mod store;
|
|
|
|
mod utils;
|
|
|
|
|
|
|
|
#[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)
|
|
|
|
.init();
|
|
|
|
|
|
|
|
let 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) {
|
|
|
|
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 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(())
|
|
|
|
}
|