mod acme;
mod reps;
mod session;
mod talk;
use async_std::{channel::unbounded, stream::StreamExt};
use futures::{select, stream::FuturesUnordered, FutureExt};
use log::*;
#[async_std::main]
async fn main() {
env_logger::init();
let bind = std::env::var("LISTEN_ON").unwrap_or("localhost:0".to_owned());
let domains = std::env::var("DOMAIN")
.unwrap_or_else(|_| {
bind.rsplit_once(":")
.map(|(host, _port)| host.to_owned())
.unwrap_or(bind.clone())
})
.split(",")
.map(|s| s.to_owned())
.collect::<Vec<_>>();
let contact = std::env::var("CONTACT").ok();
let prod = std::env::var("ENV") == Ok("production".to_owned());
let mut works = FuturesUnordered::new();
info!("Binding {bind} for domains {domains:?}, ACME contact {contact:?}, prod: {prod}");
loop {
let (todo_tx, todo_rx) = unbounded();
let (rep_tx, rep_rx) = unbounded();
let (ban_tx, ban_rx) = unbounded();
let (cert_tx, cert_rx) = unbounded();
let mut reps = Box::pin(reps::reps(rep_rx, ban_tx)).fuse();
let mut talk = Box::pin(talk::talk(
bind.clone(),
todo_tx,
rep_tx,
ban_rx,
talk::new_certs(domains.clone(), cert_rx),
))
.fuse();
let mut acme = Box::pin(acme::acme(
prod,
&bind,
&domains,
contact.as_ref(),
cert_tx.clone(),
None ))
.fuse();
loop {
select! {
_ = acme => {}
res = talk => res.expect("processing"),
todo = todo_rx.recv().fuse() => if let Ok(fut) = todo { works.push(fut) },
_ = reps => break,
_ = (&mut works).for_each(|_|{}).fuse() => {
}
}
}
}
}