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
+5 -5
View File
@@ -41,8 +41,7 @@ pub struct RestfulServer {
// serve_task: Option<ScopedTask<()>>,
// delete_task: Option<ScopedTask<tower_sessions::session_store::Result<()>>>,
network_api: NetworkApi,
// network_api: NetworkApi<WebClientManager>,
web_router: Option<Router>,
}
@@ -108,7 +107,7 @@ impl RestfulServer {
) -> anyhow::Result<Self> {
assert!(client_mgr.is_running());
let network_api = NetworkApi::new();
// let network_api = NetworkApi::new();
Ok(RestfulServer {
bind_addr,
@@ -116,7 +115,7 @@ impl RestfulServer {
db,
// serve_task: None,
// delete_task: None,
network_api,
// network_api,
web_router,
})
}
@@ -188,6 +187,7 @@ impl RestfulServer {
}
}
#[allow(unused_mut)]
pub async fn start(
mut self,
) -> Result<
@@ -238,7 +238,7 @@ impl RestfulServer {
let app = Router::new()
.route("/api/v1/summary", get(Self::handle_get_summary))
.route("/api/v1/sessions", get(Self::handle_list_all_sessions))
.merge(self.network_api.build_route())
.merge(NetworkApi::build_route())
.route_layer(login_required!(Backend))
.merge(auth::router())
.with_state(self.client_mgr.clone())
+67 -219
View File
@@ -1,5 +1,3 @@
use std::sync::Arc;
use axum::extract::Path;
use axum::http::StatusCode;
use axum::routing::{delete, post};
@@ -7,12 +5,14 @@ use axum::{extract::State, routing::get, Json, Router};
use axum_login::AuthUser;
use easytier::launcher::NetworkConfig;
use easytier::proto::common::Void;
use easytier::proto::rpc_types::controller::BaseController;
use easytier::proto::{self, api::manage::*, web::*};
use easytier::proto::{api::manage::*, web::*};
use easytier::rpc_service::remote_client::{
ListNetworkInstanceIdsJsonResp, RemoteClientError, RemoteClientManager,
};
use sea_orm::DbErr;
use crate::client_manager::session::{Location, Session};
use crate::client_manager::ClientManager;
use crate::db::{ListNetworkProps, UserIdInDb};
use crate::client_manager::session::Location;
use crate::db::UserIdInDb;
use super::users::AuthSession;
use super::{
@@ -31,6 +31,21 @@ fn convert_rpc_error(e: RpcError) -> (StatusCode, Json<Error>) {
(status_code, Json(error))
}
fn convert_error(e: RemoteClientError<DbErr>) -> (StatusCode, Json<Error>) {
match e {
RemoteClientError::PersistentError(e) => convert_db_error(e),
RemoteClientError::RpcError(e) => convert_rpc_error(e),
RemoteClientError::ClientNotFound => (
StatusCode::NOT_FOUND,
other_error("Client not found").into(),
),
RemoteClientError::NotFound(msg) => (StatusCode::NOT_FOUND, other_error(msg).into()),
RemoteClientError::Other(msg) => {
(StatusCode::INTERNAL_SERVER_ERROR, other_error(msg).into())
}
}
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
struct ValidateConfigJsonReq {
config: NetworkConfig,
@@ -42,7 +57,7 @@ struct RunNetworkJsonReq {
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
struct ColletNetworkInfoJsonReq {
struct CollectNetworkInfoJsonReq {
inst_ids: Option<Vec<uuid::Uuid>>,
}
@@ -56,12 +71,6 @@ struct RemoveNetworkJsonReq {
inst_ids: Vec<uuid::Uuid>,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
struct ListNetworkInstanceIdsJsonResp {
running_inst_ids: Vec<easytier::proto::common::Uuid>,
disabled_inst_ids: Vec<easytier::proto::common::Uuid>,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
struct ListMachineItem {
client_url: Option<url::Url>,
@@ -74,13 +83,9 @@ struct ListMachineJsonResp {
machines: Vec<ListMachineItem>,
}
pub struct NetworkApi {}
pub struct NetworkApi;
impl NetworkApi {
pub fn new() -> Self {
Self {}
}
fn get_user_id(auth_session: &AuthSession) -> Result<UserIdInDb, (StatusCode, Json<Error>)> {
let Some(user_id) = auth_session.user.as_ref().map(|x| x.id()) else {
return Err((
@@ -91,63 +96,20 @@ impl NetworkApi {
Ok(user_id)
}
async fn get_session_by_machine_id(
auth_session: &AuthSession,
client_mgr: &ClientManager,
machine_id: &uuid::Uuid,
) -> Result<Arc<Session>, HttpHandleError> {
let user_id = Self::get_user_id(auth_session)?;
let Some(result) = client_mgr.get_session_by_machine_id(user_id, machine_id) else {
return Err((
StatusCode::NOT_FOUND,
other_error(format!("No such session: {}", machine_id)).into(),
));
};
let Some(token) = result.get_token().await else {
return Err((
StatusCode::UNAUTHORIZED,
other_error("No token reported".to_string()).into(),
));
};
if !auth_session
.user
.as_ref()
.map(|x| x.tokens.contains(&token.token))
.unwrap_or(false)
{
return Err((
StatusCode::FORBIDDEN,
other_error("Token mismatch".to_string()).into(),
));
}
Ok(result)
}
async fn handle_validate_config(
auth_session: AuthSession,
State(client_mgr): AppState,
Path(machine_id): Path<uuid::Uuid>,
Json(payload): Json<ValidateConfigJsonReq>,
) -> Result<Json<ValidateConfigResponse>, HttpHandleError> {
let config = payload.config;
let result =
Self::get_session_by_machine_id(&auth_session, &client_mgr, &machine_id).await?;
let c = result.scoped_rpc_client();
let ret = c
.validate_config(
BaseController::default(),
ValidateConfigRequest {
config: Some(config),
},
Ok(client_mgr
.handle_validate_config(
(Self::get_user_id(&auth_session)?, machine_id),
payload.config,
)
.await
.map_err(convert_rpc_error)?;
Ok(ret.into())
.map_err(convert_error)?
.into())
}
async fn handle_run_network_instance(
@@ -156,33 +118,13 @@ impl NetworkApi {
Path(machine_id): Path<uuid::Uuid>,
Json(payload): Json<RunNetworkJsonReq>,
) -> Result<Json<Void>, HttpHandleError> {
let config = payload.config;
let result =
Self::get_session_by_machine_id(&auth_session, &client_mgr, &machine_id).await?;
let c = result.scoped_rpc_client();
let resp = c
.run_network_instance(
BaseController::default(),
RunNetworkInstanceRequest {
inst_id: None,
config: Some(config.clone()),
},
)
.await
.map_err(convert_rpc_error)?;
client_mgr
.db()
.insert_or_update_user_network_config(
auth_session.user.as_ref().unwrap().id(),
machine_id,
resp.inst_id.unwrap_or_default().into(),
serde_json::to_string(&config).unwrap(),
.handle_run_network_instance(
(Self::get_user_id(&auth_session)?, machine_id),
payload.config,
)
.await
.map_err(convert_db_error)?;
.map_err(convert_error)?;
Ok(Void::default().into())
}
@@ -191,47 +133,30 @@ impl NetworkApi {
State(client_mgr): AppState,
Path((machine_id, inst_id)): Path<(uuid::Uuid, uuid::Uuid)>,
) -> Result<Json<CollectNetworkInfoResponse>, HttpHandleError> {
let result =
Self::get_session_by_machine_id(&auth_session, &client_mgr, &machine_id).await?;
let c = result.scoped_rpc_client();
let ret = c
.collect_network_info(
BaseController::default(),
CollectNetworkInfoRequest {
inst_ids: vec![inst_id.into()],
},
Ok(client_mgr
.handle_collect_network_info(
(Self::get_user_id(&auth_session)?, machine_id),
Some(vec![inst_id]),
)
.await
.map_err(convert_rpc_error)?;
Ok(ret.into())
.map_err(convert_error)?
.into())
}
async fn handle_collect_network_info(
auth_session: AuthSession,
State(client_mgr): AppState,
Path(machine_id): Path<uuid::Uuid>,
Json(payload): Json<ColletNetworkInfoJsonReq>,
Json(payload): Json<CollectNetworkInfoJsonReq>,
) -> Result<Json<CollectNetworkInfoResponse>, HttpHandleError> {
let result =
Self::get_session_by_machine_id(&auth_session, &client_mgr, &machine_id).await?;
let c = result.scoped_rpc_client();
let ret = c
.collect_network_info(
BaseController::default(),
CollectNetworkInfoRequest {
inst_ids: payload
.inst_ids
.unwrap_or_default()
.into_iter()
.map(Into::into)
.collect(),
},
Ok(client_mgr
.handle_collect_network_info(
(Self::get_user_id(&auth_session)?, machine_id),
payload.inst_ids,
)
.await
.map_err(convert_rpc_error)?;
Ok(ret.into())
.map_err(convert_error)?
.into())
}
async fn handle_list_network_instance_ids(
@@ -239,36 +164,11 @@ impl NetworkApi {
State(client_mgr): AppState,
Path(machine_id): Path<uuid::Uuid>,
) -> Result<Json<ListNetworkInstanceIdsJsonResp>, HttpHandleError> {
let result =
Self::get_session_by_machine_id(&auth_session, &client_mgr, &machine_id).await?;
let c = result.scoped_rpc_client();
let ret = c
.list_network_instance(BaseController::default(), ListNetworkInstanceRequest {})
Ok(client_mgr
.handle_list_network_instance_ids((Self::get_user_id(&auth_session)?, machine_id))
.await
.map_err(convert_rpc_error)?;
let running_inst_ids = ret.inst_ids.clone().into_iter().collect();
// collect networks that are disabled
let disabled_inst_ids = client_mgr
.db()
.list_network_configs(
auth_session.user.unwrap().id(),
Some(machine_id),
ListNetworkProps::DisabledOnly,
)
.await
.map_err(convert_db_error)?
.iter()
.map(|x| Into::<proto::common::Uuid>::into(x.network_instance_id.clone()))
.collect::<Vec<_>>();
Ok(ListNetworkInstanceIdsJsonResp {
running_inst_ids,
disabled_inst_ids,
}
.into())
.map_err(convert_error)?
.into())
}
async fn handle_remove_network_instance(
@@ -276,25 +176,13 @@ impl NetworkApi {
State(client_mgr): AppState,
Path((machine_id, inst_id)): Path<(uuid::Uuid, uuid::Uuid)>,
) -> Result<(), HttpHandleError> {
let result =
Self::get_session_by_machine_id(&auth_session, &client_mgr, &machine_id).await?;
client_mgr
.db()
.delete_network_config(auth_session.user.as_ref().unwrap().id(), inst_id)
.handle_remove_network_instance(
(Self::get_user_id(&auth_session)?, machine_id),
inst_id,
)
.await
.map_err(convert_db_error)?;
let c = result.scoped_rpc_client();
c.delete_network_instance(
BaseController::default(),
DeleteNetworkInstanceRequest {
inst_ids: vec![inst_id.into()],
},
)
.await
.map_err(convert_rpc_error)?;
Ok(())
.map_err(convert_error)
}
async fn handle_list_machines(
@@ -334,37 +222,14 @@ impl NetworkApi {
));
};
let sess = Self::get_session_by_machine_id(&auth_session, &client_mgr, &machine_id).await?;
let cfg = client_mgr
.db()
.update_network_config_state(auth_session.user.unwrap().id(), inst_id, payload.disabled)
.await
.map_err(convert_db_error)?;
let c = sess.scoped_rpc_client();
if payload.disabled {
c.delete_network_instance(
BaseController::default(),
DeleteNetworkInstanceRequest {
inst_ids: vec![inst_id.into()],
},
client_mgr
.handle_update_network_state(
(auth_session.user.unwrap().id(), machine_id),
inst_id,
payload.disabled,
)
.await
.map_err(convert_rpc_error)?;
} else {
c.run_network_instance(
BaseController::default(),
RunNetworkInstanceRequest {
inst_id: Some(inst_id.into()),
config: Some(serde_json::from_str(&cfg.network_config).unwrap()),
},
)
.await
.map_err(convert_rpc_error)?;
}
Ok(())
.map_err(convert_error)
}
async fn handle_get_network_config(
@@ -372,31 +237,14 @@ impl NetworkApi {
State(client_mgr): AppState,
Path((machine_id, inst_id)): Path<(uuid::Uuid, uuid::Uuid)>,
) -> Result<Json<NetworkConfig>, HttpHandleError> {
let inst_id = inst_id.to_string();
let db_row = client_mgr
.db()
.get_network_config(auth_session.user.unwrap().id(), &machine_id, &inst_id)
Ok(client_mgr
.handle_get_network_config((auth_session.user.unwrap().id(), machine_id), inst_id)
.await
.map_err(convert_db_error)?
.ok_or((
StatusCode::NOT_FOUND,
other_error(format!("No such network instance: {}", inst_id)).into(),
))?;
Ok(
serde_json::from_str::<NetworkConfig>(&db_row.network_config)
.map_err(|e| {
(
StatusCode::INTERNAL_SERVER_ERROR,
other_error(format!("Failed to parse network config: {:?}", e)).into(),
)
})?
.into(),
)
.map_err(convert_error)?
.into())
}
pub fn build_route(&mut self) -> Router<AppStateInner> {
pub fn build_route() -> Router<AppStateInner> {
Router::new()
.route("/api/v1/machines", get(Self::handle_list_machines))
.route(