This repository has been archived on 2025-08-14. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
subscribe-list/src/cli.rs
2024-04-08 23:39:40 -07:00

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(())
}
}