feat: implement Nginx service with upstream management and configuration generation

This commit is contained in:
GW_MC
2025-12-29 15:21:02 +08:00
parent 814f76291c
commit 238c3db92b
15 changed files with 661 additions and 1 deletions

View File

@@ -0,0 +1,226 @@
use std::{option, sync::Arc};
use sea_orm::{
ActiveModelTrait, ColumnTrait, DatabaseConnection, DatabaseTransaction, EntityTrait,
ModelTrait, QueryFilter, QuerySelect,
};
use database::generated::entities::{upstream, upstream_target};
use crate::{
errors::service_error::ServiceError,
helpers::database::PaginationFilter,
services::nginx::info::{
upstream::{UpdateUpstreamInfo, UpstreamCreateInfo, UpstreamInfo},
upstream_target::{UpdateUpstreamTargetInfo, UpstreamTargetCreateInfo, UpstreamTargetInfo},
},
with_conn,
};
pub struct UpstreamService {
connection: Arc<DatabaseConnection>,
}
#[derive(Default)]
pub struct GetUpstreamOptions {
pub include_targets: bool,
}
impl UpstreamService {
pub fn new(connection: Arc<DatabaseConnection>) -> Self {
Self { connection }
}
//
//
pub async fn create_upstream(
&self,
create_info: UpstreamCreateInfo,
tx: Option<&mut DatabaseTransaction>,
) -> Result<UpstreamInfo, ServiceError> {
let model: upstream::ActiveModel = create_info.into();
let r = with_conn!(&*self.connection, tx, conn, { model.insert(*conn).await? });
Ok(r.into())
}
pub async fn get_upstream(
&self,
upstream_id: uuid::Uuid,
options: Option<GetUpstreamOptions>,
tx: Option<&mut DatabaseTransaction>,
) -> Result<UpstreamInfo, ServiceError> {
let concrete_options = options.unwrap_or_default();
let info: UpstreamInfo = if concrete_options.include_targets {
let (up_model, targets) = with_conn!(&*self.connection, tx, conn, {
let up = upstream::Entity::find_by_id(upstream_id)
.one(*conn)
.await?
.ok_or(ServiceError::NotFound(format!(
"Upstream with id {} not found",
upstream_id
)))?;
let targets = upstream_target::Entity::find()
.filter(upstream_target::Column::UpstreamId.eq(upstream_id))
.all(*conn)
.await?;
(up, targets)
});
(up_model, targets).into()
} else {
with_conn!(&*self.connection, tx, conn, {
upstream::Entity::find_by_id(upstream_id)
.one(*conn)
.await?
.ok_or(ServiceError::NotFound(format!(
"Upstream with id {} not found",
upstream_id
)))?
})
.into()
};
Ok(info)
}
pub async fn get_upstreams(
&self,
pagination: Option<PaginationFilter>,
tx: Option<&mut DatabaseTransaction>,
) -> Result<Vec<UpstreamInfo>, ServiceError> {
let r = with_conn!(&*self.connection, tx, conn, {
let find_query = upstream::Entity::find();
let find_query = if let Some(pagination) = pagination {
let (offset, limit) = pagination.get_offset_limit();
find_query.offset(offset).limit(limit)
} else {
find_query
};
find_query.all(*conn).await?
});
Ok(r.into_iter().map(|m| m.into()).collect())
}
pub async fn update_upstream(
&self,
id: uuid::Uuid,
upstream: UpdateUpstreamInfo,
tx: Option<&mut DatabaseTransaction>,
) -> Result<UpstreamInfo, ServiceError> {
let current_model = with_conn!(&*self.connection, tx, conn, {
upstream::Entity::find_by_id(id)
.one(*conn)
.await?
.ok_or(ServiceError::NotFound(format!(
"Upstream with id {} not found",
id
)))?
});
let active_model = upstream.apply_to_model(current_model);
let r = active_model.update(&*self.connection).await?;
Ok(r.into())
}
pub async fn delete_upstream(
&self,
upstream_id: uuid::Uuid,
tx: Option<&mut DatabaseTransaction>,
) -> Result<(), ServiceError> {
let model = with_conn!(&*self.connection, tx, conn, {
upstream::Entity::find_by_id(upstream_id)
.one(*conn)
.await?
.ok_or(ServiceError::NotFound(format!(
"Upstream with id {} not found",
upstream_id
)))?
});
with_conn!(&*self.connection, tx, conn, {
model.delete(*conn).await?;
Ok(())
})
}
//
//
pub async fn create_upstream_target(
&self,
create_info: UpstreamTargetCreateInfo,
tx: Option<&mut DatabaseTransaction>,
) -> Result<UpstreamTargetInfo, ServiceError> {
let model: upstream_target::ActiveModel = create_info.into();
let r = with_conn!(&*self.connection, tx, conn, { model.insert(*conn).await? });
Ok(r.into())
}
pub async fn get_upstream_target(
&self,
target_id: uuid::Uuid,
tx: Option<&mut DatabaseTransaction>,
) -> Result<UpstreamTargetInfo, ServiceError> {
let r = with_conn!(&*self.connection, tx, conn, {
upstream_target::Entity::find_by_id(target_id)
.one(*conn)
.await?
.ok_or(ServiceError::NotFound(format!(
"Upstream target with id {} not found",
target_id
)))?
});
Ok(r.into())
}
pub async fn get_upstream_targets_by_upstream(
&self,
upstream_id: uuid::Uuid,
tx: Option<&mut DatabaseTransaction>,
) -> Result<Vec<UpstreamTargetInfo>, ServiceError> {
let r = with_conn!(&*self.connection, tx, conn, {
upstream_target::Entity::find()
.filter(upstream_target::Column::UpstreamId.eq(upstream_id))
.all(*conn)
.await?
});
Ok(r.into_iter().map(|m| m.into()).collect())
}
pub async fn update_upstream_target(
&self,
id: uuid::Uuid,
target: UpdateUpstreamTargetInfo,
tx: Option<&mut DatabaseTransaction>,
) -> Result<UpstreamTargetInfo, ServiceError> {
let current_model = with_conn!(&*self.connection, tx, conn, {
upstream_target::Entity::find_by_id(id)
.one(*conn)
.await?
.ok_or(ServiceError::NotFound(format!(
"Upstream target with id {} not found",
id
)))?
});
let active_model = target.apply_to_model(current_model);
let r = active_model.update(&*self.connection).await?;
Ok(r.into())
}
pub async fn delete_upstream_target(
&self,
target_id: uuid::Uuid,
tx: Option<&mut DatabaseTransaction>,
) -> Result<(), ServiceError> {
let model = with_conn!(&*self.connection, tx, conn, {
upstream_target::Entity::find_by_id(target_id)
.one(*conn)
.await?
.ok_or(ServiceError::NotFound(format!(
"Upstream target with id {} not found",
target_id
)))?
});
with_conn!(&*self.connection, tx, conn, {
model.delete(*conn).await?;
Ok(())
})
}
}