use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProxyAddr {
pub host: String,
pub port: u16,
}
impl ProxyAddr {
pub fn new(host: impl Into<String>, port: u16) -> Self {
Self { host: host.into(), port }
}
pub fn parse(s: &str) -> Result<Self, crate::McError> {
match s.rsplit_once(':') {
Some((h, p)) => {
let port = p.parse::<u16>()
.map_err(|e| crate::McError::invalid_port(e.to_string()))?;
Ok(Self::new(h, port))
}
None => Err(crate::McError::invalid_address(
format!("proxy address must be 'host:port', got '{s}'")
)),
}
}
}
impl fmt::Display for ProxyAddr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.host, self.port)
}
}
#[derive(Clone)]
pub struct ProxyAuth {
pub username: String,
pub password: String,
}
impl fmt::Debug for ProxyAuth {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ProxyAuth")
.field("username", &self.username)
.field("password", &"***")
.finish()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum UdpSupport {
#[default]
No,
Yes,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProxyKind {
Socks5,
Http,
}
#[derive(Debug, Clone)]
pub struct ProxyConfig {
pub(crate) addr: ProxyAddr,
pub(crate) auth: Option<ProxyAuth>,
pub(crate) kind: ProxyKind,
pub(crate) udp_support: UdpSupport,
}
impl ProxyConfig {
pub fn socks5(addr: impl AsRef<str>) -> Self {
Self {
addr: ProxyAddr::parse(addr.as_ref())
.expect("invalid proxy address — use 'host:port'"),
auth: None,
kind: ProxyKind::Socks5,
udp_support: UdpSupport::No,
}
}
pub fn socks5_with_udp(addr: impl AsRef<str>) -> Self {
Self {
addr: ProxyAddr::parse(addr.as_ref())
.expect("invalid proxy address — use 'host:port'"),
auth: None,
kind: ProxyKind::Socks5,
udp_support: UdpSupport::Yes,
}
}
pub fn http(addr: impl AsRef<str>) -> Self {
Self {
addr: ProxyAddr::parse(addr.as_ref())
.expect("invalid proxy address — use 'host:port'"),
auth: None,
kind: ProxyKind::Http,
udp_support: UdpSupport::No, }
}
pub fn with_auth(mut self, username: impl Into<String>, password: impl Into<String>) -> Self {
self.auth = Some(ProxyAuth {
username: username.into(),
password: password.into(),
});
self
}
pub fn addr(&self) -> &ProxyAddr { &self.addr }
pub fn auth(&self) -> Option<&ProxyAuth> { self.auth.as_ref() }
pub fn kind(&self) -> ProxyKind { self.kind }
pub fn udp_support(&self) -> UdpSupport { self.udp_support }
}