99 lines
3 KiB
Rust
99 lines
3 KiB
Rust
use crate::config;
|
|
use clap::{ArgAction, Args, Parser, Subcommand};
|
|
use eyre::ensure;
|
|
use futures::future::try_join_all;
|
|
use listenfd::ListenFd;
|
|
|
|
use std::{future::Future, net::TcpListener, os::unix::net::UnixListener, path::PathBuf, pin::Pin};
|
|
|
|
#[derive(Parser, Debug)]
|
|
pub struct CLI {
|
|
#[arg(long, value_name = "path/to/config.toml")]
|
|
pub config: config::Config,
|
|
#[command(subcommand)]
|
|
pub subcommand: CLISubcommand,
|
|
}
|
|
|
|
impl CLI {
|
|
pub async fn resolve(&mut self, listenfd: &mut ListenFd) -> eyre::Result<()> {
|
|
let mut futures: Vec<Pin<Box<dyn Future<Output = eyre::Result<()>> + Send>>> = vec![];
|
|
let resolve_provider_metadata;
|
|
match &mut self.subcommand {
|
|
CLISubcommand::Serve { listen } => {
|
|
resolve_provider_metadata = true;
|
|
futures.push(Box::pin(listen.resolve(listenfd)));
|
|
}
|
|
CLISubcommand::GenerateUnsubscribeUrls { emails: _ } => {
|
|
resolve_provider_metadata = false;
|
|
}
|
|
}
|
|
futures.push(Box::pin(self.config.resolve(resolve_provider_metadata)));
|
|
try_join_all(futures).await?;
|
|
if resolve_provider_metadata {
|
|
log::info!("retrieved config from auth servers");
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Subcommand, Debug)]
|
|
pub enum CLISubcommand {
|
|
Serve {
|
|
#[command(flatten)]
|
|
listen: Listen,
|
|
},
|
|
GenerateUnsubscribeUrls {
|
|
emails: Vec<String>,
|
|
},
|
|
}
|
|
|
|
#[derive(Args, Debug)]
|
|
#[group(required = true)]
|
|
pub struct Listen {
|
|
#[arg(long, value_name = "HOST:PORT")]
|
|
pub listen_tcp: Vec<String>,
|
|
#[arg(long, value_name = "path/to/socket.sock")]
|
|
pub listen_unix: Vec<PathBuf>,
|
|
#[arg(long, action = ArgAction::SetTrue, default_missing_value = "", value_parser = |_: &str| Ok::<_, String>(ListenFdSockets(vec![])))]
|
|
pub listen_fd: Option<ListenFdSockets>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct ListenFdSockets(pub Vec<ListenFdSocket>);
|
|
|
|
impl Clone for ListenFdSockets {
|
|
fn clone(&self) -> Self {
|
|
panic!("not clonable")
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum ListenFdSocket {
|
|
Tcp(TcpListener),
|
|
Unix(UnixListener),
|
|
}
|
|
|
|
impl Listen {
|
|
pub async fn resolve(&mut self, listenfd: &mut ListenFd) -> eyre::Result<()> {
|
|
if let Some(listen_fd_sockets) = &mut self.listen_fd {
|
|
ensure!(
|
|
listenfd.len() != 0,
|
|
"no file descriptor passed in through LISTEN_FDS systemd protocol"
|
|
);
|
|
for index in 0..listenfd.len() {
|
|
let mut result = listenfd
|
|
.take_tcp_listener(index)
|
|
.transpose()
|
|
.expect("fds not yet taken")
|
|
.map(ListenFdSocket::Tcp);
|
|
if result.is_err() {
|
|
if let Ok(Some(v)) = listenfd.take_unix_listener(index) {
|
|
result = Ok(ListenFdSocket::Unix(v));
|
|
}
|
|
}
|
|
listen_fd_sockets.0.push(result?);
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|