doe 1.1.78

doe is a powerful Rust crate designed to enhance development workflow by providing an extensive collection of useful macros and utility functions. It not only simplifies common tasks but also offers convenient features for clipboard management,robust cryptographic functions,keyboard input, and mouse interaction.
Documentation
/// ip_addr mod
/// ```ignore
/// #[allow(warnings)]
/// fn main() {
///     let rt = doe::asyncrs::runtime::Builder::new_multi_thread()
///         .enable_all()
///         .build()
///         .unwrap();
///     rt.block_on(run());
///     rt.block_on(async {
///         run().await;
///     });
/// }
/// 
/// async fn run() {
///     use doe::logger::*;
///     doe::logger::init_info();
///     debug!("开始服务");
///     use doe::axumserver::response::Html;
///     use doe::axumserver::routing::get;
///     pub async fn home() -> Html<String> {
///         include_str!("../index.html").to_string().into()
///     }
///     let router = doe::axumserver::router_allow_cors().route("/", get(home));
///     doe::axumserver::server_app_default_ip(router, 60001)
///         .await
///         .unwrap();
///     // doe::axumserver::server_app( vec![IpAddr::from([127, 0, 0, 1])],router, 60001).await;
/// }
/// ```
///
#[allow(warnings)]
#[cfg(feature = "ip_addr")]
pub mod ip_addr {
    use anyhow::{Context, Result};
    use std::net::{IpAddr, SocketAddr, TcpListener as StdTcpListener};
    use tokio::net::TcpListener;
    
    #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
    pub enum BindAddr {
        IpAddr(IpAddr),
        #[cfg(unix)]
        SocketPath(String),
    }
    impl BindAddr {
        fn parse_addrs(addrs: &[&str]) -> Result<Vec<Self>> {
            let mut bind_addrs = vec![];
            #[cfg(not(unix))]
            let mut invalid_addrs = vec![];
            for addr in addrs {
                match addr.parse::<IpAddr>() {
                    Ok(v) => {
                        bind_addrs.push(BindAddr::IpAddr(v));
                    }
                    Err(_) => {
                        #[cfg(unix)]
                        bind_addrs.push(BindAddr::SocketPath(addr.to_string()));
                        #[cfg(not(unix))]
                        invalid_addrs.push(*addr);
                    }
                }
            }
            #[cfg(not(unix))]
            if !invalid_addrs.is_empty() {
                anyhow::bail!("Invalid bind address `{}`", invalid_addrs.join(","));
            }
            Ok(bind_addrs)
        }
    }
    pub fn interface_addrs() -> Result<(Vec<BindAddr>, Vec<BindAddr>)> {
        let (mut ipv4_addrs, mut ipv6_addrs) = (vec![], vec![]);
        let ifaces =
            if_addrs::get_if_addrs().with_context(|| "Failed to get local interface addresses")?;
        for iface in ifaces.into_iter() {
            let ip = iface.ip();
            if ip.is_ipv4() {
                ipv4_addrs.push(BindAddr::IpAddr(ip))
            }
            if ip.is_ipv6() {
                ipv6_addrs.push(BindAddr::IpAddr(ip))
            }
        }
        Ok((ipv4_addrs, ipv6_addrs))
    }
    
    pub async fn shutdown_signal() {
        tokio::signal::ctrl_c()
            .await
            .expect("Failed to install CTRL+C signal handler")
    }
    pub fn print_listening(print_addrs: &[BindAddr], port: u16) -> Result<String> {
        let mut output = String::new();
        let urls = print_addrs
            .iter()
            .map(|bind_addr| match bind_addr {
                BindAddr::IpAddr(addr) => {
                    let addr = match addr {
                        IpAddr::V4(_) => format!("{}:{}", addr, port),
                        IpAddr::V6(_) => format!("[{}]:{}", addr, port),
                    };
                    let protocol = "http";
                    format!("{}://{}", protocol, addr)
                }
                #[cfg(unix)]
                BindAddr::SocketPath(path) => path.to_string(),
            })
            .collect::<Vec<_>>();
    
        if urls.len() == 1 {
            output.push_str(&format!("Listening on {}", urls[0]))
        } else {
            let info = urls
                .iter()
                .map(|v| format!("  {v}"))
                .collect::<Vec<String>>()
                .join("\n");
            output.push_str(&format!("Listening on:\n{info}\n"))
        }
    
        Ok(output)
    }
    
    pub fn print_listening_with_protocol(print_addrs: &[BindAddr], port: u16,protocol:&str) -> Result<String> {
        let mut output = String::new();
        let urls = print_addrs
            .iter()
            .map(|bind_addr| match bind_addr {
                BindAddr::IpAddr(addr) => {
                    let addr = match addr {
                        IpAddr::V4(_) => format!("{}:{}", addr, port),
                        IpAddr::V6(_) => format!("[{}]:{}", addr, port),
                    };
                    format!("{}://{}", protocol, addr)
                }
                #[cfg(unix)]
                BindAddr::SocketPath(path) => path.to_string(),
            })
            .collect::<Vec<_>>();
    
        if urls.len() == 1 {
            output.push_str(&format!("Listening on {}", urls[0]))
        } else {
            let info = urls
                .iter()
                .map(|v| format!("  {v}"))
                .collect::<Vec<String>>()
                .join("\n");
            output.push_str(&format!("Listening on:\n{info}\n"))
        }
    
        Ok(output)
    }
    
    pub fn create_listener(addr: SocketAddr) -> Result<TcpListener> {
        use socket2::{Domain, Protocol, Socket, Type};
        let socket = Socket::new(Domain::for_address(addr), Type::STREAM, Some(Protocol::TCP))?;
        if addr.is_ipv6() {
            socket.set_only_v6(true)?;
        }
        socket.set_reuse_address(true)?;
        socket.bind(&addr.into())?;
        socket.listen(1024 /* Default backlog */)?;
        let std_listener = StdTcpListener::from(socket);
        std_listener.set_nonblocking(true)?;
        let listener = TcpListener::from_std(std_listener)?;
        Ok(listener)
    }
    
    pub fn get_addrs() -> Result<(Vec<BindAddr>, Vec<BindAddr>)> {
        let (ipv4_addrs, ipv6_addrs) = interface_addrs()?;
        Ok((ipv4_addrs, ipv6_addrs))
    }
    
}
#[cfg(feature = "ip_addr")]
pub use ip_addr::*;