panorama/daemon/src/main.rs
2021-08-09 06:50:32 -05:00

115 lines
2.8 KiB
Rust

#[macro_use]
extern crate serde;
#[macro_use]
extern crate anyhow;
#[macro_use]
extern crate log;
#[macro_use]
extern crate futures;
mod config;
mod mail;
use anyhow::Result;
use clap::Clap;
use futures::future::{
select,
Either::{Left, Right},
FutureExt,
};
use panorama_imap::client::ConfigBuilder;
use tokio::sync::oneshot;
use crate::config::{Config, MailAccountConfig, TlsMethod};
type ExitListener = oneshot::Receiver<()>;
/// The panorama daemon runs in the background and communicates with other
/// panorama components over Unix sockets.
#[derive(Debug, Clap)]
struct Options {
// /// Config file path (defaults to XDG)
// #[clap(long = "config", short = 'c')]
// config_file: Option<PathBuf>,
/// Verbose mode (-v, -vv, -vvv, etc)
#[clap(short = 'v', long = "verbose", parse(from_occurrences))]
verbose: usize,
}
#[tokio::main]
async fn main() -> Result<()> {
let opt = Options::parse();
stderrlog::new()
.module(module_path!())
.verbosity(opt.verbose)
.init()
.unwrap();
let (_, mut config_watcher) = config::spawn_config_watcher_system()?;
loop {
let (exit_tx, exit_rx) = oneshot::channel();
let new_config = config_watcher.borrow().clone();
tokio::spawn(run_with_config(new_config, exit_rx));
// wait till the config has changed, then tell the current thread to stop
config_watcher.changed().await?;
let _ = exit_tx.send(());
}
}
async fn run_with_config(config: Config, exit: ExitListener) -> Result<()> {
debug!("new config");
let mut notify_mail_threads = Vec::new();
for (account_name, account) in config.mail_accounts {
let (exit_tx, exit_rx) = oneshot::channel();
tokio::spawn(run_single_mail_account(account_name, account, exit_rx));
notify_mail_threads.push(exit_tx);
}
exit.await?;
for exit_tx in notify_mail_threads {
let _ = exit_tx.send(());
}
Ok(())
}
async fn run_single_mail_account(
account_name: String,
account: MailAccountConfig,
exit: ExitListener,
) -> Result<()> {
debug!("connecting to account {}", account_name);
// set up the connection
let mut builder = ConfigBuilder::default();
let imap_cookie = builder
.hostname(account.imap.server.clone())
.port(account.imap.port)
.tls(matches!(account.imap.tls, TlsMethod::On))
.open();
pin_mut!(imap_cookie);
pin_mut!(exit);
let (imap, exit) = match select(imap_cookie, exit).await {
Left(res) => res,
Right(_) => return Ok(()),
};
debug!("connected to {}", account.imap.server);
let _imap = imap?;
let mut exit = exit.fuse();
loop {
select! {
_ = exit => break,
}
}
debug!("disconnecting from account {}", account_name);
Ok(())
}