From 7ae76f622c31dec5beeebaa594f02cb7d6c5e224 Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Wed, 7 Jan 2026 16:37:51 +0800 Subject: [PATCH] feat: added proxy_host builder, and improve transaction borrowing --- .../nginx/proxy_host/create_location.rs | 6 +- .../nginx/proxy_host/create_proxy.rs | 8 +- .../restricted/nginx/proxy_host/get_proxy.rs | 8 +- .../nginx/proxy_host/remove_location.rs | 6 +- .../nginx/proxy_host/remove_proxy.rs | 8 +- .../nginx/proxy_host/update_location.rs | 6 +- .../nginx/proxy_host/update_proxy.rs | 8 +- .../nginx/upstream/create_upstream.rs | 6 +- .../nginx/upstream/create_upstream_target.rs | 8 +- .../nginx/upstream/remove_upstream.rs | 6 +- .../nginx/upstream/remove_upstream_target.rs | 6 +- .../nginx/upstream/update_upstream.rs | 6 +- .../nginx/upstream/update_upstream_target.rs | 5 +- apps/api/src/services/nginx.rs | 5 +- apps/api/src/services/nginx/builder.rs | 20 ++++- apps/api/src/services/nginx/proxy_host.rs | 86 ++++++++++++------- apps/api/src/services/nginx/upstream.rs | 4 +- 17 files changed, 136 insertions(+), 66 deletions(-) diff --git a/apps/api/src/routes/api/restricted/nginx/proxy_host/create_location.rs b/apps/api/src/routes/api/restricted/nginx/proxy_host/create_location.rs index f184c27..d804553 100644 --- a/apps/api/src/routes/api/restricted/nginx/proxy_host/create_location.rs +++ b/apps/api/src/routes/api/restricted/nginx/proxy_host/create_location.rs @@ -30,7 +30,7 @@ mod tests { use axum::http::StatusCode; use axum_test::TestServer; - use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase}; + use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase, MockRow}; use database::generated::entities::{location, upstream, upstream_target}; @@ -105,11 +105,13 @@ mod tests { created_at: chrono::Utc::now(), updated_at: chrono::Utc::now(), }; + let dummy_row: Vec = vec![]; let db = MockDatabase::new(DatabaseBackend::Sqlite) .append_query_results(vec![vec![loc_model.clone()]]) // additional query result for regenerate_and_apply_config -> generate_config .append_query_results(vec![vec![(up_model.clone(), Some(target_model.clone()))]]) + .append_query_results(vec![dummy_row]) .into_connection(); let router = get_router_with_state(db.clone()); @@ -213,7 +215,7 @@ pub async fn create_location( state .service .nginx - .regenerate_and_apply_config(state.service.agent_client.clone(), Some(&mut tx)) + .regenerate_and_apply_config(state.service.agent_client.clone(), &Some(&mut tx)) .await?; tx.commit().await?; diff --git a/apps/api/src/routes/api/restricted/nginx/proxy_host/create_proxy.rs b/apps/api/src/routes/api/restricted/nginx/proxy_host/create_proxy.rs index da1ad9e..abb1f70 100644 --- a/apps/api/src/routes/api/restricted/nginx/proxy_host/create_proxy.rs +++ b/apps/api/src/routes/api/restricted/nginx/proxy_host/create_proxy.rs @@ -30,7 +30,7 @@ mod tests { use axum::http::StatusCode; use axum_test::TestServer; - use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase}; + use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase, MockRow}; use database::generated::entities::{location, proxy_host, upstream, upstream_target}; @@ -125,12 +125,14 @@ mod tests { created_at: chrono::Utc::now(), updated_at: chrono::Utc::now(), }; + let dummy_row: Vec = vec![]; let db = MockDatabase::new(DatabaseBackend::Sqlite) .append_query_results(vec![vec![ph_model.clone()]]) .append_query_results(vec![vec![loc_model.clone()]]) // additional query result for regenerate_and_apply_config -> generate_config .append_query_results(vec![vec![(up_model.clone(), Some(target_model.clone()))]]) + .append_query_results(vec![dummy_row]) .into_connection(); let router = get_router_with_state(db.clone()); @@ -293,13 +295,13 @@ pub async fn create_proxy( let mut tx = state.database_connection.begin().await?; let info = proxy_service - .create_proxy(create_info, Some(&mut tx)) + .create_proxy(create_info, &Some(&mut tx)) .await?; state .service .nginx - .regenerate_and_apply_config(state.service.agent_client.clone(), Some(&mut tx)) + .regenerate_and_apply_config(state.service.agent_client.clone(), &Some(&mut tx)) .await?; tx.commit().await?; diff --git a/apps/api/src/routes/api/restricted/nginx/proxy_host/get_proxy.rs b/apps/api/src/routes/api/restricted/nginx/proxy_host/get_proxy.rs index f57fa06..63eb584 100644 --- a/apps/api/src/routes/api/restricted/nginx/proxy_host/get_proxy.rs +++ b/apps/api/src/routes/api/restricted/nginx/proxy_host/get_proxy.rs @@ -46,9 +46,9 @@ pub async fn get_proxy_list( include_upstream: true, filter_by_enabled: false, }), - None, + &None, ), - svc.get_total_proxies(None, None), + svc.get_total_proxies(None, &None), ); let proxies = proxies_res?; @@ -271,11 +271,11 @@ pub async fn get_proxy( include_upstream: true, filter_by_enabled: false, }), - None, + &None, ) .await? } else { - svc.get_proxy(proxy_id, None, None).await? + svc.get_proxy(proxy_id, None, &None).await? }; Ok(Json(info.into())) } diff --git a/apps/api/src/routes/api/restricted/nginx/proxy_host/remove_location.rs b/apps/api/src/routes/api/restricted/nginx/proxy_host/remove_location.rs index 8035c8e..1dc8c3a 100644 --- a/apps/api/src/routes/api/restricted/nginx/proxy_host/remove_location.rs +++ b/apps/api/src/routes/api/restricted/nginx/proxy_host/remove_location.rs @@ -37,7 +37,7 @@ pub async fn remove_location( state .service .nginx - .regenerate_and_apply_config(state.service.agent_client.clone(), Some(&mut tx)) + .regenerate_and_apply_config(state.service.agent_client.clone(), &Some(&mut tx)) .await?; tx.commit().await?; @@ -50,7 +50,7 @@ mod tests { use axum::http::StatusCode; use axum_test::TestServer; - use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase}; + use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase, MockRow}; use database::generated::entities::{location, upstream, upstream_target}; @@ -122,6 +122,7 @@ mod tests { created_at: chrono::Utc::now(), updated_at: chrono::Utc::now(), }; + let dummy_row: Vec = vec![]; let db = MockDatabase::new(DatabaseBackend::Sqlite) .append_query_results(vec![vec![existing.clone()]]) @@ -131,6 +132,7 @@ mod tests { }]) // additional query result for regenerate_and_apply_config -> generate_config .append_query_results(vec![vec![(up_model.clone(), Some(target_model.clone()))]]) + .append_query_results(vec![dummy_row]) .into_connection(); let router = get_router_with_state(db.clone()); diff --git a/apps/api/src/routes/api/restricted/nginx/proxy_host/remove_proxy.rs b/apps/api/src/routes/api/restricted/nginx/proxy_host/remove_proxy.rs index 1ab462e..b53a740 100644 --- a/apps/api/src/routes/api/restricted/nginx/proxy_host/remove_proxy.rs +++ b/apps/api/src/routes/api/restricted/nginx/proxy_host/remove_proxy.rs @@ -34,11 +34,11 @@ pub async fn remove_proxy( let svc = &state.service.nginx.get_proxy_service(); let mut tx = state.database_connection.begin().await?; - svc.delete_proxy(proxy_id, Some(&mut tx)).await?; + svc.delete_proxy(proxy_id, &Some(&mut tx)).await?; state .service .nginx - .regenerate_and_apply_config(state.service.agent_client.clone(), Some(&mut tx)) + .regenerate_and_apply_config(state.service.agent_client.clone(), &Some(&mut tx)) .await?; tx.commit().await?; @@ -51,7 +51,7 @@ mod tests { use axum::http::StatusCode; use axum_test::TestServer; - use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase, MockExecResult}; + use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase, MockExecResult, MockRow}; use database::generated::entities::{proxy_host, upstream, upstream_target}; @@ -125,6 +125,7 @@ mod tests { created_at: chrono::Utc::now(), updated_at: chrono::Utc::now(), }; + let dummy_row: Vec = vec![]; let db = MockDatabase::new(DatabaseBackend::Sqlite) .append_query_results(vec![vec![existing.clone()]]) @@ -140,6 +141,7 @@ mod tests { ]) // additional query result for regenerate_and_apply_config -> generate_config .append_query_results(vec![vec![(up_model.clone(), Some(target_model.clone()))]]) + .append_query_results(vec![dummy_row]) .into_connection(); let router = get_router_with_state(db.clone()); diff --git a/apps/api/src/routes/api/restricted/nginx/proxy_host/update_location.rs b/apps/api/src/routes/api/restricted/nginx/proxy_host/update_location.rs index 2f67ce5..b1d5144 100644 --- a/apps/api/src/routes/api/restricted/nginx/proxy_host/update_location.rs +++ b/apps/api/src/routes/api/restricted/nginx/proxy_host/update_location.rs @@ -34,7 +34,7 @@ mod tests { use axum::http::StatusCode; use axum_test::TestServer; - use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase}; + use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase, MockRow}; use database::generated::entities::{location, upstream, upstream_target}; @@ -111,12 +111,14 @@ mod tests { created_at: chrono::Utc::now(), updated_at: chrono::Utc::now(), }; + let dummy_row: Vec = vec![]; let db = MockDatabase::new(DatabaseBackend::Sqlite) .append_query_results(first) .append_query_results(second) // additional query result for regenerate_and_apply_config -> generate_config .append_query_results(vec![vec![(up_model.clone(), Some(target_model.clone()))]]) + .append_query_results(vec![dummy_row]) .into_connection(); let router = get_router_with_state(db.clone()); @@ -210,7 +212,7 @@ pub async fn update_location( state .service .nginx - .regenerate_and_apply_config(state.service.agent_client.clone(), Some(&mut tx)) + .regenerate_and_apply_config(state.service.agent_client.clone(), &Some(&mut tx)) .await?; tx.commit().await?; diff --git a/apps/api/src/routes/api/restricted/nginx/proxy_host/update_proxy.rs b/apps/api/src/routes/api/restricted/nginx/proxy_host/update_proxy.rs index 64fbfe5..4c22135 100644 --- a/apps/api/src/routes/api/restricted/nginx/proxy_host/update_proxy.rs +++ b/apps/api/src/routes/api/restricted/nginx/proxy_host/update_proxy.rs @@ -26,7 +26,7 @@ mod tests { use axum::http::StatusCode; use axum_test::TestServer; - use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase}; + use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase, MockRow}; use database::generated::entities::{proxy_host, upstream, upstream_target}; @@ -105,12 +105,14 @@ mod tests { created_at: chrono::Utc::now(), updated_at: chrono::Utc::now(), }; + let dummy_row: Vec = vec![]; let db = MockDatabase::new(DatabaseBackend::Sqlite) .append_query_results(first) .append_query_results(second) // additional query result for regenerate_and_apply_config -> generate_config .append_query_results(vec![vec![(up_model.clone(), Some(target_model.clone()))]]) + .append_query_results(vec![dummy_row]) .into_connection(); let router = get_router_with_state(db.clone()); @@ -213,11 +215,11 @@ pub async fn update_proxy( let update: UpdateProxyHostInfo = payload.into(); let mut tx = state.database_connection.begin().await?; - let info = svc.update_proxy(proxy_id, update, Some(&mut tx)).await?; + let info = svc.update_proxy(proxy_id, update, &Some(&mut tx)).await?; state .service .nginx - .regenerate_and_apply_config(state.service.agent_client.clone(), Some(&mut tx)) + .regenerate_and_apply_config(state.service.agent_client.clone(), &Some(&mut tx)) .await?; tx.commit().await?; diff --git a/apps/api/src/routes/api/restricted/nginx/upstream/create_upstream.rs b/apps/api/src/routes/api/restricted/nginx/upstream/create_upstream.rs index 67cb4e7..c781f32 100644 --- a/apps/api/src/routes/api/restricted/nginx/upstream/create_upstream.rs +++ b/apps/api/src/routes/api/restricted/nginx/upstream/create_upstream.rs @@ -131,7 +131,7 @@ pub async fn create_upstream( state .service .nginx - .regenerate_and_apply_config(state.service.agent_client.clone(), Some(&mut tx)) + .regenerate_and_apply_config(state.service.agent_client.clone(), &Some(&mut tx)) .await?; tx.commit().await?; @@ -145,7 +145,7 @@ mod tests { use axum::http::StatusCode; use axum_test::TestServer; - use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase}; + use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase, MockRow}; use database::generated::entities::{upstream, upstream_target}; @@ -204,6 +204,7 @@ mod tests { created_at: chrono::Utc::now(), updated_at: chrono::Utc::now(), }; + let dummy_row: Vec = vec![]; // service will likely perform an insert and then query to return created models let db = MockDatabase::new(DatabaseBackend::Sqlite) @@ -213,6 +214,7 @@ mod tests { // `find_with_related` returns rows of `(upstream, Option)` which // the mock DB expects as `(Model, Option)` per row. .append_query_results(vec![vec![(up_model.clone(), Some(target_model.clone()))]]) + .append_query_results(vec![dummy_row]) .into_connection(); let router = get_router_with_state(db.clone()); diff --git a/apps/api/src/routes/api/restricted/nginx/upstream/create_upstream_target.rs b/apps/api/src/routes/api/restricted/nginx/upstream/create_upstream_target.rs index 1584871..93e20c3 100644 --- a/apps/api/src/routes/api/restricted/nginx/upstream/create_upstream_target.rs +++ b/apps/api/src/routes/api/restricted/nginx/upstream/create_upstream_target.rs @@ -86,7 +86,7 @@ pub async fn add_upstream_target( state .service .nginx - .regenerate_and_apply_config(state.service.agent_client.clone(), Some(&mut tx)) + .regenerate_and_apply_config(state.service.agent_client.clone(), &Some(&mut tx)) .await?; tx.commit().await?; @@ -100,7 +100,7 @@ mod tests { use axum::http::StatusCode; use axum_test::TestServer; - use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase}; + use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase, MockRow}; use database::generated::entities::{upstream, upstream_target}; @@ -158,6 +158,7 @@ mod tests { created_at: chrono::Utc::now(), updated_at: chrono::Utc::now(), }; + let dummy_row: Vec = vec![]; // configure mock agent to return an error on apply let mut mock = MockAgentService::new(); @@ -175,6 +176,7 @@ mod tests { let db = MockDatabase::new(DatabaseBackend::Sqlite) .append_query_results(vec![vec![target_model.clone()]]) .append_query_results(vec![vec![(up_model.clone(), Some(target_model.clone()))]]) + .append_query_results(vec![dummy_row]) .into_connection(); let program_settings = ProgramSettings::mock(); @@ -235,11 +237,13 @@ mod tests { created_at: chrono::Utc::now(), updated_at: chrono::Utc::now(), }; + let dummy_row: Vec = vec![]; let db = MockDatabase::new(DatabaseBackend::Sqlite) .append_query_results(vec![vec![target_model.clone()]]) // additional query result for regenerate_and_apply_config -> generate_config .append_query_results(vec![vec![(up_model.clone(), Some(target_model.clone()))]]) + .append_query_results(vec![dummy_row]) .into_connection(); let router = get_router_with_state(db.clone()); diff --git a/apps/api/src/routes/api/restricted/nginx/upstream/remove_upstream.rs b/apps/api/src/routes/api/restricted/nginx/upstream/remove_upstream.rs index 9b8ea83..ec8be97 100644 --- a/apps/api/src/routes/api/restricted/nginx/upstream/remove_upstream.rs +++ b/apps/api/src/routes/api/restricted/nginx/upstream/remove_upstream.rs @@ -40,7 +40,7 @@ pub async fn remove_upstream( state .service .nginx - .regenerate_and_apply_config(state.service.agent_client.clone(), Some(&mut tx)) + .regenerate_and_apply_config(state.service.agent_client.clone(), &Some(&mut tx)) .await?; tx.commit().await?; @@ -54,7 +54,7 @@ mod tests { use axum::http::StatusCode; use axum_test::TestServer; - use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase, MockExecResult}; + use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase, MockExecResult, MockRow}; use database::generated::entities::{upstream, upstream_target}; @@ -109,6 +109,7 @@ mod tests { created_at: chrono::Utc::now(), updated_at: chrono::Utc::now(), }; + let dummy_row: Vec = vec![]; let db = MockDatabase::new(DatabaseBackend::Sqlite) .append_query_results(vec![vec![existing.clone()]]) @@ -124,6 +125,7 @@ mod tests { ]) // additional query result for regenerate_and_apply_config -> generate_config .append_query_results(vec![vec![(existing.clone(), Some(target_model.clone()))]]) + .append_query_results(vec![dummy_row]) .into_connection(); let router = get_router_with_state(db.clone()); diff --git a/apps/api/src/routes/api/restricted/nginx/upstream/remove_upstream_target.rs b/apps/api/src/routes/api/restricted/nginx/upstream/remove_upstream_target.rs index e4c858e..749f3d2 100644 --- a/apps/api/src/routes/api/restricted/nginx/upstream/remove_upstream_target.rs +++ b/apps/api/src/routes/api/restricted/nginx/upstream/remove_upstream_target.rs @@ -40,7 +40,7 @@ pub async fn remove_upstream_target( state .service .nginx - .regenerate_and_apply_config(state.service.agent_client.clone(), Some(&mut tx)) + .regenerate_and_apply_config(state.service.agent_client.clone(), &Some(&mut tx)) .await?; tx.commit().await?; @@ -54,7 +54,7 @@ mod tests { use axum::http::StatusCode; use axum_test::TestServer; - use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase, MockExecResult}; + use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase, MockExecResult, MockRow}; use database::generated::entities::{upstream, upstream_target}; @@ -110,6 +110,7 @@ mod tests { created_at: chrono::Utc::now(), updated_at: chrono::Utc::now(), }; + let dummy_row: Vec = vec![]; let first: Vec> = vec![vec![current_model.clone()]]; let db = MockDatabase::new(DatabaseBackend::Sqlite) @@ -120,6 +121,7 @@ mod tests { }]) // additional query result for regenerate_and_apply_config -> generate_config .append_query_results(vec![vec![(up_model.clone(), Some(current_model.clone()))]]) + .append_query_results(vec![dummy_row]) .into_connection(); let router = get_router_with_state(db.clone()); diff --git a/apps/api/src/routes/api/restricted/nginx/upstream/update_upstream.rs b/apps/api/src/routes/api/restricted/nginx/upstream/update_upstream.rs index 86da499..1cf668c 100644 --- a/apps/api/src/routes/api/restricted/nginx/upstream/update_upstream.rs +++ b/apps/api/src/routes/api/restricted/nginx/upstream/update_upstream.rs @@ -78,7 +78,7 @@ pub async fn update_upstream( state .service .nginx - .regenerate_and_apply_config(state.service.agent_client.clone(), Some(&mut tx)) + .regenerate_and_apply_config(state.service.agent_client.clone(), &Some(&mut tx)) .await?; tx.commit().await?; @@ -92,7 +92,7 @@ mod tests { use axum::http::StatusCode; use axum_test::TestServer; - use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase}; + use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase, MockRow}; use database::generated::entities::{upstream, upstream_target}; @@ -152,6 +152,7 @@ mod tests { let up_model = current_model.clone(); let first: Vec> = vec![vec![current_model.clone()]]; let second: Vec> = vec![vec![updated_model.clone()]]; + let dummy_row: Vec = vec![]; let db = MockDatabase::new(DatabaseBackend::Sqlite) .append_query_results(first) .append_query_results(second) @@ -160,6 +161,7 @@ mod tests { up_model.clone(), Option::::None, )]]) + .append_query_results(vec![dummy_row]) .into_connection(); let router = get_router_with_state(db.clone()); diff --git a/apps/api/src/routes/api/restricted/nginx/upstream/update_upstream_target.rs b/apps/api/src/routes/api/restricted/nginx/upstream/update_upstream_target.rs index ef8ac57..666cfb0 100644 --- a/apps/api/src/routes/api/restricted/nginx/upstream/update_upstream_target.rs +++ b/apps/api/src/routes/api/restricted/nginx/upstream/update_upstream_target.rs @@ -70,7 +70,7 @@ pub async fn update_upstream_target( state .service .nginx - .regenerate_and_apply_config(state.service.agent_client.clone(), Some(&mut tx)) + .regenerate_and_apply_config(state.service.agent_client.clone(), &Some(&mut tx)) .await?; tx.commit().await?; @@ -165,11 +165,14 @@ mod tests { // additional query result for regenerate_and_apply_config -> generate_config let third: Vec)>> = vec![vec![(up_model.clone(), Some(updated_model.clone()))]]; + // placeholder for other queries called by regenerate_and_apply_config + let fourth: Vec> = vec![vec![]]; let db = MockDatabase::new(DatabaseBackend::Sqlite) .append_query_results(first) .append_query_results(second) .append_query_results(third) + .append_query_results(fourth) .into_connection(); let router = get_router_with_state(db.clone()); diff --git a/apps/api/src/services/nginx.rs b/apps/api/src/services/nginx.rs index e21b882..a732dc5 100644 --- a/apps/api/src/services/nginx.rs +++ b/apps/api/src/services/nginx.rs @@ -81,12 +81,13 @@ impl NginxService { pub async fn generate_config( &self, - tx: Option<&mut DatabaseTransaction>, + tx: &Option<&mut DatabaseTransaction>, ) -> Result { let mut builder = NginxConfigBuilder::default(); self.upstream_service .generate_config(&mut builder, tx) .await?; + self.proxy_service.generate_config(&mut builder, tx).await?; builder.to_nginx_config(None) } @@ -94,7 +95,7 @@ impl NginxService { pub async fn regenerate_and_apply_config( &self, agent: Arc, - tx: Option<&mut DatabaseTransaction>, + tx: &Option<&mut DatabaseTransaction>, ) -> Result<(), ServiceError> { let config = self.generate_config(tx).await?; diff --git a/apps/api/src/services/nginx/builder.rs b/apps/api/src/services/nginx/builder.rs index 0b435bb..632d63b 100644 --- a/apps/api/src/services/nginx/builder.rs +++ b/apps/api/src/services/nginx/builder.rs @@ -1,4 +1,7 @@ -use crate::{errors::service_error::ServiceError, services::nginx::info::upstream::UpstreamInfo}; +use crate::{ + errors::service_error::ServiceError, + services::nginx::info::{proxy_host::ProxyHostInfo, upstream::UpstreamInfo}, +}; pub const INDENT_SIZE: usize = 2; @@ -9,6 +12,7 @@ pub trait NginxConfigProvider { #[derive(Default)] pub struct NginxConfigBuilder { upstreams: Vec, + proxy_hosts: Vec, } impl NginxConfigBuilder { @@ -21,6 +25,16 @@ impl NginxConfigBuilder { self.add_upstream(upstream); } } + + pub fn add_proxy_host(&mut self, proxy_host: ProxyHostInfo) { + self.proxy_hosts.push(proxy_host); + } + + pub fn add_proxy_hosts(&mut self, proxy_hosts: Vec) { + for proxy_host in proxy_hosts { + self.add_proxy_host(proxy_host); + } + } } impl NginxConfigProvider for NginxConfigBuilder { @@ -35,6 +49,10 @@ impl NginxConfigProvider for NginxConfigBuilder { config.push_str(&upstream.to_nginx_config(indent)?); } + for proxy_host in &self.proxy_hosts { + config.push('\n'); + config.push_str(&proxy_host.to_nginx_config(indent)?); + } // TODO: Add other sections like servers, locations, etc. // trailing newline for file ending config.push('\n'); diff --git a/apps/api/src/services/nginx/proxy_host.rs b/apps/api/src/services/nginx/proxy_host.rs index e77626e..afc3688 100644 --- a/apps/api/src/services/nginx/proxy_host.rs +++ b/apps/api/src/services/nginx/proxy_host.rs @@ -11,7 +11,10 @@ use database::generated::entities::{location, proxy_host}; use crate::{ errors::service_error::ServiceError, helpers::database::PaginationFilter, - services::nginx::info::proxy_host::{ProxyHostCreateInfo, ProxyHostInfo, UpdateProxyHostInfo}, + services::nginx::{ + builder::NginxConfigBuilder, + info::proxy_host::{ProxyHostCreateInfo, ProxyHostInfo, UpdateProxyHostInfo}, + }, with_conn, }; @@ -20,35 +23,40 @@ pub trait ProxyService: Send + Sync { async fn create_proxy( &self, create_info: ProxyHostCreateInfo, - tx: Option<&mut DatabaseTransaction>, + tx: &Option<&mut DatabaseTransaction>, ) -> Result; async fn get_total_proxies( &self, options: Option, - tx: Option<&mut DatabaseTransaction>, + tx: &Option<&mut DatabaseTransaction>, ) -> Result; async fn get_proxies( &self, pagination: Option, options: Option, - tx: Option<&mut DatabaseTransaction>, + tx: &Option<&mut DatabaseTransaction>, ) -> Result, ServiceError>; async fn get_proxy( &self, proxy_id: uuid::Uuid, options: Option, - tx: Option<&mut DatabaseTransaction>, + tx: &Option<&mut DatabaseTransaction>, ) -> Result; async fn update_proxy( &self, proxy_id: uuid::Uuid, update: UpdateProxyHostInfo, - tx: Option<&mut DatabaseTransaction>, + tx: &Option<&mut DatabaseTransaction>, ) -> Result; async fn delete_proxy( &self, proxy_id: uuid::Uuid, - tx: Option<&mut DatabaseTransaction>, + tx: &Option<&mut DatabaseTransaction>, + ) -> Result<(), ServiceError>; + async fn generate_config( + &self, + builder: &mut NginxConfigBuilder, + tx: &Option<&mut DatabaseTransaction>, ) -> Result<(), ServiceError>; } @@ -78,18 +86,18 @@ impl ProxyService for ProxyServiceImpl { async fn create_proxy( &self, create_info: ProxyHostCreateInfo, - tx: Option<&mut DatabaseTransaction>, + tx: &Option<&mut DatabaseTransaction>, ) -> Result { let (proxy_host, location_models): (proxy_host::ActiveModel, Vec) = create_info.into(); - let mut maybe_owned_tx: Option = None; - let tx_ref: Option<&mut DatabaseTransaction> = if let Some(tx) = tx { - Some(tx) - } else { - maybe_owned_tx = Some(self.connection.begin().await?); - maybe_owned_tx.as_mut() + let owned_tx = match tx { + Some(_) => None, + None => Some(self.connection.begin().await.map_err(ServiceError::from)?), }; + + let tx_ref = owned_tx.as_ref().or(tx.as_deref()); + let r = with_conn!(&*self.connection, tx_ref, conn, { let inserted_proxy = proxy_host.insert(*conn).await?; let mut inserted_location_models: Vec = @@ -103,16 +111,13 @@ impl ProxyService for ProxyServiceImpl { (inserted_proxy, inserted_location_models) }); - if let Some(t) = maybe_owned_tx.take() { - t.commit().await?; - } Ok(r.into()) } async fn get_total_proxies( &self, _options: Option, - tx: Option<&mut DatabaseTransaction>, + tx: &Option<&mut DatabaseTransaction>, ) -> Result { #[derive(Debug, FromQueryResult)] struct CountResult { @@ -133,7 +138,7 @@ impl ProxyService for ProxyServiceImpl { &self, pagination: Option, options: Option, - tx: Option<&mut DatabaseTransaction>, + tx: &Option<&mut DatabaseTransaction>, ) -> Result, ServiceError> { let r = with_conn!(&*self.connection, tx, conn, { let mut find_query = proxy_host::Entity::find(); @@ -177,7 +182,7 @@ impl ProxyService for ProxyServiceImpl { &self, proxy_id: uuid::Uuid, options: Option, - tx: Option<&mut DatabaseTransaction>, + tx: &Option<&mut DatabaseTransaction>, ) -> Result { let r: ProxyHostInfo = with_conn!(&*self.connection, tx, conn, { let find_query = proxy_host::Entity::find_by_id(proxy_id) @@ -217,7 +222,7 @@ impl ProxyService for ProxyServiceImpl { &self, proxy_id: uuid::Uuid, update: UpdateProxyHostInfo, - tx: Option<&mut DatabaseTransaction>, + tx: &Option<&mut DatabaseTransaction>, ) -> Result { let current_model = with_conn!(&*self.connection, tx, conn, { proxy_host::Entity::find_by_id(proxy_id) @@ -239,7 +244,7 @@ impl ProxyService for ProxyServiceImpl { async fn delete_proxy( &self, proxy_id: uuid::Uuid, - tx: Option<&mut DatabaseTransaction>, + tx: &Option<&mut DatabaseTransaction>, ) -> Result<(), ServiceError> { let model = with_conn!(&*self.connection, tx, conn, { proxy_host::Entity::find_by_id(proxy_id) @@ -255,6 +260,25 @@ impl ProxyService for ProxyServiceImpl { Ok(()) }) } + + async fn generate_config( + &self, + builder: &mut NginxConfigBuilder, + tx: &Option<&mut DatabaseTransaction>, + ) -> Result<(), ServiceError> { + let proxies = self + .get_proxies( + None, + Some(ProxyHostListOptions { + include_upstream: true, + ..Default::default() + }), + tx, + ) + .await?; + builder.add_proxy_hosts(proxies); + Ok(()) + } } #[cfg(test)] @@ -331,7 +355,7 @@ mod tests { locations: Vec::new(), }; - let res = svc.create_proxy(create_info, None).await; + let res = svc.create_proxy(create_info, &None).await; assert!(res.is_ok()); let info = res.expect("Failed to create proxy"); assert_eq!(info.domain, "example.com"); @@ -345,7 +369,7 @@ mod tests { let svc = ProxyServiceImpl::new(Arc::new(db)); let res = svc - .get_total_proxies(None, None) + .get_total_proxies(None, &None) .await .expect("Failed to get total proxies"); assert_eq!(res, 0u64); @@ -398,7 +422,7 @@ mod tests { .into_connection(); let svc = ProxyServiceImpl::new(Arc::new(db)); - let res = svc.get_proxies(None, None, None).await; + let res = svc.get_proxies(None, None, &None).await; assert!(res.is_ok()); let list = res.expect("Failed to get proxies"); assert_eq!(list.len(), 2); @@ -431,7 +455,7 @@ mod tests { .into_connection(); let svc = ProxyServiceImpl::new(Arc::new(db)); - let res = svc.get_proxy(id, None, None).await; + let res = svc.get_proxy(id, None, &None).await; assert!(res.is_ok()); let got = res.expect("Failed to get proxy"); assert_eq!(got.id, id); @@ -444,7 +468,7 @@ mod tests { .into_connection(); let svc = ProxyServiceImpl::new(Arc::new(db)); - let res = svc.get_proxy(uuid::Uuid::new_v4(), None, None).await; + let res = svc.get_proxy(uuid::Uuid::new_v4(), None, &None).await; assert!(matches!(res, Err(ServiceError::NotFound(_)))); } @@ -510,7 +534,7 @@ mod tests { default_upstream_id: None, }; - let res = svc.update_proxy(id, update_info, None).await; + let res = svc.update_proxy(id, update_info, &None).await; assert!(res.is_ok()); let got = res.expect("Failed to update proxy"); assert_eq!(got.name.expect("Name should be present"), "new"); @@ -541,7 +565,7 @@ mod tests { meta: None, default_upstream_id: None, }, - None, + &None, ) .await; @@ -580,7 +604,7 @@ mod tests { let svc = ProxyServiceImpl::new(Arc::new(db)); - let res = svc.delete_proxy(id, None).await; + let res = svc.delete_proxy(id, &None).await; assert!(res.is_ok()); } @@ -592,7 +616,7 @@ mod tests { let svc = ProxyServiceImpl::new(Arc::new(db)); - let res = svc.delete_proxy(uuid::Uuid::new_v4(), None).await; + let res = svc.delete_proxy(uuid::Uuid::new_v4(), &None).await; assert!(matches!(res, Err(ServiceError::NotFound(_)))); } } diff --git a/apps/api/src/services/nginx/upstream.rs b/apps/api/src/services/nginx/upstream.rs index 5ed9a14..8c8dd31 100644 --- a/apps/api/src/services/nginx/upstream.rs +++ b/apps/api/src/services/nginx/upstream.rs @@ -88,7 +88,7 @@ pub trait UpstreamService: Send + Sync { async fn generate_config( &self, builder: &mut NginxConfigBuilder, - tx: Option<&mut DatabaseTransaction>, + tx: &Option<&mut DatabaseTransaction>, ) -> Result<(), ServiceError>; } @@ -457,7 +457,7 @@ impl UpstreamService for UpstreamServiceImpl { async fn generate_config( &self, builder: &mut NginxConfigBuilder, - tx: Option<&mut DatabaseTransaction>, + tx: &Option<&mut DatabaseTransaction>, ) -> Result<(), ServiceError> { // get all upstreams and their targets let upstreams = with_conn!(&*self.connection, tx, conn, {