aggligator_util/
lib.rs

1#![warn(missing_docs)]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc(
4    html_logo_url = "https://raw.githubusercontent.com/surban/aggligator/master/.misc/aggligator.png",
5    html_favicon_url = "https://raw.githubusercontent.com/surban/aggligator/master/.misc/aggligator.png",
6    issue_tracker_base_url = "https://github.com/surban/aggligator/issues/"
7)]
8
9//! Aggligator command line utilities.
10
11use anyhow::{bail, Context};
12use std::path::PathBuf;
13use tracing_subscriber::{fmt, prelude::*, EnvFilter};
14
15use aggligator::cfg::Cfg;
16use aggligator_transport_tcp::TcpLinkFilter;
17
18/// Initializes logging for command line utilities.
19pub fn init_log() {
20    tracing_subscriber::registry().with(fmt::layer()).with(EnvFilter::from_default_env()).init();
21    tracing_log::LogTracer::init().unwrap();
22}
23
24/// Prints the default Aggligator configuration.
25pub fn print_default_cfg() {
26    println!("{}", serde_json::to_string_pretty(&Cfg::default()).unwrap());
27}
28
29/// Loads an Aggligator configuration from disk or returns the default
30/// configuration if the path is empty.
31pub fn load_cfg(path: &Option<PathBuf>) -> anyhow::Result<Cfg> {
32    match path {
33        Some(path) => {
34            let file = std::fs::File::open(path).context("cannot open configuration file")?;
35            serde_json::from_reader(file).context("cannot parse configuration file")
36        }
37        None => Ok(Cfg::default()),
38    }
39}
40
41/// Parse [TcpLinkFilter] option.
42pub fn parse_tcp_link_filter(s: &str) -> anyhow::Result<TcpLinkFilter> {
43    match s {
44        "none" => Ok(TcpLinkFilter::None),
45        "interface-interface" => Ok(TcpLinkFilter::InterfaceInterface),
46        "interface-ip" => Ok(TcpLinkFilter::InterfaceIp),
47        other => bail!("unknown TCP link filter: {other}"),
48    }
49}
50
51/// Waits for a platform-specific termination signal.
52pub async fn wait_sigterm() {
53    #[cfg(unix)]
54    {
55        use tokio::signal::unix::{signal, SignalKind};
56
57        let mut sigterm = signal(SignalKind::terminate()).unwrap();
58        let mut sigint = signal(SignalKind::interrupt()).unwrap();
59        let mut sighup = signal(SignalKind::hangup()).unwrap();
60
61        tokio::select! {
62            _ = sigterm.recv() => {},
63            _ = sigint.recv() => {},
64            _ = sighup.recv() => {},
65        }
66    }
67
68    #[cfg(windows)]
69    {
70        use tokio::signal::windows;
71
72        let mut ctrl_c = windows::ctrl_c().unwrap();
73        let mut ctrl_break = windows::ctrl_break().unwrap();
74        let mut ctrl_close = windows::ctrl_close().unwrap();
75        let mut ctrl_logoff = windows::ctrl_logoff().unwrap();
76        let mut ctrl_shutdown = windows::ctrl_shutdown().unwrap();
77
78        tokio::select! {
79            _ = ctrl_c.recv() => {},
80            _ = ctrl_break.recv() => {},
81            _ = ctrl_close.recv() => {},
82            _ = ctrl_logoff.recv() => {},
83            _ = ctrl_shutdown.recv() => {},
84        }
85    }
86
87    #[cfg(not(any(unix, windows)))]
88    {
89        std::future::pending::<()>().await;
90    }
91
92    tracing::info!("received termination signal");
93}