dhomer 0.1.0

Simple and easy to use, a proxy server based on Pingora
use lazy_static::lazy_static;
use std::{
    net::{SocketAddr, ToSocketAddrs},
    vec,
};

use regex::Regex;
use serde::Serialize;
use snafu::OptionExt;

use super::Result;
use crate::config::error::{Error, InvalidAddressSnafu};

lazy_static! {
    static ref DOMAIN_PORT_REGEX: Regex =
        Regex::new(r"^([a-zA-Z0-9.-]+):(\d+)$").expect("Failed to compile regex");
}

#[derive(Hash, PartialEq, Eq, Debug, Serialize)]
pub struct Address(String, u16);

impl Address {
    pub fn new(s: String) -> Result<Self> {
        // 使用?操作符简化错误传递,当匹配失败时直接返回错误
        let caps = DOMAIN_PORT_REGEX
            .captures(&s)
            .context(InvalidAddressSnafu { s: s.clone() })?;

        // 提取域名并转换为String
        let domain = caps
            .get(1)
            .context(InvalidAddressSnafu { s: s.clone() })?
            .as_str()
            .to_string();

        // 提取端口并转换为u16,同时捕获解析错误
        let port = caps
            .get(2)
            .context(InvalidAddressSnafu { s: s.clone() })?
            .as_str()
            .parse()
            .map_err(|_| Error::InvalidAddress { s })?;

        Ok(Self(domain, port))
    }
}

impl TryFrom<String> for Address {
    type Error = Error;

    fn try_from(value: String) -> std::result::Result<Self, Self::Error> {
        Self::new(value)
    }
}

impl From<Address> for String {
    fn from(value: Address) -> Self {
        format!("{}:{}", value.0, value.1)
    }
}

impl ToSocketAddrs for Address {
    type Iter = vec::IntoIter<SocketAddr>;

    fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
        let pair = (self.0.clone(), self.1);
        pair.to_socket_addrs()
    }
}