use crate::handle::{ClientHandle, ServerHandle}; use crate::target_configure::{ClientTargetConfig, ServerTargetConfig}; use serde::{Deserialize, Serialize}; use std::{ fmt::{Display, Formatter}, marker::PhantomData, net::{AddrParseError, IpAddr, Ipv4Addr, SocketAddr}, str::FromStr, }; use tokio::net::lookup_host; const DEFAULT_PORT: u16 = 8080; #[derive(Debug, Serialize, Deserialize)] pub struct TcpServerTarget where Client: ClientHandle, Server: ServerHandle, { /// Client Config client_cfg: Option, /// Server Config server_cfg: Option, /// Server port port: u16, /// Bind addr bind_addr: IpAddr, /// Client Phantom Data _client: PhantomData, /// Server Phantom Data _server: PhantomData, } impl Default for TcpServerTarget where Client: ClientHandle, Server: ServerHandle, { fn default() -> Self { Self { client_cfg: None, server_cfg: None, port: DEFAULT_PORT, bind_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), _client: PhantomData, _server: PhantomData, } } } impl From for TcpServerTarget where Client: ClientHandle, Server: ServerHandle, { /// Convert SocketAddr to TcpServerTarget fn from(value: SocketAddr) -> Self { Self { port: value.port(), bind_addr: value.ip(), ..Self::default() } } } impl From> for SocketAddr where Client: ClientHandle, Server: ServerHandle, { /// Convert TcpServerTarget to SocketAddr fn from(val: TcpServerTarget) -> Self { SocketAddr::new(val.bind_addr, val.port) } } impl Display for TcpServerTarget where Client: ClientHandle, Server: ServerHandle, { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}:{}", self.bind_addr, self.port) } } impl TcpServerTarget where Client: ClientHandle, Server: ServerHandle, { /// Create target by address pub fn from_addr(addr: impl Into, port: impl Into) -> Self { Self { port: port.into(), bind_addr: addr.into(), ..Self::default() } } /// Try to create target by string pub fn from_str<'a>(addr_str: impl Into<&'a str>) -> Result { let socket_addr = SocketAddr::from_str(addr_str.into()); match socket_addr { Ok(socket_addr) => Ok(Self::from_addr(socket_addr.ip(), socket_addr.port())), Err(err) => Err(err), } } /// Try to create target by domain name pub async fn from_domain<'a>(domain: impl Into<&'a str>) -> Result { match domain_to_addr(domain).await { Ok(domain_addr) => Ok(Self::from(domain_addr)), Err(e) => Err(e), } } /// Set client config pub fn client_cfg(mut self, config: ClientTargetConfig) -> Self { self.client_cfg = Some(config); self } /// Set server config pub fn server_cfg(mut self, config: ServerTargetConfig) -> Self { self.server_cfg = Some(config); self } /// Add client config pub fn add_client_cfg(&mut self, config: ClientTargetConfig) { self.client_cfg = Some(config); } /// Add server config pub fn add_server_cfg(&mut self, config: ServerTargetConfig) { self.server_cfg = Some(config); } /// Get client config ref pub fn get_client_cfg(&self) -> Option<&ClientTargetConfig> { self.client_cfg.as_ref() } /// Get server config ref pub fn get_server_cfg(&self) -> Option<&ServerTargetConfig> { self.server_cfg.as_ref() } /// Get SocketAddr of TcpServerTarget pub fn get_addr(&self) -> SocketAddr { SocketAddr::new(self.bind_addr, self.port) } } /// Parse Domain Name to IpAddr via DNS async fn domain_to_addr<'a>(domain: impl Into<&'a str>) -> Result { let domain = domain.into(); let default_port: u16 = DEFAULT_PORT; if let Ok(socket_addr) = domain.parse::() { return Ok(match socket_addr.ip() { IpAddr::V4(_) => socket_addr, IpAddr::V6(_) => SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), socket_addr.port()), }); } if let Ok(_v6_addr) = domain.parse::() { return Ok(SocketAddr::new( IpAddr::V4(Ipv4Addr::LOCALHOST), default_port, )); } let (host, port_str) = if let Some((host, port)) = domain.rsplit_once(':') { (host.trim_matches(|c| c == '[' || c == ']'), Some(port)) } else { (domain, None) }; let port = port_str .and_then(|p| p.parse::().ok()) .map(|p| p.clamp(0, u16::MAX)) .unwrap_or(default_port); let mut socket_iter = lookup_host((host, 0)).await?; if let Some(addr) = socket_iter.find(|addr| addr.is_ipv4()) { return Ok(SocketAddr::new(addr.ip(), port)); } Ok(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port)) }