mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-06 17:59:11 +00:00
fix(web-client): keep retrying unreachable config server (#2140)
Defer config-server connector creation into the web client retry loop so service startup does not fail when network or DNS is unavailable.
This commit is contained in:
@@ -2,13 +2,17 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
common::{
|
common::{
|
||||||
config::TomlConfigLoader, global_ctx::GlobalCtx, log, os_info::collect_device_os_info,
|
config::TomlConfigLoader,
|
||||||
set_default_machine_id, stun::MockStunInfoCollector,
|
global_ctx::{ArcGlobalCtx, GlobalCtx},
|
||||||
|
log,
|
||||||
|
os_info::collect_device_os_info,
|
||||||
|
set_default_machine_id,
|
||||||
|
stun::MockStunInfoCollector,
|
||||||
},
|
},
|
||||||
connector::create_connector_by_url,
|
connector::create_connector_by_url,
|
||||||
instance_manager::{DaemonGuard, NetworkInstanceManager},
|
instance_manager::{DaemonGuard, NetworkInstanceManager},
|
||||||
proto::common::NatType,
|
proto::common::NatType,
|
||||||
tunnel::{IpVersion, TunnelConnector},
|
tunnel::{IpVersion, Tunnel, TunnelConnector, TunnelError, TunnelScheme},
|
||||||
};
|
};
|
||||||
use anyhow::{Context as _, Result};
|
use anyhow::{Context as _, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
@@ -49,6 +53,30 @@ pub struct WebClient {
|
|||||||
connected: Arc<AtomicBool>,
|
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 {
|
impl WebClient {
|
||||||
pub fn new<T: TunnelConnector + 'static, S: ToString, H: ToString>(
|
pub fn new<T: TunnelConnector + 'static, S: ToString, H: ToString>(
|
||||||
connector: T,
|
connector: T,
|
||||||
@@ -218,6 +246,13 @@ pub async fn run_web_client(
|
|||||||
.with_context(|| "failed to parse config server URL")?,
|
.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();
|
let mut c_url = config_server_url.clone();
|
||||||
if !matches!(c_url.scheme(), "ws" | "wss") {
|
if !matches!(c_url.scheme(), "ws" | "wss") {
|
||||||
c_url.set_path("");
|
c_url.set_path("");
|
||||||
@@ -243,16 +278,20 @@ pub async fn run_web_client(
|
|||||||
let mut flags = global_ctx.get_flags();
|
let mut flags = global_ctx.get_flags();
|
||||||
flags.bind_device = false;
|
flags.bind_device = false;
|
||||||
global_ctx.set_flags(flags);
|
global_ctx.set_flags(flags);
|
||||||
|
|
||||||
let hostname = match hostname {
|
let hostname = match hostname {
|
||||||
None => gethostname::gethostname().to_string_lossy().to_string(),
|
None => gethostname::gethostname().to_string_lossy().to_string(),
|
||||||
Some(hostname) => hostname,
|
Some(hostname) => hostname,
|
||||||
};
|
};
|
||||||
Ok(WebClient::new(
|
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(),
|
token.to_string(),
|
||||||
hostname,
|
hostname,
|
||||||
secure_mode,
|
secure_mode,
|
||||||
manager.clone(),
|
manager,
|
||||||
hooks,
|
hooks,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -292,4 +331,23 @@ mod tests {
|
|||||||
assert!(sleep_finish.load(std::sync::atomic::Ordering::Relaxed));
|
assert!(sleep_finish.load(std::sync::atomic::Ordering::Relaxed));
|
||||||
println!("Manager stopped.");
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user