#[derive(serde::Deserialize, serde::Serialize, Debug, Clone, PartialEq, Eq, Hash)]
pub enum ProxyKind {
Socks5,
Socks4,
Http,
Https,
}
#[derive(serde::Deserialize, serde::Serialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct Proxy {
pub kind: ProxyKind,
pub addr: String,
pub port: u16,
pub creds: Option<(String, String)>,
#[serde(skip_serializing_if = "Option::is_none")]
pub refresh_url: Option<String>,
}
impl Proxy {
pub fn is_dns_addr(&self) -> bool {
self.addr.chars().any(char::is_alphabetic)
}
pub fn is_ip_addr(&self) -> bool {
!self.is_dns_addr()
}
pub async fn connect_tcp(&self, target: NetworkTarget) -> Result<TcpStream, ConnectError> {
connect::connect(self, target).await
}
}
#[cfg(feature = "reqwest")]
mod reqwest_helpers {
use super::Proxy;
pub trait ProxifyClient {
fn proxify(self, client: reqwest::ClientBuilder) -> reqwest::ClientBuilder;
}
#[cfg(feature = "reqwest")]
impl Into<reqwest::Proxy> for Proxy {
fn into(self) -> reqwest::Proxy {
let url = format!("{}://{}:{}", self.kind.to_string(), &self.addr, self.port);
let mut proxy =
reqwest::Proxy::all(url).expect("Structure provides fixed format, never crashed");
if let Some((username, password)) = self.creds {
proxy = proxy.basic_auth(&username, &password);
}
proxy
}
}
impl ProxifyClient for Proxy {
fn proxify(self, client: reqwest::ClientBuilder) -> reqwest::ClientBuilder {
client.proxy(self.into())
}
}
impl ProxifyClient for Option<Proxy> {
fn proxify(self, client: reqwest::ClientBuilder) -> reqwest::ClientBuilder {
match self {
Some(proxy) => proxy.proxify(client),
None => client,
}
}
}
}
#[cfg(feature = "reqwest")]
pub use reqwest_helpers::*;
pub mod parse;
mod connect;
pub use connect::{ConnectError, NetworkTarget};
use tokio::net::TcpStream;