123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- //#![allow(unused)]
- #![allow(incomplete_features)]
- #![feature(impl_trait_in_bindings)]
- #![feature(async_closure)]
-
- use std::collections::*;
- use std::path::PathBuf;
-
- use argh::FromArgs;
-
- use tokio::runtime;
- use tokio::sync::mpsc;
-
- mod client;
- mod config;
- mod spool;
-
- use crate::config::*;
-
- #[derive(FromArgs, PartialEq, Debug)]
- #[argh(description = "mtxspooler")]
- struct Opts {
- #[argh(
- option,
- short = 'c',
- description = "read this config file by itself, parsed before -C"
- )]
- conf: Option<PathBuf>,
-
- #[argh(
- option,
- short = 'C',
- description = "read all config files in this directory"
- )]
- conf_dir: Option<PathBuf>,
-
- #[argh(
- option,
- short = 'r',
- description = "delete this file to trigger a config reload [NYI]"
- )]
- reload_trigger: Option<PathBuf>,
- }
-
- fn main() {
- let opts: Opts = argh::from_env();
- if opts.reload_trigger.is_some() {
- eprintln!("[init] warning: reload trigger file specified, but this option is not supported yet, ignoring...");
- }
-
- let mut rt = make_runtime();
- rt.block_on(main_inner(opts));
- }
-
- async fn main_inner(opts: Opts) {
- // Figure out which files we want to configure.
- let mut confs = Vec::new();
- if let Some(main) = opts.conf {
- confs.push(main.clone());
- }
- if let Some(dir) = opts.conf_dir {
- match find_configs(&dir).await {
- Ok(paths) => confs.extend(paths),
- Err(e) => {
- eprintln!("[init] error reading configuration: {:?}", e);
- return;
- }
- }
- }
-
- // Sanity check.
- if confs.len() == 0 {
- println!("[init] no configuration declared, exiting...");
- return;
- }
-
- // Process configuration.
- // TODO Remove all these cases of `block_on` except for a final toplevel task.
- let config = match parse_configs(&confs).await {
- Ok(c) => c,
- Err(e) => {
- eprintln!("[init] error parsing configuration: {:?}", e);
- return; // maybe
- }
- };
-
- let mut clients = HashMap::new();
- let mut sender_futs = Vec::new();
-
- // Init each account and put outgoing channels into a table for later reference.
- for cc in config.accounts.iter() {
- match client::create_and_auth_client(cc.1.clone()).await {
- Ok(c) => {
- let (send, recv) = mpsc::channel(2); // FIXME configurable
- clients.insert(cc.0.clone(), send);
- sender_futs.push(client::submit_messages(c, recv));
- }
- Err(e) => {
- eprintln!("[init] error: client setup failed: {:?}", e);
- return; // maybe
- }
- }
- }
-
- // This is where the real stuff actually happens.
- match spool::start_spoolers(config, clients).await {
- Ok(_) => {}
- Err(e) => println!("fatal error: {:?}", e),
- }
-
- // just wait I guess?
- futures::future::join_all(sender_futs.into_iter()).await;
- }
-
- fn make_runtime() -> runtime::Runtime {
- runtime::Builder::new_current_thread()
- .thread_name("mtxspooler-worker")
- .enable_all()
- .build()
- .expect("rt: init")
- }
|