refactor(web): Refactor web logic to extract reusable remote client management module (#1465)

This commit is contained in:
Mg Pig
2025-10-13 23:59:46 +08:00
committed by GitHub
parent 999a486928
commit 87b7b7ed7c
24 changed files with 1382 additions and 995 deletions

View File

@@ -11,6 +11,7 @@ mod vpn_portal;
pub mod instance_manage;
pub mod logger;
pub mod remote_client;
pub type ApiRpcServer = self::api::ApiRpcServer;

View File

@@ -0,0 +1,273 @@
use async_trait::async_trait;
use uuid::Uuid;
use crate::proto::{api::manage::*, rpc_types::controller::BaseController};
#[async_trait]
pub trait RemoteClientManager<T, C, E>
where
T: Copy + Send + 'static,
C: PersistentConfig + Send + 'static,
E: Send + 'static,
{
fn get_rpc_client(
&self,
identify: T,
) -> Option<Box<dyn WebClientService<Controller = BaseController> + Send>>;
fn get_storage(&self) -> &impl Storage<T, C, E>;
async fn handle_validate_config(
&self,
identify: T,
config: NetworkConfig,
) -> Result<ValidateConfigResponse, RemoteClientError<E>> {
let client = self
.get_rpc_client(identify)
.ok_or(RemoteClientError::ClientNotFound)?;
client
.validate_config(
BaseController::default(),
ValidateConfigRequest {
config: Some(config),
},
)
.await
.map_err(RemoteClientError::RpcError)
}
async fn handle_run_network_instance(
&self,
identify: T,
config: NetworkConfig,
) -> Result<(), RemoteClientError<E>> {
let client = self
.get_rpc_client(identify)
.ok_or(RemoteClientError::ClientNotFound)?;
let network_config_json = serde_json::to_string(&config).map_err(|e| {
RemoteClientError::Other(format!("Failed to serialize config: {:?}", e))
})?;
let resp = client
.run_network_instance(
BaseController::default(),
RunNetworkInstanceRequest {
inst_id: None,
config: Some(config),
},
)
.await?;
self.get_storage()
.insert_or_update_user_network_config(
identify,
resp.inst_id.unwrap_or_default().into(),
network_config_json,
)
.await
.map_err(RemoteClientError::PersistentError)?;
Ok(())
}
async fn handle_collect_network_info(
&self,
identify: T,
inst_ids: Option<Vec<uuid::Uuid>>,
) -> Result<CollectNetworkInfoResponse, RemoteClientError<E>> {
let client = self
.get_rpc_client(identify)
.ok_or(RemoteClientError::ClientNotFound)?;
let resp = client
.collect_network_info(
BaseController::default(),
CollectNetworkInfoRequest {
inst_ids: inst_ids
.unwrap_or_default()
.into_iter()
.map(|id| id.into())
.collect(),
},
)
.await?;
Ok(resp)
}
async fn handle_list_network_instance_ids(
&self,
identify: T,
) -> Result<ListNetworkInstanceIdsJsonResp, RemoteClientError<E>> {
let client = self
.get_rpc_client(identify)
.ok_or(RemoteClientError::ClientNotFound)?;
let ret = client
.list_network_instance(BaseController::default(), ListNetworkInstanceRequest {})
.await?;
let running_inst_ids = ret.inst_ids.clone().into_iter().collect();
// collect networks that are disabled
let disabled_inst_ids = self
.get_storage()
.list_network_configs(identify, ListNetworkProps::DisabledOnly)
.await
.map_err(RemoteClientError::PersistentError)?
.iter()
.map(|x| Into::<crate::proto::common::Uuid>::into(x.get_network_inst_id().to_string()))
.collect::<Vec<_>>();
Ok(ListNetworkInstanceIdsJsonResp {
running_inst_ids,
disabled_inst_ids,
})
}
async fn handle_remove_network_instance(
&self,
identify: T,
inst_id: uuid::Uuid,
) -> Result<(), RemoteClientError<E>> {
let client = self
.get_rpc_client(identify)
.ok_or(RemoteClientError::ClientNotFound)?;
self.get_storage()
.delete_network_config(identify, inst_id)
.await
.map_err(RemoteClientError::PersistentError)?;
client
.delete_network_instance(
BaseController::default(),
DeleteNetworkInstanceRequest {
inst_ids: vec![inst_id.into()],
},
)
.await?;
Ok(())
}
async fn handle_update_network_state(
&self,
identify: T,
inst_id: uuid::Uuid,
disabled: bool,
) -> Result<(), RemoteClientError<E>> {
let client = self
.get_rpc_client(identify)
.ok_or(RemoteClientError::ClientNotFound)?;
let cfg = self
.get_storage()
.update_network_config_state(identify, inst_id, disabled)
.await
.map_err(RemoteClientError::PersistentError)?;
if disabled {
client
.delete_network_instance(
BaseController::default(),
DeleteNetworkInstanceRequest {
inst_ids: vec![inst_id.into()],
},
)
.await?;
} else {
client
.run_network_instance(
BaseController::default(),
RunNetworkInstanceRequest {
inst_id: Some(inst_id.into()),
config: Some(serde_json::from_str(cfg.get_network_config()).map_err(
|e| {
RemoteClientError::Other(format!(
"Failed to parse network config: {:?}",
e
))
},
)?),
},
)
.await?;
}
Ok(())
}
async fn handle_get_network_config(
&self,
identify: T,
inst_id: uuid::Uuid,
) -> Result<NetworkConfig, RemoteClientError<E>> {
let inst_id = inst_id.to_string();
let db_row = self
.get_storage()
.get_network_config(identify, &inst_id)
.await
.map_err(RemoteClientError::PersistentError)?
.ok_or(RemoteClientError::NotFound(format!(
"No such network instance: {}",
inst_id
)))?;
Ok(
serde_json::from_str::<NetworkConfig>(db_row.get_network_config()).map_err(|e| {
RemoteClientError::Other(format!("Failed to parse network config: {:?}", e))
})?,
)
}
}
#[derive(Debug, thiserror::Error)]
pub enum RemoteClientError<E> {
ClientNotFound,
NotFound(String),
#[error(transparent)]
RpcError(#[from] crate::proto::rpc_types::error::Error),
PersistentError(E),
Other(String),
}
pub enum ListNetworkProps {
All,
EnabledOnly,
DisabledOnly,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct ListNetworkInstanceIdsJsonResp {
running_inst_ids: Vec<crate::proto::common::Uuid>,
disabled_inst_ids: Vec<crate::proto::common::Uuid>,
}
pub trait PersistentConfig {
fn get_network_inst_id(&self) -> &str;
fn get_network_config(&self) -> &str;
}
#[async_trait]
pub trait Storage<T, C, E>: Send + Sync
where
C: PersistentConfig,
{
async fn insert_or_update_user_network_config(
&self,
identify: T,
network_inst_id: Uuid,
network_config: impl ToString + Send,
) -> Result<(), E>;
async fn delete_network_config(&self, identify: T, network_inst_id: Uuid) -> Result<(), E>;
async fn update_network_config_state(
&self,
identify: T,
network_inst_id: Uuid,
disabled: bool,
) -> Result<C, E>;
async fn list_network_configs(&self, identify: T, props: ListNetworkProps)
-> Result<Vec<C>, E>;
async fn get_network_config(&self, identify: T, network_inst_id: &str) -> Result<Option<C>, E>;
}