Merge branch 'main' into feat/dns-policy

# Conflicts:
#	easytier/build.rs
#	easytier/src/common/dns.rs
#	easytier/src/web_client/mod.rs
This commit is contained in:
Luna Yao
2026-05-04 01:44:54 +02:00
45 changed files with 2064 additions and 216 deletions
+62 -5
View File
@@ -2,13 +2,17 @@ use std::sync::Arc;
use crate::{
common::{
config::TomlConfigLoader, global_ctx::GlobalCtx, log, os_info::collect_device_os_info,
set_default_machine_id, stun::MockStunInfoCollector,
config::TomlConfigLoader,
global_ctx::{ArcGlobalCtx, GlobalCtx},
log,
os_info::collect_device_os_info,
set_default_machine_id,
stun::MockStunInfoCollector,
},
connector::create_connector_by_url,
instance_manager::{DaemonGuard, NetworkInstanceManager},
proto::common::NatType,
tunnel::{IpVersion, TunnelConnector},
tunnel::{IpVersion, Tunnel, TunnelConnector, TunnelError, TunnelScheme},
utils,
};
use anyhow::{Context as _, Result};
@@ -50,6 +54,30 @@ pub struct WebClient {
connected: Arc<AtomicBool>,
}
struct ConfigServerConnector {
url: Url,
global_ctx: ArcGlobalCtx,
}
#[async_trait]
impl TunnelConnector for ConfigServerConnector {
async fn connect(&mut self) -> std::result::Result<Box<dyn Tunnel>, TunnelError> {
let mut connector =
create_connector_by_url(self.url.as_str(), &self.global_ctx, IpVersion::Both)
.await
.map_err(|err| match err {
crate::common::error::Error::TunnelError(err) => err,
err => TunnelError::Anyhow(err.into()),
})?;
connector.connect().await
}
fn remote_url(&self) -> Url {
self.url.clone()
}
}
impl WebClient {
pub fn new<T: TunnelConnector + 'static, S: ToString, H: ToString>(
connector: T,
@@ -219,6 +247,13 @@ pub async fn run_web_client(
.with_context(|| "failed to parse config server URL")?,
};
TunnelScheme::try_from(&config_server_url).map_err(|_| {
anyhow::anyhow!(
"unsupported config server scheme: {}",
config_server_url.scheme()
)
})?;
let mut c_url = config_server_url.clone();
if !matches!(c_url.scheme(), "ws" | "wss") {
c_url.set_path("");
@@ -246,11 +281,14 @@ pub async fn run_web_client(
global_ctx.set_flags(flags);
let hostname = hostname.unwrap_or_else(utils::hostname);
Ok(WebClient::new(
create_connector_by_url(c_url.as_str(), &global_ctx, IpVersion::Both).await?,
ConfigServerConnector {
url: c_url,
global_ctx,
},
token.to_string(),
hostname,
secure_mode,
manager.clone(),
manager,
hooks,
))
}
@@ -290,4 +328,23 @@ mod tests {
assert!(sleep_finish.load(std::sync::atomic::Ordering::Relaxed));
println!("Manager stopped.");
}
#[tokio::test]
async fn test_run_web_client_with_unreachable_config_server() {
let manager = Arc::new(NetworkInstanceManager::new());
let client = super::run_web_client(
"udp://config-server.invalid:22020/test",
None,
None,
false,
manager,
None,
)
.await
.unwrap();
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
assert!(!client.is_connected());
drop(client);
}
}