mirror of
https://mirror.suhoan.cn/https://github.com/EasyTier/EasyTier.git
synced 2025-12-14 21:57:24 +08:00
Feat/web (PatchSet 1) (#436)
* move rpc-build out of easytier dir and make it a independant project * easytier core use launcher * fix flags not print on launch * allow launcher not fetch node info * abstract out peer rpc impl * fix arm gui ci. see https://github.com/actions/runner-images/pull/10807 * add easytier-web crate * fix manual_connector test case
This commit is contained in:
@@ -7,7 +7,7 @@ use crate::{
|
||||
common::{
|
||||
config::{ConfigLoader, TomlConfigLoader},
|
||||
constants::EASYTIER_VERSION,
|
||||
global_ctx::GlobalCtxEvent,
|
||||
global_ctx::{EventBusSubscriber, GlobalCtxEvent},
|
||||
stun::StunInfoCollectorTrait,
|
||||
},
|
||||
instance::instance::Instance,
|
||||
@@ -21,7 +21,7 @@ use crate::{
|
||||
};
|
||||
use chrono::{DateTime, Local};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::task::JoinSet;
|
||||
use tokio::{sync::broadcast, task::JoinSet};
|
||||
|
||||
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct MyNodeInfo {
|
||||
@@ -34,14 +34,31 @@ pub struct MyNodeInfo {
|
||||
pub vpn_portal_cfg: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
struct EasyTierData {
|
||||
events: Arc<RwLock<VecDeque<(DateTime<Local>, GlobalCtxEvent)>>>,
|
||||
node_info: Arc<RwLock<MyNodeInfo>>,
|
||||
routes: Arc<RwLock<Vec<Route>>>,
|
||||
peers: Arc<RwLock<Vec<PeerInfo>>>,
|
||||
events: RwLock<VecDeque<(DateTime<Local>, GlobalCtxEvent)>>,
|
||||
node_info: RwLock<MyNodeInfo>,
|
||||
routes: RwLock<Vec<Route>>,
|
||||
peers: RwLock<Vec<PeerInfo>>,
|
||||
tun_fd: Arc<RwLock<Option<i32>>>,
|
||||
tun_dev_name: Arc<RwLock<String>>,
|
||||
tun_dev_name: RwLock<String>,
|
||||
event_subscriber: RwLock<broadcast::Sender<GlobalCtxEvent>>,
|
||||
instance_stop_notifier: Arc<tokio::sync::Notify>,
|
||||
}
|
||||
|
||||
impl Default for EasyTierData {
|
||||
fn default() -> Self {
|
||||
let (tx, _) = broadcast::channel(100);
|
||||
Self {
|
||||
event_subscriber: RwLock::new(tx),
|
||||
events: RwLock::new(VecDeque::new()),
|
||||
node_info: RwLock::new(MyNodeInfo::default()),
|
||||
routes: RwLock::new(Vec::new()),
|
||||
peers: RwLock::new(Vec::new()),
|
||||
tun_fd: Arc::new(RwLock::new(None)),
|
||||
tun_dev_name: RwLock::new(String::new()),
|
||||
instance_stop_notifier: Arc::new(tokio::sync::Notify::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EasyTierLauncher {
|
||||
@@ -49,27 +66,30 @@ pub struct EasyTierLauncher {
|
||||
stop_flag: Arc<AtomicBool>,
|
||||
thread_handle: Option<std::thread::JoinHandle<()>>,
|
||||
running_cfg: String,
|
||||
fetch_node_info: bool,
|
||||
|
||||
error_msg: Arc<RwLock<Option<String>>>,
|
||||
data: EasyTierData,
|
||||
data: Arc<EasyTierData>,
|
||||
}
|
||||
|
||||
impl EasyTierLauncher {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(fetch_node_info: bool) -> Self {
|
||||
let instance_alive = Arc::new(AtomicBool::new(false));
|
||||
Self {
|
||||
instance_alive,
|
||||
thread_handle: None,
|
||||
error_msg: Arc::new(RwLock::new(None)),
|
||||
running_cfg: String::new(),
|
||||
fetch_node_info,
|
||||
|
||||
stop_flag: Arc::new(AtomicBool::new(false)),
|
||||
data: EasyTierData::default(),
|
||||
data: Arc::new(EasyTierData::default()),
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_easytier_event(event: GlobalCtxEvent, data: EasyTierData) {
|
||||
async fn handle_easytier_event(event: GlobalCtxEvent, data: &EasyTierData) {
|
||||
let mut events = data.events.write().unwrap();
|
||||
let _ = data.event_subscriber.read().unwrap().send(event.clone());
|
||||
events.push_back((chrono::Local::now(), event));
|
||||
if events.len() > 100 {
|
||||
events.pop_front();
|
||||
@@ -113,7 +133,8 @@ impl EasyTierLauncher {
|
||||
async fn easytier_routine(
|
||||
cfg: TomlConfigLoader,
|
||||
stop_signal: Arc<tokio::sync::Notify>,
|
||||
data: EasyTierData,
|
||||
data: Arc<EasyTierData>,
|
||||
fetch_node_info: bool,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
let mut instance = Instance::new(cfg);
|
||||
let peer_mgr = instance.get_peer_manager();
|
||||
@@ -126,50 +147,53 @@ impl EasyTierLauncher {
|
||||
tasks.spawn(async move {
|
||||
let mut receiver = global_ctx.subscribe();
|
||||
while let Ok(event) = receiver.recv().await {
|
||||
Self::handle_easytier_event(event, data_c.clone()).await;
|
||||
Self::handle_easytier_event(event, &data_c).await;
|
||||
}
|
||||
});
|
||||
|
||||
// update my node info
|
||||
let data_c = data.clone();
|
||||
let global_ctx_c = instance.get_global_ctx();
|
||||
let peer_mgr_c = peer_mgr.clone();
|
||||
let vpn_portal = instance.get_vpn_portal_inst();
|
||||
tasks.spawn(async move {
|
||||
loop {
|
||||
// Update TUN Device Name
|
||||
*data_c.tun_dev_name.write().unwrap() = global_ctx_c.get_flags().dev_name.clone();
|
||||
if fetch_node_info {
|
||||
let data_c = data.clone();
|
||||
let global_ctx_c = instance.get_global_ctx();
|
||||
let peer_mgr_c = peer_mgr.clone();
|
||||
let vpn_portal = instance.get_vpn_portal_inst();
|
||||
tasks.spawn(async move {
|
||||
loop {
|
||||
// Update TUN Device Name
|
||||
*data_c.tun_dev_name.write().unwrap() =
|
||||
global_ctx_c.get_flags().dev_name.clone();
|
||||
|
||||
let node_info = MyNodeInfo {
|
||||
virtual_ipv4: global_ctx_c
|
||||
.get_ipv4()
|
||||
.map(|x| x.to_string())
|
||||
.unwrap_or_default(),
|
||||
hostname: global_ctx_c.get_hostname(),
|
||||
version: EASYTIER_VERSION.to_string(),
|
||||
ips: global_ctx_c.get_ip_collector().collect_ip_addrs().await,
|
||||
stun_info: global_ctx_c.get_stun_info_collector().get_stun_info(),
|
||||
listeners: global_ctx_c
|
||||
.get_running_listeners()
|
||||
.iter()
|
||||
.map(|x| x.to_string())
|
||||
.collect(),
|
||||
vpn_portal_cfg: Some(
|
||||
vpn_portal
|
||||
.lock()
|
||||
.await
|
||||
.dump_client_config(peer_mgr_c.clone())
|
||||
.await,
|
||||
),
|
||||
};
|
||||
*data_c.node_info.write().unwrap() = node_info.clone();
|
||||
*data_c.routes.write().unwrap() = peer_mgr_c.list_routes().await;
|
||||
*data_c.peers.write().unwrap() = PeerManagerRpcService::new(peer_mgr_c.clone())
|
||||
.list_peers()
|
||||
.await;
|
||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||
}
|
||||
});
|
||||
let node_info = MyNodeInfo {
|
||||
virtual_ipv4: global_ctx_c
|
||||
.get_ipv4()
|
||||
.map(|x| x.to_string())
|
||||
.unwrap_or_default(),
|
||||
hostname: global_ctx_c.get_hostname(),
|
||||
version: EASYTIER_VERSION.to_string(),
|
||||
ips: global_ctx_c.get_ip_collector().collect_ip_addrs().await,
|
||||
stun_info: global_ctx_c.get_stun_info_collector().get_stun_info(),
|
||||
listeners: global_ctx_c
|
||||
.get_running_listeners()
|
||||
.iter()
|
||||
.map(|x| x.to_string())
|
||||
.collect(),
|
||||
vpn_portal_cfg: Some(
|
||||
vpn_portal
|
||||
.lock()
|
||||
.await
|
||||
.dump_client_config(peer_mgr_c.clone())
|
||||
.await,
|
||||
),
|
||||
};
|
||||
*data_c.node_info.write().unwrap() = node_info.clone();
|
||||
*data_c.routes.write().unwrap() = peer_mgr_c.list_routes().await;
|
||||
*data_c.peers.write().unwrap() = PeerManagerRpcService::new(peer_mgr_c.clone())
|
||||
.list_peers()
|
||||
.await;
|
||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
Self::run_routine_for_android(&instance, &data, &mut tasks).await;
|
||||
@@ -188,13 +212,15 @@ impl EasyTierLauncher {
|
||||
F: FnOnce() -> Result<TomlConfigLoader, anyhow::Error> + Send + Sync,
|
||||
{
|
||||
let error_msg = self.error_msg.clone();
|
||||
let cfg = cfg_generator();
|
||||
if let Err(e) = cfg {
|
||||
error_msg.write().unwrap().replace(e.to_string());
|
||||
return;
|
||||
}
|
||||
let cfg = match cfg_generator() {
|
||||
Err(e) => {
|
||||
error_msg.write().unwrap().replace(e.to_string());
|
||||
return;
|
||||
}
|
||||
Ok(cfg) => cfg,
|
||||
};
|
||||
|
||||
self.running_cfg = cfg.as_ref().unwrap().dump();
|
||||
self.running_cfg = cfg.dump();
|
||||
|
||||
let stop_flag = self.stop_flag.clone();
|
||||
|
||||
@@ -202,12 +228,21 @@ impl EasyTierLauncher {
|
||||
instance_alive.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
|
||||
let data = self.data.clone();
|
||||
let fetch_node_info = self.fetch_node_info;
|
||||
|
||||
self.thread_handle = Some(std::thread::spawn(move || {
|
||||
let rt = tokio::runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap();
|
||||
let rt = if cfg.get_flags().multi_thread {
|
||||
tokio::runtime::Builder::new_multi_thread()
|
||||
.worker_threads(2)
|
||||
.enable_all()
|
||||
.build()
|
||||
} else {
|
||||
tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
}
|
||||
.unwrap();
|
||||
|
||||
let stop_notifier = Arc::new(tokio::sync::Notify::new());
|
||||
|
||||
let stop_notifier_clone = stop_notifier.clone();
|
||||
@@ -218,15 +253,18 @@ impl EasyTierLauncher {
|
||||
stop_notifier_clone.notify_one();
|
||||
});
|
||||
|
||||
let notifier = data.instance_stop_notifier.clone();
|
||||
let ret = rt.block_on(Self::easytier_routine(
|
||||
cfg.unwrap(),
|
||||
cfg,
|
||||
stop_notifier.clone(),
|
||||
data,
|
||||
fetch_node_info,
|
||||
));
|
||||
if let Err(e) = ret {
|
||||
error_msg.write().unwrap().replace(e.to_string());
|
||||
}
|
||||
instance_alive.store(false, std::sync::atomic::Ordering::Relaxed);
|
||||
notifier.notify_one();
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -289,6 +327,8 @@ pub struct NetworkInstanceRunningInfo {
|
||||
pub struct NetworkInstance {
|
||||
config: TomlConfigLoader,
|
||||
launcher: Option<EasyTierLauncher>,
|
||||
|
||||
fetch_node_info: bool,
|
||||
}
|
||||
|
||||
impl NetworkInstance {
|
||||
@@ -296,9 +336,15 @@ impl NetworkInstance {
|
||||
Self {
|
||||
config,
|
||||
launcher: None,
|
||||
fetch_node_info: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_fetch_node_info(mut self, fetch_node_info: bool) -> Self {
|
||||
self.fetch_node_info = fetch_node_info;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_easytier_running(&self) -> bool {
|
||||
self.launcher.is_some() && self.launcher.as_ref().unwrap().running()
|
||||
}
|
||||
@@ -333,15 +379,37 @@ impl NetworkInstance {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(&mut self) -> Result<(), anyhow::Error> {
|
||||
pub fn start(&mut self) -> Result<EventBusSubscriber, anyhow::Error> {
|
||||
if self.is_easytier_running() {
|
||||
return Ok(());
|
||||
return Ok(self.subscribe_event().unwrap());
|
||||
}
|
||||
|
||||
let mut launcher = EasyTierLauncher::new();
|
||||
launcher.start(|| Ok(self.config.clone()));
|
||||
|
||||
let launcher = EasyTierLauncher::new(self.fetch_node_info);
|
||||
self.launcher = Some(launcher);
|
||||
Ok(())
|
||||
let ev = self.subscribe_event().unwrap();
|
||||
|
||||
self.launcher
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.start(|| Ok(self.config.clone()));
|
||||
|
||||
Ok(ev)
|
||||
}
|
||||
|
||||
fn subscribe_event(&self) -> Option<broadcast::Receiver<GlobalCtxEvent>> {
|
||||
if let Some(launcher) = self.launcher.as_ref() {
|
||||
Some(launcher.data.event_subscriber.read().unwrap().subscribe())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn wait(&self) -> Option<String> {
|
||||
if let Some(launcher) = self.launcher.as_ref() {
|
||||
launcher.data.instance_stop_notifier.notified().await;
|
||||
launcher.error_msg.read().unwrap().clone()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user