use std::{sync::Arc, time::Duration}; use tokio::task::JoinSet; use crate::{ peers::peer_manager::PeerManager, proto::{ api::instance::Route, common::Void, magic_dns::{ HandshakeRequest, MagicDnsServerRpc, MagicDnsServerRpcClientFactory, UpdateDnsRecordRequest, }, rpc_impl::standalone::StandAloneClient, rpc_types::controller::BaseController, }, tunnel::tcp::TcpTunnelConnector, }; use super::MAGIC_DNS_INSTANCE_ADDR; pub struct MagicDnsClientInstance { rpc_client: StandAloneClient, rpc_stub: Option + Send>>, peer_mgr: Arc, tasks: JoinSet<()>, } impl MagicDnsClientInstance { pub async fn new(peer_mgr: Arc) -> Result { let tcp_connector = TcpTunnelConnector::new(MAGIC_DNS_INSTANCE_ADDR.parse().unwrap()); let mut rpc_client = StandAloneClient::new(tcp_connector); let rpc_stub = rpc_client .scoped_client::>("".to_string()) .await?; Ok(MagicDnsClientInstance { rpc_client, rpc_stub: Some(rpc_stub), peer_mgr, tasks: JoinSet::new(), }) } async fn update_dns_task( peer_mgr: Arc, rpc_stub: Box + Send>, ) -> Result<(), anyhow::Error> { let mut prev_last_update = None; rpc_stub .handshake(BaseController::default(), HandshakeRequest::default()) .await?; loop { rpc_stub .heartbeat(BaseController::default(), Void::default()) .await?; let last_update = peer_mgr.get_route_peer_info_last_update_time().await; if Some(last_update) == prev_last_update { tokio::time::sleep(Duration::from_millis(500)).await; continue; } let mut routes = peer_mgr.list_routes().await; // add self as a route let ctx = peer_mgr.get_global_ctx(); routes.push(Route { hostname: ctx.get_hostname(), ipv4_addr: ctx.get_ipv4().map(Into::into), ..Default::default() }); // Use configured tld_dns_zone (always set by default) let flags = ctx.config.get_flags(); let req = UpdateDnsRecordRequest { routes, zone: flags.tld_dns_zone.clone(), }; tracing::debug!( "MagicDnsClientInstance::update_dns_task: update dns records: {:?}", req ); rpc_stub .update_dns_record(BaseController::default(), req) .await?; let last_update_after_rpc = peer_mgr.get_route_peer_info_last_update_time().await; if last_update_after_rpc == last_update { prev_last_update = Some(last_update); } } } pub async fn run_and_wait(&mut self) { let rpc_stub = self.rpc_stub.take().unwrap(); let peer_mgr = self.peer_mgr.clone(); self.tasks.spawn(async move { let ret = Self::update_dns_task(peer_mgr, rpc_stub).await; if let Err(e) = ret { tracing::error!("MagicDnsServerInstanceData::run_and_wait: {:?}", e); } }); tokio::select! { _ = self.tasks.join_next() => { tracing::warn!("MagicDnsServerInstanceData::run_and_wait: dns record update task exited"); } _ = self.rpc_client.wait() => { tracing::warn!("MagicDnsServerInstanceData::run_and_wait: rpc client exited"); } } } }