diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index feb9cb83c..22bd5c411 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,8 +30,8 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Run cargo check run: cargo check --all --all-features -# - name Run cargo clippy -# run: cargo clippy --all --all-features + - name: Run cargo clippy + run: cargo clippy --all --all-features -- -D warnings - name: Run cargo test run: cargo test --all --all-features diff --git a/clash_lib/src/app/api/handlers/config.rs b/clash_lib/src/app/api/handlers/config.rs index f4f33d5e8..746cb3cea 100644 --- a/clash_lib/src/app/api/handlers/config.rs +++ b/clash_lib/src/app/api/handlers/config.rs @@ -99,7 +99,7 @@ async fn update_configs( let g = state.global_state.lock().await; match (req.path, req.payload) { (_, Some(payload)) => { - let msg = format!("config reloading from payload"); + let msg = "config reloading from payload".to_string(); let cfg = crate::Config::Str(payload); match g.reload_tx.send(cfg).await { Ok(_) => (StatusCode::ACCEPTED, msg).into_response(), @@ -208,10 +208,9 @@ async fn patch_configs( inbound_manager.rebuild_listeners(ports); - global_state + if let Some(h) = global_state .inbound_listener_handle - .take() - .map(|h| h.abort()); + .take() { h.abort() } let r = inbound_manager.get_runner().unwrap(); diff --git a/clash_lib/src/app/api/handlers/provider.rs b/clash_lib/src/app/api/handlers/provider.rs index fc824bafa..e0534e81f 100644 --- a/clash_lib/src/app/api/handlers/provider.rs +++ b/clash_lib/src/app/api/handlers/provider.rs @@ -107,7 +107,7 @@ async fn update_provider( format!( "update proxy provider {} failed with error {}", provider.name(), - err.to_string() + err ), ) .into_response(), diff --git a/clash_lib/src/app/api/mod.rs b/clash_lib/src/app/api/mod.rs index a9e2d4e5c..84e640d2e 100644 --- a/clash_lib/src/app/api/mod.rs +++ b/clash_lib/src/app/api/mod.rs @@ -29,6 +29,7 @@ pub struct AppState { statistics_manager: Arc, } +#[allow(clippy::too_many_arguments)] pub fn get_api_runner( controller_cfg: Controller, log_source: Sender, diff --git a/clash_lib/src/app/dispatcher/dispatcher.rs b/clash_lib/src/app/dispatcher/dispatcher_impl.rs similarity index 98% rename from clash_lib/src/app/dispatcher/dispatcher.rs rename to clash_lib/src/app/dispatcher/dispatcher_impl.rs index 69a616c01..78427a63c 100644 --- a/clash_lib/src/app/dispatcher/dispatcher.rs +++ b/clash_lib/src/app/dispatcher/dispatcher_impl.rs @@ -299,7 +299,7 @@ impl Dispatcher { while let Some(packet) = remote_r.next().await { // NAT let mut packet = packet; - packet.src_addr = sess.destination.clone().into(); + packet.src_addr = sess.destination.clone(); packet.dst_addr = sess.source.into(); debug!("UDP NAT for packet: {:?}, session: {}", packet, sess); @@ -394,7 +394,9 @@ struct TimeoutUdpSessionManager { impl Drop for TimeoutUdpSessionManager { fn drop(&mut self) { trace!("dropping timeout udp session manager"); - self.cleaner.take().map(|x| x.abort()); + if let Some(x) = self.cleaner.take() { + x.abort() + } } } @@ -467,18 +469,16 @@ impl TimeoutUdpSessionManager { } } -struct OutboundHandleMap( - HashMap< - (String, SocketAddr), - ( - JoinHandle<()>, - JoinHandle<()>, - OutboundPacketSender, - Instant, - ), - >, +type OutboundHandleKey = (String, SocketAddr); +type OutboundHandleVal = ( + JoinHandle<()>, + JoinHandle<()>, + OutboundPacketSender, + Instant, ); +struct OutboundHandleMap(HashMap); + impl OutboundHandleMap { fn new() -> Self { Self(HashMap::new()) diff --git a/clash_lib/src/app/dispatcher/mod.rs b/clash_lib/src/app/dispatcher/mod.rs index b3e36e0a9..4eb015f4e 100644 --- a/clash_lib/src/app/dispatcher/mod.rs +++ b/clash_lib/src/app/dispatcher/mod.rs @@ -1,8 +1,8 @@ -mod dispatcher; +mod dispatcher_impl; mod statistics_manager; mod tracked; -pub use dispatcher::Dispatcher; +pub use dispatcher_impl::Dispatcher; pub use statistics_manager::Manager as StatisticsManager; pub use tracked::BoxedChainedDatagram; pub use tracked::BoxedChainedStream; diff --git a/clash_lib/src/app/dispatcher/statistics_manager.rs b/clash_lib/src/app/dispatcher/statistics_manager.rs index 0e41e99a6..4914c90f6 100644 --- a/clash_lib/src/app/dispatcher/statistics_manager.rs +++ b/clash_lib/src/app/dispatcher/statistics_manager.rs @@ -57,8 +57,10 @@ pub struct Snapshot { connections: Vec, } +type ConnectionMap = HashMap)>; + pub struct Manager { - connections: Arc)>>>, + connections: Arc>, upload_temp: AtomicI64, download_temp: AtomicI64, upload_blip: AtomicI64, diff --git a/clash_lib/src/app/dispatcher/tracked.rs b/clash_lib/src/app/dispatcher/tracked.rs index 560fb54a4..4e7ba27d1 100644 --- a/clash_lib/src/app/dispatcher/tracked.rs +++ b/clash_lib/src/app/dispatcher/tracked.rs @@ -119,6 +119,7 @@ pub struct TrackedStream { } impl TrackedStream { + #[allow(clippy::borrowed_box)] pub async fn new( inner: BoxedChainedStream, manager: Arc, @@ -164,7 +165,7 @@ impl TrackedStream { impl Drop for TrackedStream { fn drop(&mut self) { debug!("untrack connection: {}", self.id()); - let _ = self.manager.untrack(self.id()); + self.manager.untrack(self.id()); } } @@ -355,6 +356,7 @@ pub struct TrackedDatagram { } impl TrackedDatagram { + #[allow(clippy::borrowed_box)] pub async fn new( inner: BoxedChainedDatagram, manager: Arc, @@ -400,7 +402,7 @@ impl TrackedDatagram { impl Drop for TrackedDatagram { fn drop(&mut self) { debug!("untrack connection: {}", self.id()); - let _ = self.manager.untrack(self.id()); + self.manager.untrack(self.id()); } } diff --git a/clash_lib/src/app/dns/config.rs b/clash_lib/src/app/dns/config.rs index 09f76a7c2..5f8deca80 100644 --- a/clash_lib/src/app/dns/config.rs +++ b/clash_lib/src/app/dns/config.rs @@ -85,10 +85,10 @@ pub struct Config { } impl Config { - pub fn parse_nameserver(servers: &Vec) -> Result, Error> { + pub fn parse_nameserver(servers: &[String]) -> Result, Error> { let mut nameservers = vec![]; - for (i, server) in servers.into_iter().enumerate() { + for (i, server) in servers.iter().enumerate() { let mut server = server.clone(); if !server.contains("://") { @@ -106,19 +106,19 @@ impl Config { match url.scheme() { "udp" => { - addr = Config::host_with_default_port(&host, "53")?; + addr = Config::host_with_default_port(host, "53")?; net = "UDP"; } "tcp" => { - addr = Config::host_with_default_port(&host, "53")?; + addr = Config::host_with_default_port(host, "53")?; net = "TCP"; } "tls" => { - addr = Config::host_with_default_port(&host, "853")?; + addr = Config::host_with_default_port(host, "853")?; net = "DoT"; } "https" => { - addr = Config::host_with_default_port(&host, "443")?; + addr = Config::host_with_default_port(host, "443")?; net = "DoH"; } "dhcp" => { @@ -126,11 +126,11 @@ impl Config { net = "DHCP"; } _ => { - return Err(Error::InvalidConfig(String::from(format!( + return Err(Error::InvalidConfig(format!( "DNS nameserver [{}] unsupported scheme: {}", i, url.scheme() - )))); + ))); } } @@ -150,9 +150,9 @@ impl Config { let mut policy = HashMap::new(); for (domain, server) in policy_map { - let nameservers = Config::parse_nameserver(&vec![server.to_owned()])?; + let nameservers = Config::parse_nameserver(&[server.to_owned()])?; - let (_, valid) = trie::valid_and_split_domain(&domain); + let (_, valid) = trie::valid_and_split_domain(domain); if !valid { return Err(Error::InvalidConfig(format!( "DNS ResolverRule invalid domain: {}", @@ -164,7 +164,7 @@ impl Config { Ok(policy) } - pub fn parse_fallback_ip_cidr(ipcidr: &Vec) -> anyhow::Result> { + pub fn parse_fallback_ip_cidr(ipcidr: &[String]) -> anyhow::Result> { let mut output = vec![]; for (_i, ip) in ipcidr.iter().enumerate() { @@ -186,7 +186,7 @@ impl Config { Arc::new("127.0.0.1".parse::().unwrap()), ); - for (host, ip_str) in hosts_mapping.into_iter() { + for (host, ip_str) in hosts_mapping.iter() { let ip = ip_str.parse::()?; tree.insert(host.as_str(), Arc::new(ip)); } @@ -197,7 +197,7 @@ impl Config { pub fn host_with_default_port(host: &str, port: &str) -> Result { let has_port_suffix = Regex::new(r":\d+$").unwrap(); - if has_port_suffix.is_match(&host) { + if has_port_suffix.is_match(host) { Ok(host.into()) } else { Ok(format!("{}:{}", host, port)) @@ -218,7 +218,7 @@ impl TryFrom<&crate::config::def::Config> for Config { fn try_from(c: &crate::config::def::Config) -> Result { let dc = &c.dns; - if dc.enable && dc.nameserver.len() == 0 { + if dc.enable && dc.nameserver.is_empty() { return Err(Error::InvalidConfig(String::from( "dns enabled, no nameserver specified", ))); @@ -228,7 +228,7 @@ impl TryFrom<&crate::config::def::Config> for Config { let fallback = Config::parse_nameserver(&dc.fallback)?; let nameserver_policy = Config::parse_nameserver_policy(&dc.nameserver_policy)?; - if dc.default_nameserver.len() == 0 { + if dc.default_nameserver.is_empty() { return Err(Error::InvalidConfig(String::from( "default nameserver empty", ))); @@ -253,9 +253,7 @@ impl TryFrom<&crate::config::def::Config> for Config { .map(|l| match l { DNSListen::Udp(u) => { let addr = u.parse::().map_err(|_| { - Error::InvalidConfig( - format!("invalid dns udp listen address: {}", u).into(), - ) + Error::InvalidConfig(format!("invalid dns udp listen address: {}", u)) })?; Ok(DNSListenAddr { udp: Some(addr), @@ -270,9 +268,10 @@ impl TryFrom<&crate::config::def::Config> for Config { for (k, v) in map { let addr = v.parse::().map_err(|_| { - Error::InvalidConfig( - format!("invalid DNS listen address: {} -> {}", k, v).into(), - ) + Error::InvalidConfig(format!( + "invalid DNS listen address: {} -> {}", + k, v + )) })?; match k.as_str() { "udp" => udp = Some(addr), @@ -336,7 +335,7 @@ impl TryFrom<&crate::config::def::Config> for Config { .map_err(|_| Error::InvalidConfig(String::from("invalid fake ip range")))?, fake_ip_filter: dc.fake_ip_filter.clone(), store_fake_ip: c.profile.store_fake_ip, - hosts: if dc.user_hosts && c.hosts.len() > 0 { + hosts: if dc.user_hosts && !c.hosts.is_empty() { Config::parse_hosts(&c.hosts).ok() } else { let mut tree = trie::StringTrie::new(); diff --git a/clash_lib/src/app/dns/dhcp.rs b/clash_lib/src/app/dns/dhcp.rs index fba36e1a4..50d08fd5f 100644 --- a/clash_lib/src/app/dns/dhcp.rs +++ b/clash_lib/src/app/dns/dhcp.rs @@ -86,8 +86,8 @@ impl DhcpClient { inner.clients = make_clients( dns.into_iter() .map(|s| NameServer { - net: DNSNetMode::UDP, - address: format!("{}:53", s.to_string()), + net: DNSNetMode::Udp, + address: format!("{}:53", s), interface: None, }) .collect(), @@ -200,7 +200,7 @@ async fn probe_dns_server(iface: &str) -> io::Result> { io::ErrorKind::Other, format!("no MAC address on interface: {}", iface), ))? - .split(":") + .split(':') .map(|x| { u8::from_str_radix(x, 16) .map_err(|_x| io::Error::new(io::ErrorKind::Other, "malformed MAC addr")) @@ -290,7 +290,7 @@ async fn probe_dns_server(iface: &str) -> io::Result> { _ = tokio::time::sleep(Duration::from_secs(10)) => { dns_debug!("DHCP timeout after 10 secs"); - return Err(io::Error::new(io::ErrorKind::Other, "dhcp timeout")); + Err(io::Error::new(io::ErrorKind::Other, "dhcp timeout")) } } } diff --git a/clash_lib/src/app/dns/dns_client.rs b/clash_lib/src/app/dns/dns_client.rs index 688c7a17f..9794b2c72 100644 --- a/clash_lib/src/app/dns/dns_client.rs +++ b/clash_lib/src/app/dns/dns_client.rs @@ -35,21 +35,21 @@ use super::{ClashResolver, Client}; #[derive(Clone, Debug, PartialEq)] pub enum DNSNetMode { - UDP, - TCP, + Udp, + Tcp, DoT, DoH, - DHCP, + Dhcp, } impl Display for DNSNetMode { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { - Self::UDP => write!(f, "UDP"), - Self::TCP => write!(f, "TCP"), + Self::Udp => write!(f, "UDP"), + Self::Tcp => write!(f, "TCP"), Self::DoT => write!(f, "DoT"), Self::DoH => write!(f, "DoH"), - Self::DHCP => write!(f, "DHCP"), + Self::Dhcp => write!(f, "DHCP"), } } } @@ -59,11 +59,11 @@ impl FromStr for DNSNetMode { fn from_str(s: &str) -> Result { match s { - "UDP" => Ok(Self::UDP), - "TCP" => Ok(Self::TCP), + "UDP" => Ok(Self::Udp), + "TCP" => Ok(Self::Tcp), "DoH" => Ok(Self::DoH), "DoT" => Ok(Self::DoT), - "DHCP" => Ok(Self::DHCP), + "DHCP" => Ok(Self::Dhcp), _ => Err(Error::DNSError("unsupported protocol".into())), } } @@ -104,10 +104,10 @@ pub struct DnsClient { } impl DnsClient { - pub async fn new(opts: Opts) -> anyhow::Result { + pub async fn new_client(opts: Opts) -> anyhow::Result { // TODO: use proxy to connect? match &opts.net { - DNSNetMode::DHCP => Ok(Arc::new(DhcpClient::new(&opts.host).await)), + DNSNetMode::Dhcp => Ok(Arc::new(DhcpClient::new(&opts.host).await)), other => { let ip = if let Some(r) = opts.r { @@ -126,16 +126,12 @@ impl DnsClient { } } else { opts.host.parse::().map_err(|x| { - Error::DNSError(format!( - "resolve DNS hostname error: {}, {}", - x.to_string(), - opts.host - )) + Error::DNSError(format!("resolve DNS hostname error: {}, {}", x, opts.host)) })? }; match other { - DNSNetMode::UDP => { + DNSNetMode::Udp => { let cfg = DnsConfig::Udp(net::SocketAddr::new(ip, opts.port), opts.iface.clone()); let (client, bg) = dns_stream_builder(&cfg).await?; @@ -154,7 +150,7 @@ impl DnsClient { iface: opts.iface, })) } - DNSNetMode::TCP => { + DNSNetMode::Tcp => { let cfg = DnsConfig::Tcp(net::SocketAddr::new(ip, opts.port), opts.iface.clone()); @@ -281,10 +277,7 @@ async fn dns_stream_builder( net::SocketAddr::new(addr.ip(), addr.port()), // TODO: simplify this match match iface { - Some(iface) => match iface { - Interface::IpAddr(ip) => Some(SocketAddr::new(ip.clone(), 0)), - _ => None, - }, + Some(Interface::IpAddr(ip)) => Some(SocketAddr::new(*ip, 0)), _ => None, }, Duration::from_secs(5), @@ -299,10 +292,7 @@ async fn dns_stream_builder( TcpClientStream::>::with_bind_addr_and_timeout( net::SocketAddr::new(addr.ip(), addr.port()), match iface { - Some(iface) => match iface { - Interface::IpAddr(ip) => Some(SocketAddr::new(ip.clone(), 0)), - _ => None, - }, + Some(Interface::IpAddr(ip)) => Some(SocketAddr::new(*ip, 0)), _ => None, }, Duration::from_secs(5), @@ -324,10 +314,7 @@ async fn dns_stream_builder( tls_client_connect_with_bind_addr::>( net::SocketAddr::new(addr.ip(), addr.port()), match iface { - Some(iface) => match iface { - Interface::IpAddr(ip) => Some(SocketAddr::new(ip.clone(), 0)), - _ => None, - }, + Some(Interface::IpAddr(ip)) => Some(SocketAddr::new(*ip, 0)), _ => None, }, host.clone(), @@ -354,13 +341,8 @@ async fn dns_stream_builder( let mut stream_builder = HttpsClientStreamBuilder::with_client_config(Arc::new(tls_config)); - if let Some(iface) = iface { - match iface { - Interface::IpAddr(ip) => { - stream_builder.bind_addr(net::SocketAddr::new(ip.clone(), 0)) - } - _ => {} - } + if let Some(Interface::IpAddr(ip)) = iface { + stream_builder.bind_addr(net::SocketAddr::new(*ip, 0)); } let stream = stream_builder.build::>( net::SocketAddr::new(addr.ip(), addr.port()), diff --git a/clash_lib/src/app/dns/fakeip/file_store.rs b/clash_lib/src/app/dns/fakeip/file_store.rs index d620ed654..a4498bdc8 100644 --- a/clash_lib/src/app/dns/fakeip/file_store.rs +++ b/clash_lib/src/app/dns/fakeip/file_store.rs @@ -18,8 +18,7 @@ impl Store for FileStore { self.0 .get_fake_ip(host) .await - .map(|ip| ip.parse().ok()) - .flatten() + .and_then(|ip| ip.parse().ok()) } async fn pub_by_host(&mut self, host: &str, ip: std::net::IpAddr) { diff --git a/clash_lib/src/app/dns/fakeip/mod.rs b/clash_lib/src/app/dns/fakeip/mod.rs index 6ff059e5a..e91dc3086 100644 --- a/clash_lib/src/app/dns/fakeip/mod.rs +++ b/clash_lib/src/app/dns/fakeip/mod.rs @@ -77,7 +77,7 @@ impl FakeDns { let ip = self.get(host).await; self.store.pub_by_host(host, ip).await; - return ip; + ip } pub async fn reverse_lookup(&mut self, ip: net::IpAddr) -> Option { diff --git a/clash_lib/src/app/dns/filters.rs b/clash_lib/src/app/dns/filters.rs index 16487491f..97c8026f1 100644 --- a/clash_lib/src/app/dns/filters.rs +++ b/clash_lib/src/app/dns/filters.rs @@ -1,15 +1,15 @@ use std::{net, sync::Arc}; -use crate::common::{mmdb::MMDB, trie}; +use crate::common::{mmdb::Mmdb, trie}; pub trait FallbackIPFilter: Sync + Send { fn apply(&self, ip: &net::IpAddr) -> bool; } -pub struct GeoIPFilter(String, Arc); +pub struct GeoIPFilter(String, Arc); impl GeoIPFilter { - pub fn new(code: &str, mmdb: Arc) -> Self { + pub fn new(code: &str, mmdb: Arc) -> Self { Self(code.to_owned(), mmdb) } } diff --git a/clash_lib/src/app/dns/helper.rs b/clash_lib/src/app/dns/helper.rs index 9b44a3e68..b6f790010 100644 --- a/clash_lib/src/app/dns/helper.rs +++ b/clash_lib/src/app/dns/helper.rs @@ -16,23 +16,23 @@ pub async fn make_clients( for s in servers { dns_debug!("building nameserver: {:?}", s); - let (host, port) = if s.net == DNSNetMode::DHCP { + let (host, port) = if s.net == DNSNetMode::Dhcp { (s.address.as_str(), "0") } else { - let port = s.address.split(":").last().unwrap(); + let port = s.address.split(':').last().unwrap(); let host = s .address .strip_suffix(format!(":{}", port).as_str()) - .expect(format!("invalid address: {}", s.address).as_str()); + .unwrap_or_else(|| panic!("invalid address: {}", s.address)); (host, port) }; - match DnsClient::new(Opts { - r: resolver.as_ref().map(|x| x.clone()), + match DnsClient::new_client(Opts { + r: resolver.as_ref().cloned(), host: host.to_string(), port: port .parse::() - .expect(format!("no port for DNS server: {}", s.address).as_str()), + .unwrap_or_else(|_| panic!("no port for DNS server: {}", s.address)), net: s.net.to_owned(), iface: s.interface.as_ref().map(|x| Interface::Name(x.to_owned())), }) diff --git a/clash_lib/src/app/dns/resolver.rs b/clash_lib/src/app/dns/resolver.rs index e3941dd00..9c9634a70 100644 --- a/clash_lib/src/app/dns/resolver.rs +++ b/clash_lib/src/app/dns/resolver.rs @@ -11,7 +11,7 @@ use tracing::{debug, instrument, warn}; use hickory_proto::{op, rr}; use crate::app::profile::ThreadSafeCacheFile; -use crate::common::mmdb::MMDB; +use crate::common::mmdb::Mmdb; use crate::config::def::DNSMode; use crate::dns::helper::make_clients; use crate::dns::ThreadSafeDNSClient; @@ -56,7 +56,7 @@ impl Resolver { hosts: None, main: make_clients( vec![NameServer { - net: DNSNetMode::UDP, + net: DNSNetMode::Udp, address: "8.8.8.8:53".to_string(), interface: None, }], @@ -73,10 +73,10 @@ impl Resolver { } } - pub async fn new( + pub async fn new_resolver( cfg: &Config, store: ThreadSafeCacheFile, - mmdb: Arc, + mmdb: Arc, ) -> ThreadSafeDNSResolver { if !cfg.enable { return Arc::new(SystemResolver::new().expect("failed to create system resolver")); @@ -99,12 +99,12 @@ impl Resolver { ipv6: AtomicBool::new(cfg.ipv6), main: make_clients(cfg.nameserver.clone(), Some(default_resolver.clone())).await, hosts: cfg.hosts.clone(), - fallback: if cfg.fallback.len() > 0 { + fallback: if !cfg.fallback.is_empty() { Some(make_clients(cfg.fallback.clone(), Some(default_resolver.clone())).await) } else { None }, - fallback_domain_filters: if cfg.fallback_filter.domain.len() > 0 { + fallback_domain_filters: if !cfg.fallback_filter.domain.is_empty() { Some(vec![Box::new(DomainFilter::new( cfg.fallback_filter .domain @@ -139,7 +139,7 @@ impl Resolver { lru_cache: Some(Arc::new(RwLock::new( lru_time_cache::LruCache::with_expiry_duration_and_capacity(TTL, 4096), ))), - policy: if cfg.nameserver_policy.len() > 0 { + policy: if !cfg.nameserver_policy.is_empty() { let mut p = trie::StringTrie::new(); for (domain, ns) in &cfg.nameserver_policy { p.insert( @@ -157,7 +157,7 @@ impl Resolver { DNSMode::FakeIp => Some(Arc::new(RwLock::new( fakeip::FakeDns::new(fakeip::Opts { ipnet: cfg.fake_ip_range, - skipped_hostnames: if cfg.fake_ip_filter.len() != 0 { + skipped_hostnames: if !cfg.fake_ip_filter.is_empty() { let mut host = trie::StringTrie::new(); for domain in cfg.fake_ip_filter.iter() { host.insert(domain.as_str(), Arc::new(true)); @@ -208,7 +208,7 @@ impl Resolver { tokio::select! { result = futures::future::select_ok(queries) => match result { Ok(r) => Ok(r.0), - Err(e) => Err(e.into()), + Err(e) => Err(e), }, _ = timeout => Err(Error::DNSError("DNS query timeout".into()).into()) } @@ -264,11 +264,11 @@ impl Resolver { return self.ip_exchange(message).await; } - if let Some(matched) = self.match_policy(&message) { - return Resolver::batch_exchange(&matched, message).await; + if let Some(matched) = self.match_policy(message) { + return Resolver::batch_exchange(matched, message).await; } - return Resolver::batch_exchange(&self.main, message).await; + Resolver::batch_exchange(&self.main, message).await }; let rv = query.await; @@ -305,7 +305,7 @@ impl Resolver { } } - return rv; + rv } fn match_policy(&self, m: &op::Message) -> Option<&Vec> { @@ -320,13 +320,13 @@ impl Resolver { } async fn ip_exchange(&self, message: &op::Message) -> anyhow::Result { - if let Some(mut matched) = self.match_policy(message) { - return Resolver::batch_exchange(&mut matched, message).await; + if let Some(matched) = self.match_policy(message) { + return Resolver::batch_exchange(matched, message).await; } if self.should_only_query_fallback(message) { // self.fallback guaranteed in the above check - return Resolver::batch_exchange(&self.fallback.as_ref().unwrap(), message).await; + return Resolver::batch_exchange(self.fallback.as_ref().unwrap(), message).await; } let main_query = Resolver::batch_exchange(&self.main, message); @@ -335,7 +335,7 @@ impl Resolver { return main_query.await; } - let fallback_query = Resolver::batch_exchange(&self.fallback.as_ref().unwrap(), message); + let fallback_query = Resolver::batch_exchange(self.fallback.as_ref().unwrap(), message); if let Ok(main_result) = main_query.await { let ip_list = Resolver::ip_list_of_message(&main_result); @@ -355,7 +355,7 @@ impl Resolver { (&self.fallback, &self.fallback_domain_filters) { if let Some(domain) = Resolver::domain_name_of_message(message) { - for f in fallback_domain_filters.into_iter() { + for f in fallback_domain_filters.iter() { if f.apply(domain.as_str()) { return true; } @@ -389,7 +389,7 @@ impl Resolver { pub(crate) fn ip_list_of_message(m: &op::Message) -> Vec { m.answers() - .into_iter() + .iter() .filter(|r| { r.record_type() == rr::RecordType::A || r.record_type() == rr::RecordType::AAAA }) @@ -413,10 +413,10 @@ impl ClashResolver for Resolver { true => { let fut1 = self .resolve_v6(host, enhanced) - .map(|x| x.map(|v6| v6.map(|v6| net::IpAddr::from(v6)))); + .map(|x| x.map(|v6| v6.map(net::IpAddr::from))); let fut2 = self .resolve_v4(host, enhanced) - .map(|x| x.map(|v4| v4.map(|v4| net::IpAddr::from(v4)))); + .map(|x| x.map(|v4| v4.map(net::IpAddr::from))); let futs = vec![fut1.boxed(), fut2.boxed()]; let r = futures::future::select_ok(futs).await?; @@ -429,7 +429,7 @@ impl ClashResolver for Resolver { false => self .resolve_v4(host, enhanced) .await - .map(|ip| ip.map(|v4| net::IpAddr::from(v4))), + .map(|ip| ip.map(net::IpAddr::from)), } } async fn resolve_v4( @@ -469,7 +469,7 @@ impl ClashResolver for Resolver { net::IpAddr::V4(v4) => Ok(Some(*v4)), _ => unreachable!("invalid IP family"), }, - Err(e) => Err(e.into()), + Err(e) => Err(e), } } @@ -503,7 +503,7 @@ impl ClashResolver for Resolver { _ => unreachable!("invalid IP family"), }, - Err(e) => Err(e.into()), + Err(e) => Err(e), } } @@ -600,11 +600,11 @@ mod tests { #[tokio::test] async fn test_udp_resolve() { - let c = DnsClient::new(Opts { + let c = DnsClient::new_client(Opts { r: None, host: "114.114.114.114".to_string(), port: 53, - net: DNSNetMode::UDP, + net: DNSNetMode::Udp, iface: None, }) .await @@ -615,11 +615,11 @@ mod tests { #[tokio::test] async fn test_tcp_resolve() { - let c = DnsClient::new(Opts { + let c = DnsClient::new_client(Opts { r: None, host: "1.1.1.1".to_string(), port: 53, - net: DNSNetMode::TCP, + net: DNSNetMode::Tcp, iface: None, }) .await @@ -631,7 +631,7 @@ mod tests { #[tokio::test] #[ignore = "network unstable on CI"] async fn test_dot_resolve() { - let c = DnsClient::new(Opts { + let c = DnsClient::new_client(Opts { r: Some(Arc::new(Resolver::new_default().await)), host: "dns.google".to_string(), port: 853, @@ -649,7 +649,7 @@ mod tests { async fn test_doh_resolve() { let default_resolver = Arc::new(Resolver::new_default().await); - let c = DnsClient::new(Opts { + let c = DnsClient::new_client(Opts { r: Some(default_resolver.clone()), host: "cloudflare-dns.com".to_string(), port: 443, @@ -665,11 +665,11 @@ mod tests { #[tokio::test] #[ignore] async fn test_dhcp_client() { - let c = DnsClient::new(Opts { + let c = DnsClient::new_client(Opts { r: None, host: "en0".to_string(), port: 0, - net: DNSNetMode::DHCP, + net: DNSNetMode::Dhcp, iface: None, }) .await @@ -678,7 +678,7 @@ mod tests { test_client(c).await; } - async fn test_client(c: ThreadSafeDNSClient) -> () { + async fn test_client(c: ThreadSafeDNSClient) { let mut m = op::Message::new(); let mut q = op::Query::new(); q.set_name(rr::Name::from_utf8("www.google.com").unwrap()); @@ -691,7 +691,7 @@ mod tests { let ips = Resolver::ip_list_of_message(&r); - assert!(ips.len() > 0); + assert!(!ips.is_empty()); assert!(!ips[0].is_unspecified()); assert!(ips[0].is_ipv4()); @@ -707,7 +707,7 @@ mod tests { let ips = Resolver::ip_list_of_message(&r); - assert!(ips.len() > 0); + assert!(!ips.is_empty()); assert!(!ips[0].is_unspecified()); assert!(ips[0].is_ipv6()); } diff --git a/clash_lib/src/app/dns/server/mod.rs b/clash_lib/src/app/dns/server/mod.rs index cae0af371..a0d5f0d2c 100644 --- a/clash_lib/src/app/dns/server/mod.rs +++ b/clash_lib/src/app/dns/server/mod.rs @@ -72,8 +72,8 @@ impl DnsHandler { m.set_message_type(request.message_type()); m.set_recursion_desired(request.recursion_desired()); m.add_query(request.query().original().clone()); - m.add_additionals(request.additionals().into_iter().map(Clone::clone)); - m.add_name_servers(request.name_servers().into_iter().map(Clone::clone)); + m.add_additionals(request.additionals().iter().map(Clone::clone)); + m.add_name_servers(request.name_servers().iter().map(Clone::clone)); for sig0 in request.sig0() { m.add_sig0(sig0.clone()); } @@ -158,20 +158,18 @@ pub async fn get_dns_listener(cfg: Config, resolver: ThreadSafeDNSResolver) -> O if let Some(addr) = cfg.listen.udp { UdpSocket::bind(addr) .await - .and_then(|x| { + .map(|x| { info!("dns server listening on udp: {}", addr); s.register_socket(x); - Ok(()) }) .ok()?; } if let Some(addr) = cfg.listen.tcp { TcpListener::bind(addr) .await - .and_then(|x| { + .map(|x| { info!("dns server listening on tcp: {}", addr); s.register_listener(x, DEFAULT_DNS_SERVER_TIMEOUT); - Ok(()) }) .ok()?; } diff --git a/clash_lib/src/app/inbound/manager.rs b/clash_lib/src/app/inbound/manager.rs index 531d3fbb9..c68670edf 100644 --- a/clash_lib/src/app/inbound/manager.rs +++ b/clash_lib/src/app/inbound/manager.rs @@ -89,10 +89,10 @@ impl InboundManager { self.network_listeners .values() .for_each(|x| match x.listener_type { - ListenerType::HTTP => { + ListenerType::Http => { ports.port = Some(x.port); } - ListenerType::SOCKS5 => { + ListenerType::Socks5 => { ports.socks_port = Some(x.port); } ListenerType::Mixed => { @@ -107,12 +107,12 @@ impl InboundManager { let mut network_listeners = HashMap::new(); if let Some(http_port) = ports.port { network_listeners.insert( - ListenerType::HTTP, + ListenerType::Http, NetworkInboundListener { name: "HTTP".to_string(), bind_addr: self.bind_address.clone(), port: http_port, - listener_type: ListenerType::HTTP, + listener_type: ListenerType::Http, dispatcher: self.dispatcher.clone(), authenticator: self.authenticator.clone(), }, @@ -121,12 +121,12 @@ impl InboundManager { if let Some(socks_port) = ports.socks_port { network_listeners.insert( - ListenerType::SOCKS5, + ListenerType::Socks5, NetworkInboundListener { name: "SOCKS5".to_string(), bind_addr: self.bind_address.clone(), port: socks_port, - listener_type: ListenerType::SOCKS5, + listener_type: ListenerType::Socks5, dispatcher: self.dispatcher.clone(), authenticator: self.authenticator.clone(), }, diff --git a/clash_lib/src/app/inbound/network_listener.rs b/clash_lib/src/app/inbound/network_listener.rs index 043554ff3..9d3db7ea5 100644 --- a/clash_lib/src/app/inbound/network_listener.rs +++ b/clash_lib/src/app/inbound/network_listener.rs @@ -14,8 +14,8 @@ use std::sync::Arc; #[derive(Eq, PartialEq, Hash)] pub enum ListenerType { - HTTP, - SOCKS5, + Http, + Socks5, Mixed, } @@ -70,7 +70,7 @@ impl NetworkInboundListener { } BindAddress::One(iface) => match iface { Interface::IpAddr(ip) => match ip { - IpAddr::V4(ip) => self.build_and_insert_listener(&mut runners, ip.clone()), + IpAddr::V4(ip) => self.build_and_insert_listener(&mut runners, *ip), IpAddr::V6(_) => unreachable!("unsupported listening v6"), }, Interface::Name(iface) => { @@ -78,8 +78,7 @@ impl NetworkInboundListener { .expect("list interfaces") .into_iter() .filter(|x| &x.name == iface) - .map(|x| x.addr) - .flatten() + .flat_map(|x| x.addr) .map(|x| match x { Addr::V4(v4) => v4.ip, Addr::V6(_) => unreachable!(), @@ -97,12 +96,12 @@ impl NetworkInboundListener { fn build_and_insert_listener(&self, runners: &mut Vec, ip: Ipv4Addr) { let listener: AnyInboundListener = match self.listener_type { - ListenerType::HTTP => http::Listener::new( + ListenerType::Http => http::Listener::new( (ip, self.port).into(), self.dispatcher.clone(), self.authenticator.clone(), ), - ListenerType::SOCKS5 => socks::Listener::new( + ListenerType::Socks5 => socks::Listener::new( (ip, self.port).into(), self.dispatcher.clone(), self.authenticator.clone(), diff --git a/clash_lib/src/app/logging.rs b/clash_lib/src/app/logging.rs index 1e7191af2..fa7e5b26c 100644 --- a/clash_lib/src/app/logging.rs +++ b/clash_lib/src/app/logging.rs @@ -55,12 +55,12 @@ where event.record(&mut EventVisitor(&mut strs)); let event = LogEvent { - level: match event.metadata().level() { - &tracing::Level::ERROR => LogLevel::Error, - &tracing::Level::WARN => LogLevel::Warning, - &tracing::Level::INFO => LogLevel::Info, - &tracing::Level::DEBUG => LogLevel::Debug, - &tracing::Level::TRACE => LogLevel::Debug, + level: match *event.metadata().level() { + tracing::Level::ERROR => LogLevel::Error, + tracing::Level::WARN => LogLevel::Warning, + tracing::Level::INFO => LogLevel::Info, + tracing::Level::DEBUG => LogLevel::Debug, + tracing::Level::TRACE => LogLevel::Debug, }, msg: strs.join(" "), }; @@ -95,12 +95,7 @@ pub fn setup_logging( log_file: Option, ) -> anyhow::Result> { let filter = EnvFilter::builder() - .with_default_directive( - format!("clash={}", level) - .parse::() - .unwrap() - .into(), - ) + .with_default_directive(format!("clash={}", level).parse::().unwrap()) .from_env_lossy(); let jaeger = if let Ok(jager_endpoint) = std::env::var("JAGER_ENDPOINT") { diff --git a/clash_lib/src/app/outbound/manager.rs b/clash_lib/src/app/outbound/manager.rs index ea144c994..05a2ccfeb 100644 --- a/clash_lib/src/app/outbound/manager.rs +++ b/clash_lib/src/app/outbound/manager.rs @@ -172,6 +172,7 @@ impl OutboundManager { // API handlers end + #[allow(clippy::too_many_arguments)] async fn load_handlers( outbounds: Vec, outbound_groups: Vec, @@ -220,54 +221,54 @@ impl OutboundManager { let mut outbound_groups = outbound_groups; proxy_groups_dag_sort(&mut outbound_groups)?; - for outbound_group in outbound_groups.iter() { - fn make_provider_from_proxies( - name: &str, - proxies: &Vec, - interval: u64, - lazy: bool, - handlers: &HashMap, - proxy_manager: ProxyManager, - proxy_providers: &mut Vec, - provider_registry: &mut HashMap, - ) -> Result { - if name == PROXY_DIRECT || name == PROXY_REJECT { - return Err(Error::InvalidConfig(format!( - "proxy group {} is reserved", - name - ))); - } - let proxies = proxies - .into_iter() - .map(|x| { - handlers - .get(x) - .ok_or_else(|| Error::InvalidConfig(format!("proxy {} not found", x))) - .map(Clone::clone) - }) - .collect::, _>>()?; - - let hc = HealthCheck::new( - proxies.clone(), - DEFAULT_LATENCY_TEST_URL.to_owned(), - interval, - lazy, - proxy_manager.clone(), - ) - .map_err(|e| Error::InvalidConfig(format!("invalid hc config {}", e)))?; - - let pd = Arc::new(RwLock::new( - PlainProvider::new(name.to_owned(), proxies, hc).map_err(|x| { - Error::InvalidConfig(format!("invalid provider config: {}", x)) - })?, - )); - - proxy_providers.push(pd.clone()); - provider_registry.insert(name.to_owned(), pd.clone()); - - Ok(pd) + #[allow(clippy::too_many_arguments)] + fn make_provider_from_proxies( + name: &str, + proxies: &[String], + interval: u64, + lazy: bool, + handlers: &HashMap, + proxy_manager: ProxyManager, + proxy_providers: &mut Vec, + provider_registry: &mut HashMap, + ) -> Result { + if name == PROXY_DIRECT || name == PROXY_REJECT { + return Err(Error::InvalidConfig(format!( + "proxy group {} is reserved", + name + ))); } + let proxies = proxies + .iter() + .map(|x| { + handlers + .get(x) + .ok_or_else(|| Error::InvalidConfig(format!("proxy {} not found", x))) + .map(Clone::clone) + }) + .collect::, _>>()?; + + let hc = HealthCheck::new( + proxies.clone(), + DEFAULT_LATENCY_TEST_URL.to_owned(), + interval, + lazy, + proxy_manager.clone(), + ) + .map_err(|e| Error::InvalidConfig(format!("invalid hc config {}", e)))?; + + let pd = Arc::new(RwLock::new( + PlainProvider::new(name.to_owned(), proxies, hc) + .map_err(|x| Error::InvalidConfig(format!("invalid provider config: {}", x)))?, + )); + + proxy_providers.push(pd.clone()); + provider_registry.insert(name.to_owned(), pd.clone()); + + Ok(pd) + } + for outbound_group in outbound_groups.iter() { match outbound_group { OutboundGroupProtocol::Relay(proto) => { if proto.proxies.as_ref().map(|x| x.len()).unwrap_or_default() @@ -302,7 +303,7 @@ impl OutboundManager { for provider_name in provider_names { let provider = provider_registry .get(provider_name) - .expect(format!("provider {} not found", provider_name).as_str()) + .unwrap_or_else(|| panic!("provider {} not found", provider_name)) .clone(); providers.push(provider); } @@ -351,7 +352,7 @@ impl OutboundManager { for provider_name in provider_names { let provider = provider_registry .get(provider_name) - .expect(format!("provider {} not found", provider_name).as_str()) + .unwrap_or_else(|| panic!("provider {} not found", provider_name)) .clone(); providers.push(provider); } @@ -402,7 +403,7 @@ impl OutboundManager { for provider_name in provider_names { let provider = provider_registry .get(provider_name) - .expect(format!("provider {} not found", provider_name).as_str()) + .unwrap_or_else(|| panic!("provider {} not found", provider_name)) .clone(); providers.push(provider); } @@ -452,7 +453,7 @@ impl OutboundManager { for provider_name in provider_names { let provider = provider_registry .get(provider_name) - .expect(format!("provider {} not found", provider_name).as_str()) + .unwrap_or_else(|| panic!("provider {} not found", provider_name)) .clone(); providers.push(provider); } @@ -501,7 +502,7 @@ impl OutboundManager { for provider_name in provider_names { let provider = provider_registry .get(provider_name) - .expect(format!("provider {} not found", provider_name).as_str()) + .unwrap_or_else(|| panic!("provider {} not found", provider_name)) .clone(); providers.push(provider); @@ -576,7 +577,7 @@ impl OutboundManager { let vehicle = http_vehicle::Vehicle::new( http.url .parse::() - .expect(format!("invalid provider url: {}", http.url).as_str()), + .unwrap_or_else(|_| panic!("invalid provider url: {}", http.url)), http.path, Some(cwd.clone()), resolver.clone(), diff --git a/clash_lib/src/app/outbound/utils.rs b/clash_lib/src/app/outbound/utils.rs index 3cfee036b..ef94e5df2 100644 --- a/clash_lib/src/app/outbound/utils.rs +++ b/clash_lib/src/app/outbound/utils.rs @@ -80,7 +80,7 @@ pub fn proxy_groups_dag_sort(groups: &mut Vec) -> Result< let name = queue.pop_front().unwrap().to_owned(); let node = graph .get(&name) - .expect(format!("node {} not found", &name).as_str()); + .unwrap_or_else(|| panic!("node {} not found", &name)); if node.borrow().proto.is_some() { index += 1; @@ -102,7 +102,7 @@ pub fn proxy_groups_dag_sort(groups: &mut Vec) -> Result< graph.remove(&name); } - if graph.len() == 0 { + if graph.is_empty() { return Ok(()); } @@ -142,7 +142,7 @@ pub fn proxy_groups_dag_sort(groups: &mut Vec) -> Result< } } - while queue.len() > 0 { + while !queue.is_empty() { let name = queue.first().unwrap().to_owned(); let node = graph.get(&name).unwrap(); @@ -162,10 +162,10 @@ pub fn proxy_groups_dag_sort(groups: &mut Vec) -> Result< let looped_groups: Vec = graph.keys().map(|s| s.to_owned()).collect(); - return Err(Error::InvalidConfig(format!( + Err(Error::InvalidConfig(format!( "loop detected in proxy groups: {:?}", looped_groups - ))); + ))) } #[cfg(test)] @@ -220,7 +220,9 @@ mod tests { OutboundGroupProtocol::Fallback(g3), OutboundGroupProtocol::LoadBalance(g4), OutboundGroupProtocol::Select(g5), - ]; + ] + .into_iter() + .collect(); super::proxy_groups_dag_sort(&mut groups).unwrap(); @@ -261,7 +263,9 @@ mod tests { OutboundGroupProtocol::Relay(g1), OutboundGroupProtocol::UrlTest(g2), OutboundGroupProtocol::Fallback(g3), - ]; + ] + .into_iter() + .collect(); let e = super::proxy_groups_dag_sort(&mut groups).unwrap_err(); assert!(e.to_string().contains("loop detected in proxy groups")); diff --git a/clash_lib/src/app/remote_content_manager/http_client.rs b/clash_lib/src/app/remote_content_manager/http_client.rs index 098dd87dd..3277490f0 100644 --- a/clash_lib/src/app/remote_content_manager/http_client.rs +++ b/clash_lib/src/app/remote_content_manager/http_client.rs @@ -30,14 +30,14 @@ impl Service for LocalConnector { fn call(&mut self, remote: Uri) -> Self::Future { let host = remote .host() - .expect(format!("invalid url: {}", remote.to_string()).as_str()) + .unwrap_or_else(|| panic!("invalid url: {}", remote)) .to_owned(); let port = remote.port_u16().unwrap_or(match remote.scheme_str() { None => 80, Some(s) => match s { - s if s == "http" => 80, - s if s == "https" => 443, + "http" => 80, + "https" => 443, _ => panic!("invalid url: {}", remote), }, }); @@ -45,7 +45,7 @@ impl Service for LocalConnector { let sess = Session { destination: (host, port) .try_into() - .expect(format!("invalid url: {}", remote.to_string()).as_str()), + .unwrap_or_else(|_| panic!("invalid url: {}", remote)), ..Default::default() }; let handler = self.0.clone(); diff --git a/clash_lib/src/app/remote_content_manager/mod.rs b/clash_lib/src/app/remote_content_manager/mod.rs index ce3c823b3..d5dcc0aa6 100644 --- a/clash_lib/src/app/remote_content_manager/mod.rs +++ b/clash_lib/src/app/remote_content_manager/mod.rs @@ -90,7 +90,6 @@ impl ProxyManager { for proxy in proxies { let proxy = proxy.clone(); let url = url.to_owned(); - let timeout = timeout.clone(); let manager = self.clone(); futs.push(tokio::spawn(async move { manager @@ -286,7 +285,7 @@ mod tests { assert!(manager.alive(PROXY_DIRECT).await); assert!(manager.last_delay(PROXY_DIRECT).await > 0); - assert!(manager.delay_history(PROXY_DIRECT).await.len() > 0); + assert!(!manager.delay_history(PROXY_DIRECT).await.is_empty()); manager.report_alive(PROXY_DIRECT, false).await; assert!(!manager.alive(PROXY_DIRECT).await); diff --git a/clash_lib/src/app/remote_content_manager/providers/file_vehicle.rs b/clash_lib/src/app/remote_content_manager/providers/file_vehicle.rs index 95fa50878..5bd26e56c 100644 --- a/clash_lib/src/app/remote_content_manager/providers/file_vehicle.rs +++ b/clash_lib/src/app/remote_content_manager/providers/file_vehicle.rs @@ -20,7 +20,7 @@ impl ProviderVehicle for Vehicle { } fn path(&self) -> &str { - &self.path.as_str() + self.path.as_str() } fn typ(&self) -> ProviderVehicleType { diff --git a/clash_lib/src/app/remote_content_manager/providers/proxy_provider/mod.rs b/clash_lib/src/app/remote_content_manager/providers/proxy_provider/mod.rs index 55b3fb70e..256ba13b6 100644 --- a/clash_lib/src/app/remote_content_manager/providers/proxy_provider/mod.rs +++ b/clash_lib/src/app/remote_content_manager/providers/proxy_provider/mod.rs @@ -1,8 +1,23 @@ pub mod plain_provider; -pub mod proxy_provider; + pub mod proxy_set_provider; pub use plain_provider::PlainProvider; -pub use proxy_provider::ProxyProvider; -pub use proxy_provider::ThreadSafeProxyProvider; pub use proxy_set_provider::ProxySetProvider; + +use std::sync::Arc; + +use async_trait::async_trait; +use tokio::sync::RwLock; + +use crate::{app::remote_content_manager::providers::Provider, proxy::AnyOutboundHandler}; + +pub type ThreadSafeProxyProvider = Arc>; + +#[async_trait] +pub trait ProxyProvider: Provider { + async fn proxies(&self) -> Vec; + async fn touch(&self); + /// this is a blocking call, you may want to spawn a new task to run this + async fn healthcheck(&self); +} diff --git a/clash_lib/src/app/remote_content_manager/providers/proxy_provider/plain_provider.rs b/clash_lib/src/app/remote_content_manager/providers/proxy_provider/plain_provider.rs index 19c9c1c8f..5d2f45f1c 100644 --- a/clash_lib/src/app/remote_content_manager/providers/proxy_provider/plain_provider.rs +++ b/clash_lib/src/app/remote_content_manager/providers/proxy_provider/plain_provider.rs @@ -13,7 +13,7 @@ use crate::{ Error, }; -use super::proxy_provider::ProxyProvider; +use super::ProxyProvider; pub struct PlainProvider { name: String, diff --git a/clash_lib/src/app/remote_content_manager/providers/proxy_provider/proxy_provider.rs b/clash_lib/src/app/remote_content_manager/providers/proxy_provider/proxy_provider.rs deleted file mode 100644 index 8972c0bd0..000000000 --- a/clash_lib/src/app/remote_content_manager/providers/proxy_provider/proxy_provider.rs +++ /dev/null @@ -1,16 +0,0 @@ -use std::sync::Arc; - -use async_trait::async_trait; -use tokio::sync::RwLock; - -use crate::{app::remote_content_manager::providers::Provider, proxy::AnyOutboundHandler}; - -pub type ThreadSafeProxyProvider = Arc>; - -#[async_trait] -pub trait ProxyProvider: Provider { - async fn proxies(&self) -> Vec; - async fn touch(&self); - /// this is a blocking call, you may want to spawn a new task to run this - async fn healthcheck(&self); -} diff --git a/clash_lib/src/app/remote_content_manager/providers/proxy_provider/proxy_set_provider.rs b/clash_lib/src/app/remote_content_manager/providers/proxy_provider/proxy_set_provider.rs index 7f25214eb..c1a8f450c 100644 --- a/clash_lib/src/app/remote_content_manager/providers/proxy_provider/proxy_set_provider.rs +++ b/clash_lib/src/app/remote_content_manager/providers/proxy_provider/proxy_set_provider.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use serde_yaml::Value; use tracing::debug; -use super::proxy_provider::ProxyProvider; +use super::ProxyProvider; use crate::{ app::remote_content_manager::{ healthcheck::HealthCheck, @@ -31,11 +31,13 @@ struct Inner { hc: Arc, } +type ProxyUpdater = + Box) -> BoxFuture<'static, ()> + Send + Sync + 'static>; +type ProxyParser = + Box anyhow::Result> + Send + Sync + 'static>; + pub struct ProxySetProvider { - fetcher: Fetcher< - Box) -> BoxFuture<'static, ()> + Send + Sync + 'static>, - Box anyhow::Result> + Send + Sync + 'static>, - >, + fetcher: Fetcher, inner: std::sync::Arc>, } @@ -64,9 +66,7 @@ impl ProxySetProvider { let inner_clone = inner.clone(); let n = name.clone(); - let updater: Box< - dyn Fn(Vec) -> BoxFuture<'static, ()> + Send + Sync + 'static, - > = Box::new( + let updater: ProxyUpdater = Box::new( move |input: Vec| -> BoxFuture<'static, ()> { let hc = hc.clone(); let n = n.clone(); @@ -85,9 +85,7 @@ impl ProxySetProvider { ); let n = name.clone(); - let parser: Box< - dyn Fn(&[u8]) -> anyhow::Result> + Send + Sync + 'static, - > = Box::new( + let parser: ProxyParser = Box::new( move |input: &[u8]| -> anyhow::Result> { let scheme: ProviderScheme = serde_yaml::from_slice(input).map_err(|x| { Error::InvalidConfig(format!("proxy provider parse error {}: {}", n, x)) @@ -109,12 +107,12 @@ impl ProxySetProvider { .collect::, _>>(); Ok(proxies?) } else { - return Err(Error::InvalidConfig(format!("{}: proxies is empty", n)).into()); + Err(Error::InvalidConfig(format!("{}: proxies is empty", n)).into()) } }, ); - let fetcher = Fetcher::new(name, interval, vehicle, parser, Some(updater.into())); + let fetcher = Fetcher::new(name, interval, vehicle, parser, Some(updater)); Ok(Self { fetcher, inner }) } } @@ -180,13 +178,7 @@ impl Provider for ProxySetProvider { #[async_trait] impl ProxyProvider for ProxySetProvider { async fn proxies(&self) -> Vec { - self.inner - .read() - .await - .proxies - .iter() - .map(|x| x.clone()) - .collect() + self.inner.read().await.proxies.to_vec() } async fn touch(&self) { diff --git a/clash_lib/src/app/remote_content_manager/providers/rule_provider/mod.rs b/clash_lib/src/app/remote_content_manager/providers/rule_provider/mod.rs index 97dd8af3c..695019b32 100644 --- a/clash_lib/src/app/remote_content_manager/providers/rule_provider/mod.rs +++ b/clash_lib/src/app/remote_content_manager/providers/rule_provider/mod.rs @@ -1,5 +1,5 @@ mod cidr_trie; -mod rule_provider; +mod provider; -pub use rule_provider::ThreadSafeRuleProvider; -pub use rule_provider::{RuleProvider, RuleProviderImpl, RuleSetBehavior}; +pub use provider::ThreadSafeRuleProvider; +pub use provider::{RuleProvider, RuleProviderImpl, RuleSetBehavior}; diff --git a/clash_lib/src/app/remote_content_manager/providers/rule_provider/rule_provider.rs b/clash_lib/src/app/remote_content_manager/providers/rule_provider/provider.rs similarity index 79% rename from clash_lib/src/app/remote_content_manager/providers/rule_provider/rule_provider.rs rename to clash_lib/src/app/remote_content_manager/providers/rule_provider/provider.rs index b240e8daa..b142d1449 100644 --- a/clash_lib/src/app/remote_content_manager/providers/rule_provider/rule_provider.rs +++ b/clash_lib/src/app/remote_content_manager/providers/rule_provider/provider.rs @@ -20,7 +20,7 @@ use crate::{ }, router::{map_rule_type, RuleMatcher}, }, - common::{errors::map_io_error, mmdb::MMDB, trie}, + common::{errors::map_io_error, mmdb::Mmdb, trie}, config::internal::rule::RuleType, session::Session, Error, @@ -37,7 +37,7 @@ struct ProviderScheme { #[serde(rename_all = "lowercase")] pub enum RuleSetBehavior { Domain, - IPCIDR, + Ipcidr, Classical, } @@ -45,7 +45,7 @@ impl Display for RuleSetBehavior { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { RuleSetBehavior::Domain => write!(f, "Domain"), - RuleSetBehavior::IPCIDR => write!(f, "IPCIDR"), + RuleSetBehavior::Ipcidr => write!(f, "IPCIDR"), RuleSetBehavior::Classical => write!(f, "Classical"), } } @@ -53,7 +53,7 @@ impl Display for RuleSetBehavior { enum RuleContent { Domain(trie::StringTrie), - IPCIDR(CidrTrie), + Ipcidr(Box), Classical(Vec>), } @@ -68,11 +68,11 @@ pub trait RuleProvider: Provider { pub type ThreadSafeRuleProvider = Arc; +type RuleUpdater = Box BoxFuture<'static, ()> + Send + Sync + 'static>; +type RuleParser = Box anyhow::Result + Send + Sync + 'static>; + pub struct RuleProviderImpl { - fetcher: Fetcher< - Box BoxFuture<'static, ()> + Send + Sync + 'static>, - Box anyhow::Result + Send + Sync + 'static>, - >, + fetcher: Fetcher, inner: std::sync::Arc>, behavior: RuleSetBehavior, } @@ -83,12 +83,12 @@ impl RuleProviderImpl { behovior: RuleSetBehavior, interval: Duration, vehicle: ThreadSafeProviderVehicle, - mmdb: Arc, + mmdb: Arc, ) -> Self { let inner = Arc::new(tokio::sync::RwLock::new(Inner { content: match behovior { RuleSetBehavior::Domain => RuleContent::Domain(trie::StringTrie::new()), - RuleSetBehavior::IPCIDR => RuleContent::IPCIDR(CidrTrie::new()), + RuleSetBehavior::Ipcidr => RuleContent::Ipcidr(Box::new(CidrTrie::new())), RuleSetBehavior::Classical => RuleContent::Classical(vec![]), }, })); @@ -96,26 +96,24 @@ impl RuleProviderImpl { let inner_clone = inner.clone(); let n = name.clone(); - let updater: Box BoxFuture<'static, ()> + Send + Sync + 'static> = - Box::new(move |input: RuleContent| -> BoxFuture<'static, ()> { - let n = n.clone(); - let inner: Arc> = inner_clone.clone(); - Box::pin(async move { - let mut inner = inner.write().await; - trace!("updated rules for: {}", n); - inner.content = input; - }) - }); + let updater: RuleUpdater = Box::new(move |input: RuleContent| -> BoxFuture<'static, ()> { + let n = n.clone(); + let inner: Arc> = inner_clone.clone(); + Box::pin(async move { + let mut inner = inner.write().await; + trace!("updated rules for: {}", n); + inner.content = input; + }) + }); let n = name.clone(); - let parser: Box anyhow::Result + Send + Sync + 'static> = - Box::new(move |input: &[u8]| -> anyhow::Result { - let scheme: ProviderScheme = serde_yaml::from_slice(input).map_err(|x| { - Error::InvalidConfig(format!("proxy provider parse error {}: {}", n, x)) - })?; - let rules = make_rules(behovior, scheme.payload, mmdb.clone())?; - Ok(rules) - }); + let parser: RuleParser = Box::new(move |input: &[u8]| -> anyhow::Result { + let scheme: ProviderScheme = serde_yaml::from_slice(input).map_err(|x| { + Error::InvalidConfig(format!("proxy provider parse error {}: {}", n, x)) + })?; + let rules = make_rules(behovior, scheme.payload, mmdb.clone())?; + Ok(rules) + }); let fetcher = Fetcher::new(name, interval, vehicle, parser, Some(updater)); @@ -135,7 +133,7 @@ impl RuleProvider for RuleProviderImpl { match inner { Ok(inner) => match &inner.content { RuleContent::Domain(trie) => trie.search(&sess.destination.host()).is_some(), - RuleContent::IPCIDR(trie) => trie.contains( + RuleContent::Ipcidr(trie) => trie.contains( sess.destination .ip() .unwrap_or(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))), @@ -214,11 +212,11 @@ impl Provider for RuleProviderImpl { fn make_rules( behavior: RuleSetBehavior, rules: Vec, - mmdb: Arc, + mmdb: Arc, ) -> Result { match behavior { RuleSetBehavior::Domain => Ok(RuleContent::Domain(make_domain_rules(rules)?)), - RuleSetBehavior::IPCIDR => Ok(RuleContent::IPCIDR(make_ip_cidr_rules(rules)?)), + RuleSetBehavior::Ipcidr => Ok(RuleContent::Ipcidr(Box::new(make_ip_cidr_rules(rules)?))), RuleSetBehavior::Classical => { Ok(RuleContent::Classical(make_classical_rules(rules, mmdb)?)) } @@ -243,11 +241,11 @@ fn make_ip_cidr_rules(rules: Vec) -> Result { fn make_classical_rules( rules: Vec, - mmdb: Arc, + mmdb: Arc, ) -> Result>, Error> { let mut rv = vec![]; for rule in rules { - let parts = rule.split(",").map(str::trim).collect::>(); + let parts = rule.split(',').map(str::trim).collect::>(); // the rule inside RULE-SET is slightly different from the rule in config // the target is always empty as it's holded in the RULE-SET container diff --git a/clash_lib/src/app/router/mod.rs b/clash_lib/src/app/router/mod.rs index 53583dbe7..56df17145 100644 --- a/clash_lib/src/app/router/mod.rs +++ b/clash_lib/src/app/router/mod.rs @@ -1,11 +1,11 @@ use crate::app::router::rules::domain::Domain; use crate::app::router::rules::domain_keyword::DomainKeyword; use crate::app::router::rules::domain_suffix::DomainSuffix; -use crate::app::router::rules::ipcidr::IPCIDR; +use crate::app::router::rules::ipcidr::IpCidr; use crate::app::router::rules::ruleset::RuleSet; use crate::Error; -use crate::common::mmdb::MMDB; +use crate::common::mmdb::Mmdb; use crate::config::internal::config::RuleProviderDef; use crate::config::internal::rule::RuleType; use crate::session::{Session, SocksAddr}; @@ -44,7 +44,7 @@ impl Router { rules: Vec, rule_providers: HashMap, dns_resolver: ThreadSafeDNSResolver, - mmdb: Arc, + mmdb: Arc, cwd: String, ) -> Self { let mut rule_provider_registry = HashMap::new(); @@ -82,15 +82,13 @@ impl Router { "rule {r} local resolving domain {}", sess.destination.domain().unwrap() ); - if let Ok(ip) = self + if let Ok(Some(ip)) = self .dns_resolver .resolve(sess.destination.domain().unwrap(), false) .await { - if let Some(ip) = ip { - sess_dup.destination = SocksAddr::from((ip, sess.destination.port())); - sess_resolved = true; - } + sess_dup.destination = SocksAddr::from((ip, sess.destination.port())); + sess_resolved = true; } } @@ -112,7 +110,7 @@ impl Router { rule_providers: HashMap, rule_provider_registry: &mut HashMap, resolver: ThreadSafeDNSResolver, - mmdb: Arc, + mmdb: Arc, cwd: String, ) -> Result<(), Error> { for (name, provider) in rule_providers.into_iter() { @@ -121,7 +119,7 @@ impl Router { let vehicle = http_vehicle::Vehicle::new( http.url .parse::() - .expect(format!("invalid provider url: {}", http.url).as_str()), + .unwrap_or_else(|_| panic!("invalid provider url: {}", http.url)), http.path, Some(cwd.clone()), resolver.clone(), @@ -184,7 +182,7 @@ impl Router { pub fn map_rule_type( rule_type: RuleType, - mmdb: Arc, + mmdb: Arc, rule_provider_registry: Option<&HashMap>, ) -> Box { match rule_type { @@ -205,21 +203,21 @@ pub fn map_rule_type( keyword: domain_keyword, target, }), - RuleType::IPCIDR { + RuleType::IpCidr { ipnet, target, no_resolve, - } => Box::new(IPCIDR { + } => Box::new(IpCidr { ipnet, target, no_resolve, match_src: false, }), - RuleType::SRCIPCIDR { + RuleType::SrcCidr { ipnet, target, no_resolve, - } => Box::new(IPCIDR { + } => Box::new(IpCidr { ipnet, target, no_resolve, @@ -268,7 +266,7 @@ pub fn map_rule_type( target, rule_provider_registry .get(&rule_set) - .expect(format!("rule provider {} not found", rule_set).as_str()) + .unwrap_or_else(|| panic!("rule provider {} not found", rule_set)) .clone(), )), None => unreachable!("you shouldn't next rule-set within another rule-set"), diff --git a/clash_lib/src/app/router/rules/domain_suffix.rs b/clash_lib/src/app/router/rules/domain_suffix.rs index b9b0267bb..5144c8cd8 100644 --- a/clash_lib/src/app/router/rules/domain_suffix.rs +++ b/clash_lib/src/app/router/rules/domain_suffix.rs @@ -33,6 +33,6 @@ impl RuleMatcher for DomainSuffix { } fn type_name(&self) -> &str { - "DomainSuffix".into() + "DomainSuffix" } } diff --git a/clash_lib/src/app/router/rules/geoip.rs b/clash_lib/src/app/router/rules/geoip.rs index 12a57496f..a69adfe12 100644 --- a/clash_lib/src/app/router/rules/geoip.rs +++ b/clash_lib/src/app/router/rules/geoip.rs @@ -11,7 +11,7 @@ pub struct GeoIP { pub target: String, pub country_code: String, pub no_resolve: bool, - pub mmdb: Arc, + pub mmdb: Arc, } impl std::fmt::Display for GeoIP { diff --git a/clash_lib/src/app/router/rules/ipcidr.rs b/clash_lib/src/app/router/rules/ipcidr.rs index c23b0f886..dfb5bd974 100644 --- a/clash_lib/src/app/router/rules/ipcidr.rs +++ b/clash_lib/src/app/router/rules/ipcidr.rs @@ -2,14 +2,14 @@ use crate::app::router::rules::RuleMatcher; use crate::session::{Session, SocksAddr}; #[derive(Clone)] -pub struct IPCIDR { +pub struct IpCidr { pub ipnet: ipnet::IpNet, pub target: String, pub match_src: bool, pub no_resolve: bool, } -impl std::fmt::Display for IPCIDR { +impl std::fmt::Display for IpCidr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, @@ -21,7 +21,7 @@ impl std::fmt::Display for IPCIDR { } } -impl RuleMatcher for IPCIDR { +impl RuleMatcher for IpCidr { fn apply(&self, sess: &Session) -> bool { match self.match_src { true => self.ipnet.contains(&sess.source.ip()), diff --git a/clash_lib/src/common/auth.rs b/clash_lib/src/common/auth.rs index 7adebfa29..22388db82 100644 --- a/clash_lib/src/common/auth.rs +++ b/clash_lib/src/common/auth.rs @@ -46,6 +46,6 @@ impl Authenticator for PlainAuthenticator { } fn enabled(&self) -> bool { - self.usernames.len() > 0 + !self.usernames.is_empty() } } diff --git a/clash_lib/src/common/http.rs b/clash_lib/src/common/http.rs index e5a1de2b0..57e0fa7bc 100644 --- a/clash_lib/src/common/http.rs +++ b/clash_lib/src/common/http.rs @@ -33,7 +33,7 @@ impl Service for LocalConnector { fn call(&mut self, remote: Uri) -> Self::Future { let host = remote .host() - .expect(format!("invalid url: {}", remote.to_string()).as_str()) + .unwrap_or_else(|| panic!("invalid url: {}", remote)) .to_owned(); let dns = self.0.clone(); @@ -45,8 +45,8 @@ impl Service for LocalConnector { remote.port_u16().unwrap_or(match remote.scheme_str() { None => 80, Some(s) => match s { - s if s == "http" => 80, - s if s == "https" => 443, + "http" => 80, + "https" => 443, _ => panic!("invalid url: {}", remote), }, }), diff --git a/clash_lib/src/common/mmdb.rs b/clash_lib/src/common/mmdb.rs index c5b38b099..c49267969 100644 --- a/clash_lib/src/common/mmdb.rs +++ b/clash_lib/src/common/mmdb.rs @@ -13,16 +13,16 @@ use crate::{ Error, }; -pub struct MMDB { +pub struct Mmdb { reader: maxminddb::Reader>, } -impl MMDB { +impl Mmdb { pub async fn new>( path: P, download_url: Option, http_client: HttpClient, - ) -> Result { + ) -> Result { debug!("mmdb path: {}", path.as_ref().to_string_lossy()); let reader = Self::load_mmdb(path, download_url, &http_client).await?; Ok(Self { reader }) @@ -38,15 +38,14 @@ impl MMDB { if !mmdb_file.exists() { if let Some(url) = download_url.as_ref() { info!("downloading mmdb from {}", url); - Self::download(url, &mmdb_file, &http_client) + Self::download(url, &mmdb_file, http_client) .await .map_err(|x| Error::InvalidConfig(format!("mmdb download failed: {}", x)))?; } else { return Err(Error::InvalidConfig(format!( "mmdb `{}` not found and mmdb_download_url is not set", path.as_ref().to_string_lossy() - )) - .into()); + ))); } } @@ -65,7 +64,7 @@ impl MMDB { fs::remove_file(&mmdb_file)?; if let Some(url) = download_url.as_ref() { info!("downloading mmdb from {}", url); - Self::download(url, &mmdb_file, &http_client) + Self::download(url, &mmdb_file, http_client) .await .map_err(|x| { Error::InvalidConfig(format!("mmdb download failed: {}", x)) @@ -74,23 +73,21 @@ impl MMDB { Error::InvalidConfig(format!( "cant open mmdb `{}`: {}", path.as_ref().to_string_lossy(), - x.to_string() + x )) })?) } else { - return Err(Error::InvalidConfig(format!( + Err(Error::InvalidConfig(format!( "mmdb `{}` not found and mmdb_download_url is not set", path.as_ref().to_string_lossy() - )) - .into()); + ))) } } _ => Err(Error::InvalidConfig(format!( "cant open mmdb `{}`: {}", path.as_ref().to_string_lossy(), - e.to_string() - )) - .into()), + e + ))), }, } } diff --git a/clash_lib/src/common/tls.rs b/clash_lib/src/common/tls.rs index 66bd265d8..2637d6bba 100644 --- a/clash_lib/src/common/tls.rs +++ b/clash_lib/src/common/tls.rs @@ -8,7 +8,7 @@ use tracing::warn; use rustls::{Certificate, ServerName}; use std::{sync::Arc, time::SystemTime}; -pub static GLOBAL_ROOT_STORE: Lazy> = Lazy::new(|| global_root_store()); +pub static GLOBAL_ROOT_STORE: Lazy> = Lazy::new(global_root_store); fn global_root_store() -> Arc { let mut root_store = RootCertStore::empty(); diff --git a/clash_lib/src/common/trie.rs b/clash_lib/src/common/trie.rs index 6327ed72c..fa1542662 100644 --- a/clash_lib/src/common/trie.rs +++ b/clash_lib/src/common/trie.rs @@ -20,6 +20,12 @@ pub struct Node { data: Option>, } +impl Default for Node { + fn default() -> Self { + Self::new() + } +} + impl Node { pub fn new() -> Self { Node { @@ -49,6 +55,12 @@ impl Node { } } +impl Default for StringTrie { + fn default() -> Self { + Self::new() + } +} + impl StringTrie { pub fn new() -> Self { StringTrie { @@ -74,7 +86,7 @@ impl StringTrie { _ => self.insert_inner(&parts, data), } - return true; + true } pub fn search(&self, domain: &str) -> Option<&Node> { @@ -84,11 +96,11 @@ impl StringTrie { } let parts = parts.unwrap(); - if parts[0] == "" { + if parts[0].is_empty() { return None; } - if let Some(n) = self.search_inner(&self.root, parts) { + if let Some(n) = Self::search_inner(&self.root, parts) { if n.data.is_some() { return Some(n); } @@ -106,45 +118,45 @@ impl StringTrie { node.add_child(part, Node::new()) } - node = node.get_child_mut(&part.to_owned()).unwrap(); + node = node.get_child_mut(part).unwrap(); } node.data = Some(data); } - fn search_inner<'a>(&'a self, node: &'a Node, parts: Vec<&str>) -> Option<&Node> { - if parts.len() == 0 { + fn search_inner<'a>(node: &'a Node, parts: Vec<&str>) -> Option<&'a Node> { + if parts.is_empty() { return Some(node); } - if let Some(c) = node.get_child(&parts.last().unwrap().to_owned()) { - if let Some(n) = self.search_inner(c, parts[0..parts.len() - 1].into()) { + if let Some(c) = node.get_child(parts.last().unwrap().to_owned()) { + if let Some(n) = Self::search_inner(c, parts[0..parts.len() - 1].into()) { if n.data.is_some() { return Some(n); } } } - if let Some(c) = node.get_child(&WILDCARD.to_owned()) { - if let Some(n) = self.search_inner(c, parts[0..parts.len() - 1].into()) { + if let Some(c) = node.get_child(WILDCARD) { + if let Some(n) = Self::search_inner(c, parts[0..parts.len() - 1].into()) { if n.data.is_some() { return Some(n); } } } - node.get_child(&DOT_WILDCARD.to_owned()) + node.get_child(DOT_WILDCARD) } } pub fn valid_and_split_domain(domain: &str) -> (Option>, bool) { - if domain != "" && domain.ends_with(".") { + if !domain.is_empty() && domain.ends_with('.') { return (None, false); } let parts: Vec<&str> = domain.split(DOMAIN_STEP).collect(); if parts.len() == 1 { - if parts[0] == "" { + if parts[0].is_empty() { return (None, false); } return (Some(parts), true); @@ -179,7 +191,7 @@ mod tests { let node = tree.search("example.com").expect("should be not nil"); assert_eq!(node.data.as_ref().expect("data nil").as_ref(), &LOCAL_IP); - assert_eq!(tree.insert("", Arc::new(LOCAL_IP)), false); + assert!(!tree.insert("", Arc::new(LOCAL_IP))); assert!(tree.search("").is_none()); assert!(tree.search("localhost").is_some()); assert!(tree.search("www.google.com").is_none()); @@ -224,7 +236,7 @@ mod tests { fn test_priority() { let mut tree = StringTrie::new(); - let domains = vec![".dev", "example.dev", "*.example.dev", "test.example.dev"]; + let domains = [".dev", "example.dev", "*.example.dev", "test.example.dev"]; for (idx, d) in domains.iter().enumerate() { tree.insert(d, Arc::new(idx)); diff --git a/clash_lib/src/config/def.rs b/clash_lib/src/config/def.rs index c04044e39..da2947eee 100644 --- a/clash_lib/src/config/def.rs +++ b/clash_lib/src/config/def.rs @@ -390,13 +390,13 @@ impl FromStr for Config { type Err = Error; fn from_str(s: &str) -> Result { - Ok(serde_yaml::from_str(s).map_err(|x| { + serde_yaml::from_str(s).map_err(|x| { Error::InvalidConfig(format!( "cound not parse config content {}: {}", s, - x.to_string() + x )) - })?) + }) } } diff --git a/clash_lib/src/config/internal/config.rs b/clash_lib/src/config/internal/config.rs index 89ed0569d..3b5e2393b 100644 --- a/clash_lib/src/config/internal/config.rs +++ b/clash_lib/src/config/internal/config.rs @@ -155,7 +155,7 @@ impl TryFrom for Config { ))); } proxy_names.push(name.clone()); - rv.insert(String::from(name), proxy); + rv.insert(name, proxy); Ok(rv) }, )?, @@ -168,14 +168,14 @@ impl TryFrom for Config { Error::InvalidConfig(format!( "proxy group: {}: {}", name.as_str().expect("proxy group name must be string"), - x.to_string() + x )) } else { Error::InvalidConfig("proxy group name missing".to_string()) } }, )?); - proxy_names.push(group.name().into()); + proxy_names.push(group.name()); rv.insert(group.name().to_string(), group); Ok::, Error>(rv) }, diff --git a/clash_lib/src/config/internal/proxy.rs b/clash_lib/src/config/internal/proxy.rs index 1a4261be1..e934a06a0 100644 --- a/clash_lib/src/config/internal/proxy.rs +++ b/clash_lib/src/config/internal/proxy.rs @@ -11,6 +11,7 @@ pub const PROXY_DIRECT: &str = "DIRECT"; pub const PROXY_REJECT: &str = "REJECT"; pub const PROXY_GLOBAL: &str = "GLOBAL"; +#[allow(clippy::large_enum_variant)] pub enum OutboundProxy { ProxyServer(OutboundProxyProtocol), ProxyGroup(OutboundGroupProtocol), @@ -27,12 +28,7 @@ impl OutboundProxy { pub fn map_serde_error(x: serde_yaml::Error) -> crate::Error { Error::InvalidConfig(if let Some(loc) = x.location() { - format!( - "{}, line, {}, column: {}", - x.to_string(), - loc.line(), - loc.column() - ) + format!("{}, line, {}, column: {}", x, loc.line(), loc.column()) } else { x.to_string() }) @@ -87,9 +83,9 @@ impl Display for OutboundProxyProtocol { OutboundProxyProtocol::Socks5(_) => write!(f, "Socks5"), OutboundProxyProtocol::Direct => write!(f, "{}", PROXY_DIRECT), OutboundProxyProtocol::Reject => write!(f, "{}", PROXY_REJECT), - OutboundProxyProtocol::Trojan(_) => write!(f, "{}", "Trojan"), - OutboundProxyProtocol::Vmess(_) => write!(f, "{}", "Vmess"), - OutboundProxyProtocol::Wireguard(_) => write!(f, "{}", "Wireguard"), + OutboundProxyProtocol::Trojan(_) => write!(f, "Trojan"), + OutboundProxyProtocol::Vmess(_) => write!(f, "Vmess"), + OutboundProxyProtocol::Wireguard(_) => write!(f, "Wireguard"), } } } diff --git a/clash_lib/src/config/internal/rule.rs b/clash_lib/src/config/internal/rule.rs index 7a17a5043..3fd28b859 100644 --- a/clash_lib/src/config/internal/rule.rs +++ b/clash_lib/src/config/internal/rule.rs @@ -19,12 +19,12 @@ pub enum RuleType { country_code: String, no_resolve: bool, }, - IPCIDR { + IpCidr { ipnet: ipnet::IpNet, target: String, no_resolve: bool, }, - SRCIPCIDR { + SrcCidr { ipnet: ipnet::IpNet, target: String, no_resolve: bool, @@ -61,8 +61,8 @@ impl RuleType { RuleType::DomainSuffix { target, .. } => target, RuleType::DomainKeyword { target, .. } => target, RuleType::GeoIP { target, .. } => target, - RuleType::IPCIDR { target, .. } => target, - RuleType::SRCIPCIDR { target, .. } => target, + RuleType::IpCidr { target, .. } => target, + RuleType::SrcCidr { target, .. } => target, RuleType::SRCPort { target, .. } => target, RuleType::DSTPort { target, .. } => target, RuleType::ProcessName { target, .. } => target, @@ -80,8 +80,8 @@ impl Display for RuleType { RuleType::DomainSuffix { .. } => write!(f, "DOMAIN-SUFFIX"), RuleType::DomainKeyword { .. } => write!(f, "DOMAIN-KEYWORD"), RuleType::GeoIP { .. } => write!(f, "GEOIP"), - RuleType::IPCIDR { .. } => write!(f, "IP-CIDR"), - RuleType::SRCIPCIDR { .. } => write!(f, "SRC-IP-CIDR"), + RuleType::IpCidr { .. } => write!(f, "IP-CIDR"), + RuleType::SrcCidr { .. } => write!(f, "SRC-IP-CIDR"), RuleType::SRCPort { .. } => write!(f, "SRC-PORT"), RuleType::DSTPort { .. } => write!(f, "DST-PORT"), RuleType::ProcessName { .. } => write!(f, "PROCESS-NAME"), @@ -121,7 +121,7 @@ impl RuleType { false }, }), - "IP-CIDR" | "IP-CIDR6" => Ok(RuleType::IPCIDR { + "IP-CIDR" | "IP-CIDR6" => Ok(RuleType::IpCidr { ipnet: payload.parse()?, target: target.to_string(), no_resolve: if let Some(params) = params { @@ -130,7 +130,7 @@ impl RuleType { false }, }), - "SRC-IP-CIDR" => Ok(RuleType::SRCIPCIDR { + "SRC-IP-CIDR" => Ok(RuleType::SrcCidr { ipnet: payload.parse()?, target: target.to_string(), no_resolve: if let Some(params) = params { @@ -143,13 +143,13 @@ impl RuleType { target: target.to_string(), port: payload .parse() - .expect(format!("invalid port: {}", payload).as_str()), + .unwrap_or_else(|_| panic!("invalid port: {}", payload)), }), "DST-PORT" => Ok(RuleType::DSTPort { target: target.to_string(), port: payload .parse() - .expect(format!("invalid port: {}", payload).as_str()), + .unwrap_or_else(|_| panic!("invalid port: {}", payload)), }), "PROCESS-NAME" => Ok(RuleType::ProcessName { process_name: payload.to_string(), @@ -178,7 +178,7 @@ impl TryFrom for RuleType { type Error = crate::Error; fn try_from(line: String) -> Result { - let parts = line.split(",").map(str::trim).collect::>(); + let parts = line.split(',').map(str::trim).collect::>(); match parts.as_slice() { [proto, target] => RuleType::new(proto, "", target, None), diff --git a/clash_lib/src/lib.rs b/clash_lib/src/lib.rs index f5b479ccd..8e36113af 100644 --- a/clash_lib/src/lib.rs +++ b/clash_lib/src/lib.rs @@ -71,6 +71,7 @@ pub enum TokioRuntime { SingleThread, } +#[allow(clippy::large_enum_variant)] pub enum Config { Def(ClashConfigDef), Internal(InternalConfig), @@ -107,10 +108,10 @@ static RUNTIME_CONTROLLER: OnceLock> = Once pub fn start(opts: Options) -> Result<(), Error> { let rt = match opts.rt.as_ref().unwrap_or(&TokioRuntime::MultiThread) { - &TokioRuntime::MultiThread => tokio::runtime::Builder::new_multi_thread() + TokioRuntime::MultiThread => tokio::runtime::Builder::new_multi_thread() .enable_all() .build()?, - &TokioRuntime::SingleThread => tokio::runtime::Builder::new_current_thread() + TokioRuntime::SingleThread => tokio::runtime::Builder::new_current_thread() .enable_all() .build()?, }; @@ -146,13 +147,9 @@ async fn start_async(opts: Options) -> Result<(), Error> { let log_collector = app::logging::EventCollector::new(vec![log_tx.clone()]); - let _g = app::logging::setup_logging( - config.general.log_level, - log_collector, - &cwd, - opts.log_file, - ) - .map_err(|x| Error::InvalidConfig(format!("failed to setup logging: {}", x.to_string())))?; + let _g = + app::logging::setup_logging(config.general.log_level, log_collector, &cwd, opts.log_file) + .map_err(|x| Error::InvalidConfig(format!("failed to setup logging: {}", x)))?; let default_panic = std::panic::take_hook(); std::panic::set_hook(Box::new(move |info| { @@ -171,7 +168,7 @@ async fn start_async(opts: Options) -> Result<(), Error> { debug!("initializing mmdb"); let cwd = PathBuf::from(cwd); let mmdb = Arc::new( - mmdb::MMDB::new( + mmdb::Mmdb::new( cwd.join(&config.general.mmdb), config.general.mmdb_download_url, client, @@ -185,7 +182,8 @@ async fn start_async(opts: Options) -> Result<(), Error> { config.profile.store_selected, ); - let dns_resolver = dns::Resolver::new(&config.dns, cache_store.clone(), mmdb.clone()).await; + let dns_resolver = + dns::Resolver::new_resolver(&config.dns, cache_store.clone(), mmdb.clone()).await; debug!("initializing outbound manager"); let outbound_manager = Arc::new( @@ -250,16 +248,12 @@ async fn start_async(opts: Options) -> Result<(), Error> { let inbound_listener_handle = tokio::spawn(inbound_runner); let tun_runner = get_tun_runner(config.tun, dispatcher.clone(), dns_resolver.clone())?; - let tun_runner_handle = if let Some(tun_runner) = tun_runner { - Some(tokio::spawn(tun_runner)) - } else { - None - }; + let tun_runner_handle = tun_runner.map(tokio::spawn); debug!("initializing dns listener"); let dns_listener_handle = dns::get_dns_listener(config.dns, dns_resolver.clone()) .await - .map(|l| tokio::spawn(l)); + .map(tokio::spawn); let (reload_tx, mut reload_rx) = mpsc::channel(1); @@ -325,7 +319,7 @@ async fn start_async(opts: Options) -> Result<(), Error> { debug!("reloading mmdb"); let mmdb = Arc::new( - mmdb::MMDB::new( + mmdb::Mmdb::new( cwd.join(&config.general.mmdb), config.general.mmdb_download_url, client, @@ -340,7 +334,7 @@ async fn start_async(opts: Options) -> Result<(), Error> { ); let dns_resolver = - dns::Resolver::new(&config.dns, cache_store.clone(), mmdb.clone()).await; + dns::Resolver::new_resolver(&config.dns, cache_store.clone(), mmdb.clone()).await; debug!("reloading outbound manager"); let outbound_manager = Arc::new( @@ -416,16 +410,12 @@ async fn start_async(opts: Options) -> Result<(), Error> { let inbound_listener_handle = tokio::spawn(inbound_runner); let tun_runner = get_tun_runner(config.tun, dispatcher.clone(), dns_resolver.clone())?; - let tun_runner_handle = if let Some(tun_runner) = tun_runner { - Some(tokio::spawn(tun_runner)) - } else { - None - }; + let tun_runner_handle = tun_runner.map(tokio::spawn); debug!("initializing dns listener"); let dns_listener_handle = dns::get_dns_listener(config.dns, dns_resolver.clone()) .await - .map(|l| tokio::spawn(l)); + .map(tokio::spawn); g.inbound_listener_handle = Some(inbound_listener_handle); g.tunnel_listener_handle = tun_runner_handle; diff --git a/clash_lib/src/proxy/converters/shadowsocks.rs b/clash_lib/src/proxy/converters/shadowsocks.rs index 6ebe88951..b916650c9 100644 --- a/clash_lib/src/proxy/converters/shadowsocks.rs +++ b/clash_lib/src/proxy/converters/shadowsocks.rs @@ -35,7 +35,7 @@ impl TryFrom<&OutboundShadowsocks> for AnyOutboundHandler { "plugin_opts is required for plugin obfs".to_owned(), ))? .try_into() - .map(|x| OBFSOption::Simple(x)) + .map(OBFSOption::Simple) .ok(), "v2ray-plugin" => s .plugin_opts @@ -44,7 +44,7 @@ impl TryFrom<&OutboundShadowsocks> for AnyOutboundHandler { "plugin_opts is required for plugin obfs".to_owned(), ))? .try_into() - .map(|x| OBFSOption::V2Ray(x)) + .map(OBFSOption::V2Ray) .ok(), _ => { return Err(Error::InvalidConfig(format!( diff --git a/clash_lib/src/proxy/converters/trojan.rs b/clash_lib/src/proxy/converters/trojan.rs index 40f322dae..fe5d1a6d1 100644 --- a/clash_lib/src/proxy/converters/trojan.rs +++ b/clash_lib/src/proxy/converters/trojan.rs @@ -83,7 +83,7 @@ impl TryFrom<&OutboundTrojan> for AnyOutboundHandler { "grpc_opts is required for grpc".to_owned(), )), _ => { - return Err(Error::InvalidConfig(format!( + Err(Error::InvalidConfig(format!( "unsupported trojan network: {}", x ))) diff --git a/clash_lib/src/proxy/converters/vmess.rs b/clash_lib/src/proxy/converters/vmess.rs index d4c31520a..694725102 100644 --- a/clash_lib/src/proxy/converters/vmess.rs +++ b/clash_lib/src/proxy/converters/vmess.rs @@ -92,7 +92,7 @@ impl TryFrom<&OutboundVmess> for AnyOutboundHandler { "grpc_opts is required for grpc".to_owned(), )), _ => { - return Err(Error::InvalidConfig(format!("unsupported network: {}", x))); + Err(Error::InvalidConfig(format!("unsupported network: {}", x))) } }) .transpose()?, @@ -102,17 +102,15 @@ impl TryFrom<&OutboundVmess> for AnyOutboundHandler { sni: s.server_name.as_ref().map(|x| x.to_owned()).unwrap_or( s.ws_opts .as_ref() - .map(|x| { + .and_then(|x| { x.headers .as_ref() .map(Clone::clone) - .map(|x| { + .and_then(|x| { let h = x.get("Host"); h.map(Clone::clone) }) - .flatten() }) - .flatten() .unwrap_or(s.server.to_owned()) .to_owned(), ), diff --git a/clash_lib/src/proxy/datagram.rs b/clash_lib/src/proxy/datagram.rs index 6f53a5ba1..15f026124 100644 --- a/clash_lib/src/proxy/datagram.rs +++ b/clash_lib/src/proxy/datagram.rs @@ -142,6 +142,7 @@ pub struct OutboundDatagramImpl { } impl OutboundDatagramImpl { + #[allow(clippy::new_ret_no_self)] pub fn new(udp: UdpSocket, resolver: ThreadSafeDNSResolver) -> AnyOutboundDatagram { let s = Self { inner: udp, @@ -193,7 +194,7 @@ impl Sink for OutboundDatagramImpl { let dst = match dst { SocksAddr::Domain(domain, port) => { let domain = domain.to_string(); - let port = *port as u16; + let port = *port; let mut fut = resolver.resolve(domain.as_str(), false); let ip = ready!(fut.as_mut().poll(cx).map_err(|_| { io::Error::new(io::ErrorKind::Other, "resolve domain failed") diff --git a/clash_lib/src/proxy/direct/mod.rs b/clash_lib/src/proxy/direct/mod.rs index b18f74356..8abf99ff1 100644 --- a/clash_lib/src/proxy/direct/mod.rs +++ b/clash_lib/src/proxy/direct/mod.rs @@ -19,6 +19,7 @@ use super::OutboundType; pub struct Handler; impl Handler { + #[allow(clippy::new_ret_no_self)] pub fn new() -> AnyOutboundHandler { Arc::new(Self) } diff --git a/clash_lib/src/proxy/fallback/mod.rs b/clash_lib/src/proxy/fallback/mod.rs index 7e8449879..6f7f16b47 100644 --- a/clash_lib/src/proxy/fallback/mod.rs +++ b/clash_lib/src/proxy/fallback/mod.rs @@ -8,7 +8,7 @@ use crate::{ dispatcher::{BoxedChainedDatagram, BoxedChainedStream}, dns::ThreadSafeDNSResolver, remote_content_manager::{ - providers::proxy_provider::proxy_provider::ThreadSafeProxyProvider, ProxyManager, + providers::proxy_provider::ThreadSafeProxyProvider, ProxyManager, }, }, session::{Session, SocksAddr}, @@ -58,7 +58,7 @@ impl Handler { return proxy.clone(); } } - return proxies[0].clone(); + proxies[0].clone() } } diff --git a/clash_lib/src/proxy/http/inbound/auth.rs b/clash_lib/src/proxy/http/inbound/auth.rs index bf4bc2256..cb1e93f47 100644 --- a/clash_lib/src/proxy/http/inbound/auth.rs +++ b/clash_lib/src/proxy/http/inbound/auth.rs @@ -9,24 +9,18 @@ fn parse_basic_proxy_authorization(req: &Request) -> Option<&str> { req.headers() .get(http::header::PROXY_AUTHORIZATION) .map(|v| v.to_str().unwrap_or_default()) - .map(|v| { - if v.starts_with("Basic ") { - Some(&v[6..]) - } else { - None - } - }) + .map(|v| v.strip_prefix("Basic ")) .and_then(|v| v) } + fn decode_basic_proxy_authorization(cred: &str) -> Option<(String, String)> { let decoded = base64::engine::general_purpose::STANDARD .decode(cred) .ok()?; let s = std::str::from_utf8(&decoded).ok()?; - let mut parts = s.splitn(2, ":"); - let user = parts.next()?; - let pass = parts.next()?; + let (user, pass) = s.split_once(':')?; + Some((user.to_owned(), pass.to_owned())) } diff --git a/clash_lib/src/proxy/http/inbound/connector.rs b/clash_lib/src/proxy/http/inbound/connector.rs index ae48fa67f..cf227f962 100644 --- a/clash_lib/src/proxy/http/inbound/connector.rs +++ b/clash_lib/src/proxy/http/inbound/connector.rs @@ -38,7 +38,7 @@ impl tower::Service for Connector { } fn call(&mut self, url: Uri) -> Self::Future { - let src = self.src.clone(); + let src = self.src; let dispatcher = self.dispatcher.clone(); let destination = maybe_socks_addr(&url); diff --git a/clash_lib/src/proxy/http/inbound/mod.rs b/clash_lib/src/proxy/http/inbound/mod.rs index 98193da64..352926909 100644 --- a/clash_lib/src/proxy/http/inbound/mod.rs +++ b/clash_lib/src/proxy/http/inbound/mod.rs @@ -30,6 +30,7 @@ impl Drop for Listener { } impl Listener { + #[allow(clippy::new_ret_no_self)] pub fn new( addr: SocketAddr, dispatcher: Arc, diff --git a/clash_lib/src/proxy/http/inbound/proxy.rs b/clash_lib/src/proxy/http/inbound/proxy.rs index 74419951c..c288f794a 100644 --- a/clash_lib/src/proxy/http/inbound/proxy.rs +++ b/clash_lib/src/proxy/http/inbound/proxy.rs @@ -53,7 +53,7 @@ async fn proxy( let client = Client::builder() .http1_title_case_headers(true) .http1_preserve_header_case(true) - .build(Connector::new(src.clone(), dispatcher.clone())); + .build(Connector::new(src, dispatcher.clone())); // TODO: handle other upgrades: https://github.com/hyperium/hyper/blob/master/examples/upgrades.rs if req.method() == Method::CONNECT { @@ -80,7 +80,7 @@ async fn proxy( } else { Ok(Response::builder() .status(http::StatusCode::BAD_REQUEST) - .body(format!("invalid request uri: {}", req.uri().to_string()).into()) + .body(format!("invalid request uri: {}", req.uri()).into()) .unwrap()) } } else { diff --git a/clash_lib/src/proxy/loadbalance/helpers.rs b/clash_lib/src/proxy/loadbalance/helpers.rs index f07d941ff..54fcfc8df 100644 --- a/clash_lib/src/proxy/loadbalance/helpers.rs +++ b/clash_lib/src/proxy/loadbalance/helpers.rs @@ -19,7 +19,7 @@ fn get_key(sess: &Session) -> String { match &sess.destination { crate::session::SocksAddr::Ip(addr) => addr.ip().to_string(), crate::session::SocksAddr::Domain(host, _) => DEFAULT_PROVIDER - .effective_tld_plus_one(&host) + .effective_tld_plus_one(host) .map(|s| s.to_string()) .unwrap_or_default(), } @@ -49,7 +49,7 @@ pub fn strategy_rr() -> StrategyFn { pub fn strategy_consistent_hashring() -> StrategyFn { let max_retry = 5; Box::new(move |proxies, sess| { - let key = murmur3_32(&mut Cursor::new(get_key(&sess)), 0).unwrap() as u64; + let key = murmur3_32(&mut Cursor::new(get_key(sess)), 0).unwrap() as u64; let buckets = proxies.len() as i32; for _ in 0..max_retry { let index = jump_hash(key, buckets); @@ -57,9 +57,9 @@ pub fn strategy_consistent_hashring() -> StrategyFn { return Box::pin(futures::future::ok(proxy.clone())); } } - return Box::pin(futures::future::err(std::io::Error::new( + Box::pin(futures::future::err(std::io::Error::new( std::io::ErrorKind::Other, "no proxy found", - ))); + ))) }) } diff --git a/clash_lib/src/proxy/loadbalance/mod.rs b/clash_lib/src/proxy/loadbalance/mod.rs index ee7ee11aa..fb65f7825 100644 --- a/clash_lib/src/proxy/loadbalance/mod.rs +++ b/clash_lib/src/proxy/loadbalance/mod.rs @@ -93,7 +93,7 @@ impl OutboundHandler for Handler { resolver: ThreadSafeDNSResolver, ) -> io::Result { let proxies = self.get_proxies(false).await; - let proxy = (self.inner.lock().await.strategy_fn)(proxies, &sess).await?; + let proxy = (self.inner.lock().await.strategy_fn)(proxies, sess).await?; debug!("{} use proxy {}", self.name(), proxy.name()); match proxy.connect_stream(sess, resolver).await { Ok(s) => { @@ -112,7 +112,7 @@ impl OutboundHandler for Handler { resolver: ThreadSafeDNSResolver, ) -> io::Result { let proxies = self.get_proxies(false).await; - let proxy = (self.inner.lock().await.strategy_fn)(proxies, &sess).await?; + let proxy = (self.inner.lock().await.strategy_fn)(proxies, sess).await?; debug!("{} use proxy {}", self.name(), proxy.name()); proxy.proxy_stream(s, sess, resolver).await } @@ -124,7 +124,7 @@ impl OutboundHandler for Handler { resolver: ThreadSafeDNSResolver, ) -> io::Result { let proxies = self.get_proxies(false).await; - let proxy = (self.inner.lock().await.strategy_fn)(proxies, &sess).await?; + let proxy = (self.inner.lock().await.strategy_fn)(proxies, sess).await?; debug!("{} use proxy {}", self.name(), proxy.name()); proxy.connect_datagram(sess, resolver).await } diff --git a/clash_lib/src/proxy/mixed/mod.rs b/clash_lib/src/proxy/mixed/mod.rs index 9cd2326cc..371e162a4 100644 --- a/clash_lib/src/proxy/mixed/mod.rs +++ b/clash_lib/src/proxy/mixed/mod.rs @@ -25,6 +25,7 @@ impl Drop for Listener { } impl Listener { + #[allow(clippy::new_ret_no_self)] pub fn new( addr: SocketAddr, dispatcher: Arc, diff --git a/clash_lib/src/proxy/reject/mod.rs b/clash_lib/src/proxy/reject/mod.rs index b96bb31d4..1b914cbb1 100644 --- a/clash_lib/src/proxy/reject/mod.rs +++ b/clash_lib/src/proxy/reject/mod.rs @@ -14,6 +14,8 @@ use super::OutboundType; pub struct Handler; impl Handler { + #[allow(clippy::new_ret_no_self)] + pub fn new() -> AnyOutboundHandler { Arc::new(Self) } diff --git a/clash_lib/src/proxy/relay/mod.rs b/clash_lib/src/proxy/relay/mod.rs index 1af3217e6..39bb69539 100644 --- a/clash_lib/src/proxy/relay/mod.rs +++ b/clash_lib/src/proxy/relay/mod.rs @@ -34,6 +34,7 @@ pub struct Handler { } impl Handler { + #[allow(clippy::new_ret_no_self)] pub fn new( opts: HandlerOptions, providers: Vec, @@ -70,12 +71,7 @@ impl OutboundHandler for Handler { resolver: ThreadSafeDNSResolver, ) -> io::Result { let proxies: Vec = stream::iter(self.get_proxies(true).await) - .filter_map(|x| async { - match x.remote_addr().await { - Some(_) => Some(x), - None => None, - } - }) + .filter_map(|x| async { x.remote_addr().await.map(|_| x) }) .collect() .await; @@ -102,8 +98,8 @@ impl OutboundHandler for Handler { .await?; let mut next_sess = sess.clone(); - for i in 1..proxies.len() { - let proxy = proxies[i].clone(); + for proxy in proxies.iter().skip(1) { + let proxy = proxy.clone(); next_sess.destination = proxy.remote_addr().await.expect("must have remote addr"); s = first.proxy_stream(s, &next_sess, resolver.clone()).await?; @@ -111,7 +107,7 @@ impl OutboundHandler for Handler { first = proxy; } - s = last.proxy_stream(s, &sess, resolver).await?; + s = last.proxy_stream(s, sess, resolver).await?; let chained = ChainedStreamWrapper::new(s); chained.append_to_chain(self.name()).await; Ok(Box::new(chained)) diff --git a/clash_lib/src/proxy/selector/mod.rs b/clash_lib/src/proxy/selector/mod.rs index 8fb6ee7e2..29891dfdc 100644 --- a/clash_lib/src/proxy/selector/mod.rs +++ b/clash_lib/src/proxy/selector/mod.rs @@ -91,8 +91,8 @@ impl SelectorControl for Handler { } async fn current(&self) -> String { - let inner = self.inner.read().await.current.to_owned(); - inner + + self.inner.read().await.current.to_owned() } } diff --git a/clash_lib/src/proxy/shadowsocks/datagram.rs b/clash_lib/src/proxy/shadowsocks/datagram.rs index fbe0cf217..9e3e9f481 100644 --- a/clash_lib/src/proxy/shadowsocks/datagram.rs +++ b/clash_lib/src/proxy/shadowsocks/datagram.rs @@ -26,6 +26,7 @@ pub struct OutboundDatagramShadowsocks { } impl OutboundDatagramShadowsocks { + #[allow(clippy::new_ret_no_self)] pub fn new( inner: ProxySocket, remote_addr: (String, u16), diff --git a/clash_lib/src/proxy/shadowsocks/mod.rs b/clash_lib/src/proxy/shadowsocks/mod.rs index 49a95c433..f3e42e743 100644 --- a/clash_lib/src/proxy/shadowsocks/mod.rs +++ b/clash_lib/src/proxy/shadowsocks/mod.rs @@ -150,6 +150,7 @@ pub struct Handler { } impl Handler { + #[allow(clippy::new_ret_no_self)] pub fn new(opts: HandlerOptions) -> AnyOutboundHandler { Arc::new(Self { opts }) } diff --git a/clash_lib/src/proxy/socks/inbound/mod.rs b/clash_lib/src/proxy/socks/inbound/mod.rs index 4b37c807f..e6a4f8bc3 100644 --- a/clash_lib/src/proxy/socks/inbound/mod.rs +++ b/clash_lib/src/proxy/socks/inbound/mod.rs @@ -54,6 +54,7 @@ impl Drop for Listener { } impl Listener { + #[allow(clippy::new_ret_no_self)] pub fn new( addr: SocketAddr, dispatcher: Arc, diff --git a/clash_lib/src/proxy/transport/grpc.rs b/clash_lib/src/proxy/transport/grpc.rs index e75fd1442..95ec46ea3 100644 --- a/clash_lib/src/proxy/transport/grpc.rs +++ b/clash_lib/src/proxy/transport/grpc.rs @@ -88,15 +88,15 @@ impl GrpcStreamBuilder { debug!("grpc resp err: {:?}", e); } } - let _ = init_sender.send(()); + let _ = init_sender.send(()).await; }); } - return Ok(Box::new(GrpcStream::new( + Ok(Box::new(GrpcStream::new( init_ready, recv_stream, send_stream, - ))); + ))) } } @@ -171,7 +171,7 @@ impl AsyncRead for GrpcStream { ))); } - if (self.payload_len > 0 && self.buffer.len() > 0) + if (self.payload_len > 0 && !self.buffer.is_empty()) || (self.payload_len == 0 && self.buffer.len() > 6) { if self.payload_len == 0 { @@ -181,7 +181,7 @@ impl AsyncRead for GrpcStream { } trace!("grpc poll_read data left payload_len: {}", self.payload_len); - let to_read = std::cmp::min(buf.remaining(), self.payload_len as usize); + let to_read = std::cmp::min(buf.remaining(), self.payload_len); let to_read = std::cmp::min(to_read, self.buffer.len()); if to_read == 0 { @@ -220,7 +220,7 @@ impl AsyncRead for GrpcStream { let payload_len = decode_varint(&mut self.buffer).map_err(map_io_error)?; self.payload_len = payload_len as usize; } - let to_read = std::cmp::min(self.buffer.len(), self.payload_len as usize); + let to_read = std::cmp::min(self.buffer.len(), self.payload_len); let to_read = std::cmp::min(buf.remaining(), to_read); if to_read == 0 { break; diff --git a/clash_lib/src/proxy/transport/mod.rs b/clash_lib/src/proxy/transport/mod.rs index 37b7b57bc..ee1e50aab 100644 --- a/clash_lib/src/proxy/transport/mod.rs +++ b/clash_lib/src/proxy/transport/mod.rs @@ -2,11 +2,11 @@ mod grpc; mod h2; #[path = "tls.rs"] mod internal_tls; -mod websocket; +mod ws; -pub use websocket::WebsocketConn; -pub use websocket::WebsocketEarlyDataConn; -pub use websocket::WebsocketStreamBuilder; +pub use ws::WebsocketConn; +pub use ws::WebsocketEarlyDataConn; +pub use ws::WebsocketStreamBuilder; pub use grpc::GrpcStream; pub use grpc::GrpcStreamBuilder; diff --git a/clash_lib/src/proxy/transport/tls.rs b/clash_lib/src/proxy/transport/tls.rs index 7d6abfa19..55f127e61 100644 --- a/clash_lib/src/proxy/transport/tls.rs +++ b/clash_lib/src/proxy/transport/tls.rs @@ -42,7 +42,7 @@ pub async fn wrap_stream( let connector = TlsConnector::from(Arc::new(tls_config)); let dns_name = ServerName::try_from(opt.sni.as_str()) - .expect(format!("invalid server name: {}", opt.sni).as_str()); + .unwrap_or_else(|_| panic!("invalid server name: {}", opt.sni)); let c = connector.connect(dns_name, stream).await.and_then(|x| { if let Some(expected_alpn) = expected_alpn { diff --git a/clash_lib/src/proxy/transport/websocket/mod.rs b/clash_lib/src/proxy/transport/ws/mod.rs similarity index 100% rename from clash_lib/src/proxy/transport/websocket/mod.rs rename to clash_lib/src/proxy/transport/ws/mod.rs diff --git a/clash_lib/src/proxy/transport/websocket/websocket.rs b/clash_lib/src/proxy/transport/ws/websocket.rs similarity index 100% rename from clash_lib/src/proxy/transport/websocket/websocket.rs rename to clash_lib/src/proxy/transport/ws/websocket.rs diff --git a/clash_lib/src/proxy/transport/websocket/websocket_early_data.rs b/clash_lib/src/proxy/transport/ws/websocket_early_data.rs similarity index 100% rename from clash_lib/src/proxy/transport/websocket/websocket_early_data.rs rename to clash_lib/src/proxy/transport/ws/websocket_early_data.rs diff --git a/clash_lib/src/proxy/trojan/datagram.rs b/clash_lib/src/proxy/trojan/datagram.rs index c9e018228..00e20e690 100644 --- a/clash_lib/src/proxy/trojan/datagram.rs +++ b/clash_lib/src/proxy/trojan/datagram.rs @@ -94,7 +94,7 @@ impl Sink for OutboundDatagramTrojan { payload.put_slice(b"\r\n"); payload.put_slice(&data); - while payload.len() != 0 { + while !payload.is_empty() { let n = ready!(inner.as_mut().poll_write(cx, payload.as_ref()))?; payload.advance(n); diff --git a/clash_lib/src/proxy/trojan/mod.rs b/clash_lib/src/proxy/trojan/mod.rs index e83e77557..66a918385 100644 --- a/clash_lib/src/proxy/trojan/mod.rs +++ b/clash_lib/src/proxy/trojan/mod.rs @@ -56,6 +56,7 @@ pub struct Handler { } impl Handler { + #[allow(clippy::new_ret_no_self)] pub fn new(opts: Opts) -> AnyOutboundHandler { Arc::new(Self { opts }) } @@ -73,8 +74,8 @@ impl Handler { sni: self.opts.sni.clone(), alpn: self.opts.alpn.clone().or(Some( DEFAULT_ALPN - .to_vec() - .into_iter() + .iter() + .copied() .map(|x| x.to_owned()) .collect::>(), )), diff --git a/clash_lib/src/proxy/tun/datagram.rs b/clash_lib/src/proxy/tun/datagram.rs index b4759fdb7..d8f2ec966 100644 --- a/clash_lib/src/proxy/tun/datagram.rs +++ b/clash_lib/src/proxy/tun/datagram.rs @@ -100,7 +100,7 @@ impl Sink for TunDatagram { Err(err) => Poll::Ready(Err(new_io_error(err.to_string().as_str()))), } } else { - Poll::Ready(Err(new_io_error("no packet to send".into()))) + Poll::Ready(Err(new_io_error("no packet to send"))) } } diff --git a/clash_lib/src/proxy/urltest/mod.rs b/clash_lib/src/proxy/urltest/mod.rs index 59b4c6785..1480b44ce 100644 --- a/clash_lib/src/proxy/urltest/mod.rs +++ b/clash_lib/src/proxy/urltest/mod.rs @@ -71,7 +71,7 @@ impl Handler { let proxies = self.get_proxies(touch).await; let mut fastest = proxies .first() - .expect(format!("no proxy found for {}", self.name()).as_str()); + .unwrap_or_else(|| panic!("no proxy found for {}", self.name())); let mut fastest_delay = proxy_manager.last_delay(fastest.name()).await; let mut fast_not_exist = true; diff --git a/clash_lib/src/proxy/utils/provider_helper.rs b/clash_lib/src/proxy/utils/provider_helper.rs index 7cc938f99..1d7418d53 100644 --- a/clash_lib/src/proxy/utils/provider_helper.rs +++ b/clash_lib/src/proxy/utils/provider_helper.rs @@ -17,10 +17,7 @@ pub async fn get_proxies_from_providers( .read() .await .proxies() - .await - .iter() - .map(|x| x.clone()) - .collect::>(); + .await.to_vec(); proxies.append(&mut proxies_from_provider); } proxies diff --git a/clash_lib/src/proxy/utils/socket_helpers.rs b/clash_lib/src/proxy/utils/socket_helpers.rs index 118a351db..8d0051a91 100644 --- a/clash_lib/src/proxy/utils/socket_helpers.rs +++ b/clash_lib/src/proxy/utils/socket_helpers.rs @@ -26,7 +26,7 @@ pub fn apply_tcp_options(s: TcpStream) -> std::io::Result { .with_interval(Duration::from_secs(1)) .with_retries(3), )?; - Ok(TcpStream::from_std(s.into())?) + TcpStream::from_std(s.into()) } #[cfg(target_os = "windows")] { @@ -36,14 +36,14 @@ pub fn apply_tcp_options(s: TcpStream) -> std::io::Result { .with_time(Duration::from_secs(10)) .with_interval(Duration::from_secs(1)), )?; - Ok(TcpStream::from_std(s.into())?) + TcpStream::from_std(s.into()) } } fn must_bind_socket_on_interface(socket: &socket2::Socket, iface: &Interface) -> io::Result<()> { match iface { // TODO: should this be ever used vs. calling .bind(2) from the caller side? - Interface::IpAddr(ip) => socket.bind(&SocketAddr::new(ip.clone(), 0).into()), + Interface::IpAddr(ip) => socket.bind(&SocketAddr::new(*ip, 0).into()), Interface::Name(name) => { #[cfg(target_vendor = "apple")] { @@ -127,7 +127,7 @@ pub async fn new_udp_socket( }; if let Some(src) = src { - socket.bind(&src.clone().into())?; + socket.bind(&(*src).into())?; } if let Some(iface) = iface { diff --git a/clash_lib/src/proxy/vmess/mod.rs b/clash_lib/src/proxy/vmess/mod.rs index 2ba51774e..da911bb1f 100644 --- a/clash_lib/src/proxy/vmess/mod.rs +++ b/clash_lib/src/proxy/vmess/mod.rs @@ -52,6 +52,7 @@ pub struct Handler { } impl Handler { + #[allow(clippy::new_ret_no_self)] pub fn new(opts: HandlerOptions) -> AnyOutboundHandler { Arc::new(Self { opts }) } diff --git a/clash_lib/src/proxy/vmess/vmess_impl/cipher.rs b/clash_lib/src/proxy/vmess/vmess_impl/cipher.rs index 0f2776da0..8bb2e8c75 100644 --- a/clash_lib/src/proxy/vmess/vmess_impl/cipher.rs +++ b/clash_lib/src/proxy/vmess/vmess_impl/cipher.rs @@ -4,6 +4,7 @@ use chacha20poly1305::ChaCha20Poly1305; use crate::common::crypto::AeadCipherHelper; +#[allow(clippy::large_enum_variant)] pub enum VmessSecurity { Aes128Gcm(Aes128Gcm), ChaCha20Poly1305(ChaCha20Poly1305), @@ -50,20 +51,20 @@ impl AeadCipher { let nonce = &nonce[..security.nonce_len()]; match security { VmessSecurity::Aes128Gcm(cipher) => { - let dec = cipher.decrypt_in_place_with_slice(nonce.into(), &[], &mut buf[..]); - if dec.is_err() { + let dec = cipher.decrypt_in_place_with_slice(nonce, &[], &mut buf[..]); + if let Err(err) = dec { return Err(std::io::Error::new( std::io::ErrorKind::InvalidData, - dec.unwrap_err().to_string(), + err.to_string(), )); } } VmessSecurity::ChaCha20Poly1305(cipher) => { - let dec = cipher.decrypt_in_place_with_slice(nonce.into(), &[], &mut buf[..]); - if dec.is_err() { + let dec = cipher.decrypt_in_place_with_slice(nonce, &[], &mut buf[..]); + if let Err(err) = dec { return Err(std::io::Error::new( std::io::ErrorKind::InvalidData, - dec.unwrap_err().to_string(), + err.to_string(), )); } } @@ -85,10 +86,10 @@ impl AeadCipher { let nonce = &nonce[..security.nonce_len()]; match security { VmessSecurity::Aes128Gcm(cipher) => { - cipher.encrypt_in_place_with_slice(nonce.into(), &[], &mut buf[..]); + cipher.encrypt_in_place_with_slice(nonce, &[], &mut buf[..]); } VmessSecurity::ChaCha20Poly1305(cipher) => { - cipher.encrypt_in_place_with_slice(nonce.into(), &[], &mut buf[..]); + cipher.encrypt_in_place_with_slice(nonce, &[], &mut buf[..]); } } diff --git a/clash_lib/src/proxy/vmess/vmess_impl/header.rs b/clash_lib/src/proxy/vmess/vmess_impl/header.rs index 8ff2d7c0d..97d944b83 100644 --- a/clash_lib/src/proxy/vmess/vmess_impl/header.rs +++ b/clash_lib/src/proxy/vmess/vmess_impl/header.rs @@ -120,7 +120,7 @@ mod tests { let cmd_key = "1234567890123456".as_bytes(); let mut aes_key = boring_sys::AES_KEY::default(); - let pk = kdf::vmess_kdf_1_one_shot(&cmd_key[..], KDF_SALT_CONST_AUTH_ID_ENCRYPTION_KEY); + let pk = kdf::vmess_kdf_1_one_shot(cmd_key, KDF_SALT_CONST_AUTH_ID_ENCRYPTION_KEY); unsafe { boring_sys::AES_set_encrypt_key(pk.as_ptr() as _, 128, &mut aes_key); boring_sys::AES_encrypt(buf.as_mut_ptr() as _, buf.as_mut_ptr() as _, &aes_key); @@ -140,13 +140,13 @@ mod tests { let data = vec![0u8; 16]; let payload_header_length_aead_key = &kdf::vmess_kdf_3_one_shot( - &key[..], + key, KDF_SALT_CONST_VMESS_HEADER_PAYLOAD_LENGTH_AEAD_KEY, &auth_id[..], &connection_nonce[..], )[..16]; let payload_header_length_aead_nonce = &kdf::vmess_kdf_3_one_shot( - &key[..], + key, KDF_SALT_CONST_VMESS_HEADER_PAYLOAD_LENGTH_AEAD_IV, &auth_id[..], &connection_nonce[..], @@ -161,13 +161,13 @@ mod tests { .unwrap(); let payload_header_aead_key = &kdf::vmess_kdf_3_one_shot( - &key[..], + key, KDF_SALT_CONST_VMESS_HEADER_PAYLOAD_AEAD_KEY, &auth_id[..], &connection_nonce[..], )[..16]; let payload_header_aead_nonce = &kdf::vmess_kdf_3_one_shot( - &key[..], + key, KDF_SALT_CONST_VMESS_HEADER_PAYLOAD_AEAD_IV, &auth_id[..], &connection_nonce[..], diff --git a/clash_lib/src/proxy/vmess/vmess_impl/stream.rs b/clash_lib/src/proxy/vmess/vmess_impl/stream.rs index 3a1bd785e..45c0bb3dd 100644 --- a/clash_lib/src/proxy/vmess/vmess_impl/stream.rs +++ b/clash_lib/src/proxy/vmess/vmess_impl/stream.rs @@ -159,9 +159,9 @@ where ) }; - let (aead_read_cipher, aead_write_cipher) = match security { - &SECURITY_NONE => (None, None), - &SECURITY_AES_128_GCM => { + let (aead_read_cipher, aead_write_cipher) = match *security { + SECURITY_NONE => (None, None), + SECURITY_AES_128_GCM => { let write_cipher = VmessSecurity::Aes128Gcm(Aes128Gcm::new_with_slice(&req_body_key)); let write_cipher = AeadCipher::new(&req_body_iv, write_cipher); @@ -170,7 +170,7 @@ where let read_cipher = AeadCipher::new(&resp_body_iv, reader_cipher); (Some(read_cipher), Some(write_cipher)) } - &SECURITY_CHACHA20_POLY1305 => { + SECURITY_CHACHA20_POLY1305 => { let mut key = [0u8; 32]; let tmp = utils::md5(&req_body_key); key.copy_from_slice(&tmp); @@ -419,8 +419,8 @@ where )[..12]; let buf = crypto::aes_gcm_open( - &aead_response_header_payload_encryption_key, - &aead_response_header_payload_encryption_iv, + aead_response_header_payload_encryption_key, + aead_response_header_payload_encryption_iv, this.read_buf.split().as_ref(), None, ) diff --git a/clash_lib/src/proxy/vmess/vmess_impl/user.rs b/clash_lib/src/proxy/vmess/vmess_impl/user.rs index e19fa064d..b9fa267a0 100644 --- a/clash_lib/src/proxy/vmess/vmess_impl/user.rs +++ b/clash_lib/src/proxy/vmess/vmess_impl/user.rs @@ -16,7 +16,7 @@ pub fn new_alter_id_list(primary: &ID, alter_id_count: u16) -> Vec { let new_id = next_id(&prev_id); alter_id_list.push(ID { uuid: new_id, - cmd_key: primary.cmd_key.clone(), + cmd_key: primary.cmd_key, }); prev_id = new_id; } diff --git a/clash_lib/src/proxy/wg/device.rs b/clash_lib/src/proxy/wg/device.rs index 23bc0bed5..34e6e3d9b 100644 --- a/clash_lib/src/proxy/wg/device.rs +++ b/clash_lib/src/proxy/wg/device.rs @@ -34,6 +34,7 @@ use super::{ }, }; +#[allow(clippy::large_enum_variant)] enum Socket { Tcp( tcp::Socket<'static>, @@ -130,7 +131,7 @@ impl DeviceManager { pub async fn look_up_dns(&self, host: &str, server: SocketAddr) -> Option { debug!("looking up {} on {}", host, server); - let mut socket = Self::new_udp_socket(&self).await; + let mut socket = Self::new_udp_socket(self).await; let mut msg = hickory_proto::op::Message::new(); msg.add_query({ @@ -146,11 +147,7 @@ impl DeviceManager { msg.set_recursion_desired(true); - let pkt = UdpPacket::new( - msg.to_vec().unwrap().into(), - SocksAddr::any_ipv4(), - server.into(), - ); + let pkt = UdpPacket::new(msg.to_vec().unwrap(), SocksAddr::any_ipv4(), server.into()); socket.feed(pkt).await.ok()?; socket.flush().await.ok()?; @@ -645,8 +642,7 @@ impl smoltcp::phy::TxToken for TxToken { where F: FnOnce(&mut [u8]) -> R, { - let mut buffer = Vec::new(); - buffer.resize(len, 0); + let mut buffer = vec![0u8; len]; let result = f(&mut buffer); match self.sender.try_send(buffer.into()) { Ok(_) => {} diff --git a/clash_lib/src/proxy/wg/mod.rs b/clash_lib/src/proxy/wg/mod.rs index 5349963a2..774fd3f0e 100644 --- a/clash_lib/src/proxy/wg/mod.rs +++ b/clash_lib/src/proxy/wg/mod.rs @@ -68,6 +68,7 @@ pub struct Handler { } impl Handler { + #[allow(clippy::new_ret_no_self)] pub fn new(opts: HandlerOpts) -> AnyOutboundHandler { Arc::new(Self { opts, @@ -216,7 +217,7 @@ impl OutboundHandler for Handler { let ip = if self.opts.remote_dns_resolve && sess.destination.is_domain() - && self.opts.dns.as_ref().is_some_and(|x| x.len() > 0) + && self.opts.dns.as_ref().is_some_and(|x| !x.is_empty()) { debug!( "use remote dns to resolve domain: {}", diff --git a/clash_lib/src/proxy/wg/wireguard.rs b/clash_lib/src/proxy/wg/wireguard.rs index 1816169aa..d0f7c1a37 100644 --- a/clash_lib/src/proxy/wg/wireguard.rs +++ b/clash_lib/src/proxy/wg/wireguard.rs @@ -67,8 +67,8 @@ impl WireguardTunnel { ) -> Result { let source_peer_ip = config.source_peer_ip; let peer = Tunn::new( - config.private_key.into(), - config.endpoint_public_key.into(), + config.private_key, + config.endpoint_public_key, config.preshared_key.map(|x| x.to_bytes()), config.keepalive_seconds, 0, @@ -108,7 +108,7 @@ impl WireguardTunnel { error!("failed to encapsulate packet: {e:?}"); } boringtun::noise::TunnResult::WriteToNetwork(packet) => { - self.udp.send_to(&packet, self.endpoint).await?; + self.udp.send_to(packet, self.endpoint).await?; } _ => { error!("unexpected result from encapsulate"); @@ -197,7 +197,7 @@ impl WireguardTunnel { TunnResult::WriteToNetwork(packet) => { match self .udp - .send_to(&packet, self.endpoint) + .send_to(packet, self.endpoint) .instrument(trace_span!( "wg_send", endpoint = %self.endpoint, @@ -213,21 +213,16 @@ impl WireguardTunnel { } let mut send_buf = vec![0u8; 65535]; - loop { - match peer.decapsulate(None, &[], &mut send_buf) { - TunnResult::WriteToNetwork(packet) => { - match self.udp.send_to(packet, self.endpoint).await { - Ok(_) => {} - Err(e) => { - error!("Failed to send decapsulation-instructed packet to WireGuard endpoint: {:?}", e); - break; - } - }; - } - _ => { + while let TunnResult::WriteToNetwork(packet) = + peer.decapsulate(None, &[], &mut send_buf) + { + match self.udp.send_to(packet, self.endpoint).await { + Ok(_) => {} + Err(e) => { + error!("Failed to send decapsulation-instructed packet to WireGuard endpoint: {:?}", e); break; } - } + }; } } @@ -307,7 +302,7 @@ impl WireguardTunnel { error!("wireguard error: {e:?}"); } TunnResult::WriteToNetwork(packet) => { - match self.udp.send_to(&packet, self.endpoint).await { + match self.udp.send_to(packet, self.endpoint).await { Ok(_) => {} Err(e) => { error!("failed to send packet: {}", e); diff --git a/clash_lib/src/session.rs b/clash_lib/src/session.rs index 472e7f8eb..604573a8f 100644 --- a/clash_lib/src/session.rs +++ b/clash_lib/src/session.rs @@ -398,7 +398,7 @@ impl Session { ); rv.insert("host".to_string(), Box::new(self.destination.host()) as _); - return rv; + rv } } @@ -422,7 +422,7 @@ impl Display for Session { "[{}] {} -> {}", self.network, self.source, - self.destination.to_string(), + self.destination, ) } }