diff --git a/backend/basic/src/rbum/domain/rbum_item.rs b/backend/basic/src/rbum/domain/rbum_item.rs index 963ff850a..d6f8f205a 100644 --- a/backend/basic/src/rbum/domain/rbum_item.rs +++ b/backend/basic/src/rbum/domain/rbum_item.rs @@ -4,26 +4,44 @@ use tardis::db::sea_orm::prelude::*; use tardis::db::sea_orm::*; use tardis::{TardisCreateEntity, TardisEmptyBehavior, TardisEmptyRelation}; -/// Resource model +/// Resource item model +/// +/// 资源项模型 /// /// Used to represent a specific resource, -/// Each resource corresponds to a [resource kind](crate::rbum::domain::rbum_kind::Model) and [resource domain](crate::rbum::domain::rbum_domain::Model). +/// Each resource item corresponds to a [resource kind](crate::rbum::domain::rbum_kind::Model) and [resource domain](crate::rbum::domain::rbum_domain::Model). +/// +/// 用于表示具体的资源,每个资源项对应一个[资源类型](crate::rbum::domain::rbum_kind::Model) 和 [资源域](crate::rbum::domain::rbum_domain::Model)。 +/// +/// Each resource item corresponds to a unique uri, +/// and the uri consists of ``:///`` . /// -/// Each resource corresponds to a unique uri, -/// and the uri consists of `:///` +/// 每个资源项对应一个唯一的uri,uri 由 ``<资源类型编码>://<资源域编码>/<资源项编码>`` 组成。 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, TardisCreateEntity, TardisEmptyBehavior, TardisEmptyRelation)] #[sea_orm(table_name = "rbum_item")] pub struct Model { + /// Resource item id + /// + /// 资源项id #[sea_orm(primary_key, auto_increment = false)] pub id: String, - /// Resource code + /// Resource item code + /// + /// 资源项编码 #[index(index_id = "unique_id", unique)] pub code: String, + /// Resource item name + /// + /// 资源项名称 pub name: String, /// Associated [resource kind](crate::rbum::domain::rbum_kind::Model) id + /// + /// 关联的[资源类型](crate::rbum::domain::rbum_kind::Model) id #[index(repeat(index_id = "unique_id", unique))] pub rel_rbum_kind_id: String, /// Associated [resource domain](crate::rbum::domain::rbum_domain::Model) id + /// + /// 关联的[资源域](crate::rbum::domain::rbum_domain::Model) id #[index(repeat(index_id = "unique_id", unique))] pub rel_rbum_domain_id: String, diff --git a/backend/basic/src/rbum/domain/rbum_item_attr.rs b/backend/basic/src/rbum/domain/rbum_item_attr.rs index 8315b9d14..f37866dfb 100644 --- a/backend/basic/src/rbum/domain/rbum_item_attr.rs +++ b/backend/basic/src/rbum/domain/rbum_item_attr.rs @@ -4,18 +4,29 @@ use tardis::db::sea_orm::prelude::*; use tardis::db::sea_orm::*; use tardis::{TardisCreateEntity, TardisEmptyBehavior, TardisEmptyRelation}; -/// Resource extended attribute value model +/// Resource item extended attribute value model +/// +/// 资源项扩展属性值模型 #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, TardisCreateEntity, TardisEmptyBehavior, TardisEmptyRelation)] #[sea_orm(table_name = "rbum_item_attr")] pub struct Model { + /// Extended attribute value id + /// + /// 扩展属性值id #[sea_orm(primary_key, auto_increment = false)] pub id: String, /// Extended attribute value + /// + /// 扩展属性值 pub value: String, - /// Associated [resource](crate::rbum::domain::rbum_item::Model) id + /// Associated [resource item](crate::rbum::domain::rbum_item::Model) id + /// + /// 关联的[资源项](crate::rbum::domain::rbum_item::Model) id #[index(index_id = "id", unique)] pub rel_rbum_item_id: String, - /// Associated [resource kind extended attribute](crate::rbum::domain::rbum_kind_attr::Model) id + /// Associated [resource kind attribute definition](crate::rbum::domain::rbum_kind_attr::Model) id + /// + /// 关联的[资源类型属性定义](crate::rbum::domain::rbum_kind_attr::Model) id #[index(index_id = "id", unique)] pub rel_rbum_kind_attr_id: String, diff --git a/backend/basic/src/rbum/domain/rbum_kind.rs b/backend/basic/src/rbum/domain/rbum_kind.rs index f2e515d91..5f776a57b 100644 --- a/backend/basic/src/rbum/domain/rbum_kind.rs +++ b/backend/basic/src/rbum/domain/rbum_kind.rs @@ -34,9 +34,9 @@ pub struct Model { /// /// 资源类型编码 /// - /// Resource kind code, which is required to conform to the scheme specification in the uri, matching the regular: ``^[a-z0-9-.]+$`` . + /// Which is required to conform to the scheme specification in the uri, matching the regular: ``^[a-z0-9-.]+$`` . /// - /// 资源类型编码,需要符合uri中的scheme规范,匹配正则:``^[a-z0-9-.]+$`` 。 + /// 需要符合uri中的scheme规范,匹配正则:``^[a-z0-9-.]+$`` 。 #[index(unique)] pub code: String, /// Resource kind name diff --git a/backend/basic/src/rbum/dto/rbum_item_attr_dto.rs b/backend/basic/src/rbum/dto/rbum_item_attr_dto.rs index ed3e1677a..8510bea3a 100644 --- a/backend/basic/src/rbum/dto/rbum_item_attr_dto.rs +++ b/backend/basic/src/rbum/dto/rbum_item_attr_dto.rs @@ -7,42 +7,88 @@ use tardis::db::sea_orm; #[cfg(feature = "default")] use tardis::web::poem_openapi; +/// Add request for resource item extended attribute value +/// +/// 资源项扩展属性值添加请求 #[derive(Serialize, Deserialize, Debug)] #[cfg_attr(feature = "default", derive(poem_openapi::Object))] pub struct RbumItemAttrAddReq { + /// Extended attribute value + /// + /// 扩展属性值 #[cfg_attr(feature = "default", oai(validator(min_length = "1", max_length = "2000")))] pub value: String, - + /// Associated [resource item](crate::rbum::dto::rbum_item_dto::RbumItemDetailResp) id + /// + /// 关联的[资源项](crate::rbum::dto::rbum_item_dto::RbumItemDetailResp) id #[cfg_attr(feature = "default", oai(validator(min_length = "2", max_length = "255")))] pub rel_rbum_item_id: String, + /// Associated [resource kind attribute definition](crate::rbum::dto::rbum_kind_attr_dto::RbumKindAttrDetailResp) id + /// + /// 关联的[资源类型属性定义](crate::rbum::dto::rbum_kind_attr_dto::RbumKindAttrDetailResp) id #[cfg_attr(feature = "default", oai(validator(min_length = "2", max_length = "255")))] pub rel_rbum_kind_attr_id: String, } +/// Modify request for resource item extended attribute value +/// +/// 资源项扩展属性值修改请求 #[derive(Serialize, Deserialize, Debug)] #[cfg_attr(feature = "default", derive(poem_openapi::Object))] -pub struct RbumItemAttrsAddOrModifyReq { - // name -> value - pub values: HashMap, - - #[cfg_attr(feature = "default", oai(validator(min_length = "2", max_length = "255")))] - pub rel_rbum_item_id: String, +pub struct RbumItemAttrModifyReq { + /// Extended attribute value + /// + /// 扩展属性值 + #[cfg_attr(feature = "default", oai(validator(min_length = "1", max_length = "2000")))] + pub value: String, } +/// Batch add or modify request for resource item extended attribute values +/// +/// 批量添加或修改资源项扩展属性值请求 #[derive(Serialize, Deserialize, Debug)] #[cfg_attr(feature = "default", derive(poem_openapi::Object))] -pub struct RbumItemAttrModifyReq { - #[cfg_attr(feature = "default", oai(validator(min_length = "1", max_length = "2000")))] - pub value: String, +pub struct RbumItemAttrsAddOrModifyReq { + /// Add or modify value collection + /// + /// 添加或修改的值集合 + /// + /// Format: ``{ "field name": "field value" }`` + /// + /// ``field name``: [`crate::rbum::dto::rbum_kind_attr_dto::RbumKindAttrDetailResp::name`] + pub values: HashMap, + /// Associated [resource item](crate::rbum::dto::rbum_item_dto::RbumItemDetailResp) id + /// + /// 关联的[资源项](crate::rbum::dto::rbum_item_dto::RbumItemDetailResp) id + #[cfg_attr(feature = "default", oai(validator(min_length = "2", max_length = "255")))] + pub rel_rbum_item_id: String, } +/// Resource item extended attribute value summary information +/// +/// 源项扩展属性值概要信息 #[derive(Serialize, Deserialize, Debug)] #[cfg_attr(feature = "default", derive(poem_openapi::Object, sea_orm::FromQueryResult))] pub struct RbumItemAttrSummaryResp { + /// Extended attribute value id + /// + /// 扩展属性值id pub id: String, + /// Extended attribute value + /// + /// 扩展属性值 pub value: String, + /// Associated [resource item](crate::rbum::dto::rbum_item_dto::RbumItemDetailResp) id + /// + /// 关联的[资源项](crate::rbum::dto::rbum_item_dto::RbumItemDetailResp) id pub rel_rbum_item_id: String, + /// Associated [resource kind attribute definition](crate::rbum::dto::rbum_kind_attr_dto::RbumKindAttrDetailResp) id + /// + /// 关联的[资源类型属性定义](crate::rbum::dto::rbum_kind_attr_dto::RbumKindAttrDetailResp) id pub rel_rbum_kind_attr_id: String, + /// Associated [resource kind attribute definition](crate::rbum::dto::rbum_kind_attr_dto::RbumKindAttrDetailResp) name + /// + /// 关联的[资源类型属性定义](crate::rbum::dto::rbum_kind_attr_dto::RbumKindAttrDetailResp) 名称 pub rel_rbum_kind_attr_name: String, pub own_paths: String, @@ -51,13 +97,31 @@ pub struct RbumItemAttrSummaryResp { pub update_time: DateTime, } +/// Resource item extended attribute value detail information +/// +/// 源项扩展属性值详细信息 #[derive(Serialize, Deserialize, Debug)] #[cfg_attr(feature = "default", derive(poem_openapi::Object, sea_orm::FromQueryResult))] pub struct RbumItemAttrDetailResp { + /// Extended attribute value id + /// + /// 扩展属性值id pub id: String, + /// Extended attribute value + /// + /// 扩展属性值 pub value: String, + /// Associated [resource item](crate::rbum::dto::rbum_item_dto::RbumItemDetailResp) id + /// + /// 关联的[资源项](crate::rbum::dto::rbum_item_dto::RbumItemDetailResp) id pub rel_rbum_item_id: String, + /// Associated [resource kind attribute definition](crate::rbum::dto::rbum_kind_attr_dto::RbumKindAttrDetailResp) id + /// + /// 关联的[资源类型属性定义](crate::rbum::dto::rbum_kind_attr_dto::RbumKindAttrDetailResp) id pub rel_rbum_kind_attr_id: String, + /// Associated [resource kind attribute definition](crate::rbum::dto::rbum_kind_attr_dto::RbumKindAttrDetailResp) name + /// + /// 关联的[资源类型属性定义](crate::rbum::dto::rbum_kind_attr_dto::RbumKindAttrDetailResp) 名称 pub rel_rbum_kind_attr_name: String, pub own_paths: String, diff --git a/backend/basic/src/rbum/dto/rbum_item_dto.rs b/backend/basic/src/rbum/dto/rbum_item_dto.rs index ee1d4f537..b40963756 100644 --- a/backend/basic/src/rbum/dto/rbum_item_dto.rs +++ b/backend/basic/src/rbum/dto/rbum_item_dto.rs @@ -8,18 +8,35 @@ use tardis::web::poem_openapi; use crate::rbum::rbum_enumeration::RbumScopeLevelKind; +/// Add request for resource item +/// +/// 资源项添加请求 #[derive(Serialize, Deserialize, Debug)] #[cfg_attr(feature = "default", derive(poem_openapi::Object))] pub struct RbumItemAddReq { + /// Resource item id + /// + /// 资源项id #[cfg_attr(feature = "default", oai(validator(min_length = "2", max_length = "255")))] pub id: Option, + /// Resource item code + /// + /// 资源项编码 #[cfg_attr(feature = "default", oai(validator(min_length = "2", max_length = "255")))] pub code: Option, + /// Resource item name + /// + /// 资源项名称 #[cfg_attr(feature = "default", oai(validator(min_length = "2", max_length = "255")))] pub name: TrimString, - + /// Associated [resource kind](crate::rbum::dto::rbum_kind_dto::RbumKindDetailResp) id + /// + /// 关联的[资源类型](crate::rbum::dto::rbum_kind_dto::RbumKindDetailResp) id #[cfg_attr(feature = "default", oai(validator(min_length = "2", max_length = "255")))] pub rel_rbum_kind_id: String, + /// Associated [resource domain](crate::rbum::dto::rbum_domain_dto::RbumDomainDetailResp) id + /// + /// 关联的[资源域](crate::rbum::dto::rbum_domain_dto::RbumDomainDetailResp) id #[cfg_attr(feature = "default", oai(validator(min_length = "2", max_length = "255")))] pub rel_rbum_domain_id: String, @@ -40,18 +57,48 @@ impl Default for RbumItemAddReq { } } } -/// For security reasons, this object cannot be used as an input to the API +/// Add request for resource item kernel +/// +/// 资源项内核添加请求 +/// +/// Different from [`crate::rbum::dto::rbum_item_dto::RbumItemAddReq`], this object is used when there is a resource item extension table, +/// and the resource item contains kernel information (the ``rbum_item`` table) and extension information (the corresponding extension table). +/// +/// 与 [`crate::rbum::dto::rbum_item_dto::RbumItemAddReq`] 不同,此对象用于有资源项扩展表的情况下使用,此时资源项包含了内核信息(``rbum_item``表)和扩展信息(对应的扩展表)。 #[derive(Serialize, Deserialize, Debug)] #[serde(default)] pub struct RbumItemKernelAddReq { + /// Resource item id + /// + /// 资源项id pub id: Option, + /// Resource item code + /// + /// 资源项编码 pub code: Option, + /// Resource item name + /// + /// 资源项名称 pub name: TrimString, - // Special kind can be set, otherwise the default kind will be used. - // Note that setting special kind must ensure that the permissions are correct. + /// Associated [resource kind](crate::rbum::dto::rbum_kind_dto::RbumKindDetailResp) id + /// + /// 关联的[资源类型](crate::rbum::dto::rbum_kind_dto::RbumKindDetailResp) id + /// + /// Special kind can be set, otherwise the default kind will be used. + /// Note that setting special kind must ensure that the permissions are correct. + /// + /// 可以设置特殊的类型,否则将使用默认类型。 + /// 注意设置特殊类型必须确保权限正确。 pub rel_rbum_kind_id: Option, - // Special domain can be set, otherwise the default domain will be used. - // Note that setting special domain must ensure that the permissions are correct. + /// Associated [resource domain](crate::rbum::dto::rbum_domain_dto::RbumDomainDetailResp) id + /// + /// 关联的[资源域](crate::rbum::dto::rbum_domain_dto::RbumDomainDetailResp) id + /// + /// Special domain can be set, otherwise the default domain will be used. + /// Note that setting special domain must ensure that the permissions are correct. + /// + /// 可以设置特殊的域,否则将使用默认域。 + /// 注意设置特殊域必须确保权限正确。 pub rel_rbum_domain_id: Option, pub scope_level: Option, pub disabled: Option, @@ -71,23 +118,49 @@ impl Default for RbumItemKernelAddReq { } } -/// For security reasons, this object cannot be used as an input to the API +/// Modify request for resource item kernel +/// +/// 资源项内核修改请求 #[derive(Serialize, Deserialize, Debug, Default)] #[serde(default)] pub struct RbumItemKernelModifyReq { + /// Resource item code + /// + /// 资源项编码 pub code: Option, + /// Resource item name + /// + /// 资源项名称 pub name: Option, pub scope_level: Option, pub disabled: Option, } +/// Resource item summary information +/// +/// 资源项概要信息 #[derive(Serialize, Deserialize, Debug)] #[cfg_attr(feature = "default", derive(poem_openapi::Object, sea_orm::FromQueryResult))] pub struct RbumItemSummaryResp { + /// Resource item id + /// + /// 资源项id pub id: String, + /// Resource item code + /// + /// 资源项编码 pub code: String, + /// Resource item name + /// + /// 资源项名称 pub name: String, + /// Associated [resource kind](crate::rbum::dto::rbum_kind_dto::RbumKindDetailResp) id + /// + /// 关联的[资源类型](crate::rbum::dto::rbum_kind_dto::RbumKindDetailResp) id pub rel_rbum_kind_id: String, + /// Associated [resource domain](crate::rbum::dto::rbum_domain_dto::RbumDomainDetailResp) id + /// + /// 关联的[资源域](crate::rbum::dto::rbum_domain_dto::RbumDomainDetailResp) id pub rel_rbum_domain_id: String, pub own_paths: String, @@ -99,15 +172,39 @@ pub struct RbumItemSummaryResp { pub disabled: bool, } +/// Resource item detail information +/// +/// 资源项详细信息 #[derive(Serialize, Deserialize, Debug)] #[cfg_attr(feature = "default", derive(poem_openapi::Object, sea_orm::FromQueryResult))] pub struct RbumItemDetailResp { + /// Resource item id + /// + /// 资源项id pub id: String, + /// Resource item code + /// + /// 资源项编码 pub code: String, + /// Resource item name + /// + /// 资源项名称 pub name: String, + /// Associated [resource kind](crate::rbum::dto::rbum_kind_dto::RbumKindDetailResp) id + /// + /// 关联的[资源类型](crate::rbum::dto::rbum_kind_dto::RbumKindDetailResp) id pub rel_rbum_kind_id: String, + /// Associated [resource kind](crate::rbum::dto::rbum_kind_dto::RbumKindDetailResp) name + /// + /// 关联的[资源类型](crate::rbum::dto::rbum_kind_dto::RbumKindDetailResp) 名称 pub rel_rbum_kind_name: String, + /// Associated [resource domain](crate::rbum::dto::rbum_domain_dto::RbumDomainDetailResp) id + /// + /// 关联的[资源域](crate::rbum::dto::rbum_domain_dto::RbumDomainDetailResp) id pub rel_rbum_domain_id: String, + /// Associated [resource domain](crate::rbum::dto::rbum_domain_dto::RbumDomainDetailResp) name + /// + /// 关联的[资源域](crate::rbum::dto::rbum_domain_dto::RbumDomainDetailResp) 名称 pub rel_rbum_domain_name: String, pub own_paths: String, diff --git a/backend/basic/src/rbum/serv/rbum_item_serv.rs b/backend/basic/src/rbum/serv/rbum_item_serv.rs index 3b4e74bd0..b111465fa 100644 --- a/backend/basic/src/rbum/serv/rbum_item_serv.rs +++ b/backend/basic/src/rbum/serv/rbum_item_serv.rs @@ -48,6 +48,12 @@ impl RbumCrudOperation TardisResult<()> { + Self::check_scope(&add_req.rel_rbum_kind_id, RbumKindServ::get_table_name(), funs, ctx).await?; + Self::check_scope(&add_req.rel_rbum_domain_id, RbumDomainServ::get_table_name(), funs, ctx).await?; + Ok(()) + } + async fn package_add(add_req: &RbumItemAddReq, funs: &TardisFunsInst, _: &TardisContext) -> TardisResult { let id = if let Some(id) = &add_req.id { id.to_string() } else { TardisFuns::field.nanoid() }; let code = if let Some(code) = &add_req.code { @@ -88,12 +94,6 @@ impl RbumCrudOperation TardisResult<()> { - Self::check_scope(&add_req.rel_rbum_kind_id, RbumKindServ::get_table_name(), funs, ctx).await?; - Self::check_scope(&add_req.rel_rbum_domain_id, RbumDomainServ::get_table_name(), funs, ctx).await?; - Ok(()) - } - async fn package_modify(id: &str, modify_req: &RbumItemKernelModifyReq, funs: &TardisFunsInst, _: &TardisContext) -> TardisResult { let mut rbum_item = rbum_item::ActiveModel { id: Set(id.to_string()), @@ -141,9 +141,13 @@ impl RbumCrudOperation where @@ -204,20 +214,35 @@ where DetailResp: FromQueryResult + ParseFromJSON + ToJSON + Serialize + Send + Sync, ItemFilterReq: Sync + Send + RbumItemFilterFetcher, { + /// Get the name of the extended table + /// + /// 获取扩展表的名称 fn get_ext_table_name() -> &'static str; + /// Get the name of the extended object + /// + /// 获取扩展对象的名称 + /// + /// Mostly used for printing log identifiers. + /// + /// 多用于打印日志的标识。 fn get_obj_name() -> String { Self::get_ext_table_name().to_string() } - /// Get default kind + /// Get default resource kind + /// + /// 获取默认的资源类型 fn get_rbum_kind_id() -> Option; - /// Get default domain + /// Get default resource domain + /// + /// 获取默认的资源域 fn get_rbum_domain_id() -> Option; // ----------------------------- Add ------------------------------- + async fn package_item_add(add_req: &AddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult; async fn package_ext_add(id: &str, add_req: &AddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult; @@ -334,7 +359,7 @@ where // ----------------------------- Delete ------------------------------- async fn package_delete(id: &str, _funs: &TardisFunsInst, _ctx: &TardisContext) -> TardisResult> { - Ok(EXT::Entity::find().filter(Expr::col(ID_FIELD.clone()).eq(id))) + Ok(::find().filter(Expr::col(ID_FIELD.clone()).eq(id))) } async fn before_delete_item(_: &str, _: &TardisFunsInst, _: &TardisContext) -> TardisResult> { @@ -496,7 +521,7 @@ where filter.basic().rbum_domain_id.clone() } else { Self::get_rbum_domain_id() - } + }, }, funs, ctx, diff --git a/backend/basic/src/rbum/serv/rbum_rel_serv.rs b/backend/basic/src/rbum/serv/rbum_rel_serv.rs index a2ec688ac..850bfc680 100644 --- a/backend/basic/src/rbum/serv/rbum_rel_serv.rs +++ b/backend/basic/src/rbum/serv/rbum_rel_serv.rs @@ -1421,17 +1421,3 @@ impl RbumCrudOperation Result<()> { - // std::env::set_var("OUT_DIR", "tests/grpc/rust"); + // std::env::set_var("OUT_DIR", "./src/api/nacos/grpc"); let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); let proto_dir = format!("{}/proto", manifest_dir); poem_grpc_build::Config::new() diff --git a/backend/spi/spi-conf/src/api/ci/conf_auth.rs b/backend/spi/spi-conf/src/api/ci/conf_auth.rs index 230bab99c..244512d36 100644 --- a/backend/spi/spi-conf/src/api/ci/conf_auth.rs +++ b/backend/spi/spi-conf/src/api/ci/conf_auth.rs @@ -76,7 +76,7 @@ impl ConfCiAuthApi { &default_ctx, ) .await? - .ok_or_else(|| funs.err().not_found(&SpiBsServ::get_obj_name(), "register", "not found spi-conf domain", "404-spi-bs-not-exist"))?; + .ok_or_else(|| funs.err().not_found(&SpiBsServ::get_obj_name(), "register_bundle", "not found spi-conf domain", "404-spi-bs-not-exist"))?; let bs = RbumItemServ::find_one_rbum( &RbumBasicFilterReq { enabled: Some(true), @@ -87,7 +87,7 @@ impl ConfCiAuthApi { &default_ctx, ) .await? - .ok_or_else(|| funs.err().not_found(&SpiBsServ::get_obj_name(), "register", "not found backend service", "404-spi-bs-not-exist"))?; + .ok_or_else(|| funs.err().not_found(&SpiBsServ::get_obj_name(), "register_bundle", "not found backend service", "404-spi-bs-not-exist"))?; bs.id } BackendServiceSource::New { name } => { @@ -96,7 +96,7 @@ impl ConfCiAuthApi { let kind_code = spi_constants::SPI_PG_KIND_CODE.to_string(); let kind_id = RbumKindServ::get_rbum_kind_id_by_code(&kind_code, &funs) .await? - .ok_or_else(|| funs.err().not_found(&SpiBsServ::get_obj_name(), "register", "db spi kind not found", "404-spi-bs-not-exist"))?; + .ok_or_else(|| funs.err().not_found(&SpiBsServ::get_obj_name(), "register_bundle", "db spi kind not found", "404-spi-bs-not-exist"))?; let conn_uri = tardis::TardisFuns::fw_config().db().default.url.clone(); let mut req = SpiBsAddReq { name: name.unwrap_or(format!("spi-conf-{}", tardis::crypto::crypto_key::TardisCryptoKey.rand_8_hex())).into(), diff --git a/backend/spi/spi-conf/src/api/nacos/grpc/mod.rs b/backend/spi/spi-conf/src/api/nacos/grpc/mod.rs index f2a89c6d4..7dd845e67 100644 --- a/backend/spi/spi-conf/src/api/nacos/grpc/mod.rs +++ b/backend/spi/spi-conf/src/api/nacos/grpc/mod.rs @@ -5,7 +5,6 @@ use tardis::{ basic::{error::TardisError, result::TardisResult}, futures_util::StreamExt, log, serde_json, - web::poem, }; #[allow(non_snake_case)] mod proto; @@ -22,7 +21,6 @@ use crate::{ #[derive(Clone, Default)] pub struct RequestProtoImpl; -#[poem::async_trait] impl RequestProto for RequestProtoImpl { async fn request(&self, request: Request) -> Result, Status> { let Some(metadata) = &request.metadata else { @@ -47,7 +45,6 @@ impl RequestProto for RequestProtoImpl { #[derive(Clone, Default)] pub struct BiRequestStreamProtoImpl; -#[poem::async_trait] impl BiRequestStreamProto for BiRequestStreamProtoImpl { async fn request_bi_stream(&self, mut request_stream: Request>) -> Result>, Status> { let (mut _tx, rx) = tardis::tokio::sync::mpsc::unbounded_channel::>(); diff --git a/backend/spi/spi-conf/src/api/nacos/grpc/proto.rs b/backend/spi/spi-conf/src/api/nacos/grpc/proto.rs index 193d8c7cf..298cadde8 100644 --- a/backend/spi/spi-conf/src/api/nacos/grpc/proto.rs +++ b/backend/spi/spi-conf/src/api/nacos/grpc/proto.rs @@ -1,9 +1,5 @@ -/*************************************************************************************** - THIS FILE IS MOSTLY GENERATED BY POEM-GRPC, DO NOT EDIT MANUALLY. -****************************************************************************************/ - -use tardis::web::poem; -use tardis::web::poem_grpc; +use tardis::web::{poem_grpc, poem}; +// This file is @generated by prost-build. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Metadata { @@ -12,7 +8,10 @@ pub struct Metadata { #[prost(string, tag = "8")] pub client_ip: ::prost::alloc::string::String, #[prost(map = "string, string", tag = "7")] - pub headers: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, + pub headers: ::std::collections::HashMap< + ::prost::alloc::string::String, + ::prost::alloc::string::String, + >, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -35,15 +34,19 @@ pub struct ConfigQueryRequest { pub tag: ::prost::alloc::string::String, } #[allow(unused_imports)] -#[poem::async_trait] pub trait Request: Send + Sync + 'static { - async fn request(&self, request: poem_grpc::Request) -> ::std::result::Result, poem_grpc::Status>; + fn request( + &self, + request: poem_grpc::Request, + ) -> impl ::std::future::Future< + Output = ::std::result::Result, poem_grpc::Status>, + > + Send; } #[allow(unused_imports)] #[derive(Clone)] pub struct RequestServer(::std::sync::Arc); impl poem_grpc::Service for RequestServer { - const NAME: &'static str = "Request"; + const NAME: &'static str = ".Request"; } #[allow(dead_code)] impl RequestServer { @@ -60,48 +63,66 @@ impl poem::IntoEndpoint for RequestServer { let mut route = poem::Route::new(); #[allow(non_camel_case_types)] struct RequestrequestService(::std::sync::Arc); - #[poem::async_trait] - impl poem_grpc::service::UnaryService for RequestrequestService { + impl poem_grpc::service::UnaryService + for RequestrequestService { type Response = Payload; - async fn call(&self, request: poem_grpc::Request) -> Result, poem_grpc::Status> { + async fn call( + &self, + request: poem_grpc::Request, + ) -> Result, poem_grpc::Status> { self.0.request(request).await } } - route = route.at( - "/request", - poem::endpoint::make({ - let svc = self.0.clone(); - move |req| { - let svc = svc.clone(); - async move { - let codec = as ::std::default::Default>::default(); - poem_grpc::server::GrpcServer::new(codec).unary(RequestrequestService(svc.clone()), req).await + route = route + .at( + "/request", + poem::endpoint::make({ + let svc = self.0.clone(); + move |req| { + let svc = svc.clone(); + async move { + let codec = as ::std::default::Default>::default(); + poem_grpc::server::GrpcServer::new(codec) + .unary(RequestrequestService(svc.clone()), req) + .await + } } + }), + ); + let ep = route + .before(|req| async move { + if req.version() != poem::http::Version::HTTP_2 { + return Err( + poem::Error::from_status( + poem::http::StatusCode::HTTP_VERSION_NOT_SUPPORTED, + ), + ); } - }), - ); - let ep = route.before(|req| async move { - if req.version() != poem::http::Version::HTTP_2 { - return Err(poem::Error::from_status(poem::http::StatusCode::HTTP_VERSION_NOT_SUPPORTED)); - } - Ok(req) - }); + Ok(req) + }); ep.boxed() } } #[allow(unused_imports)] -#[poem::async_trait] pub trait BiRequestStream: Send + Sync + 'static { - async fn request_bi_stream( + fn request_bi_stream( &self, request: poem_grpc::Request>, - ) -> ::std::result::Result>, poem_grpc::Status>; + ) -> impl ::std::future::Future< + Output = ::std::result::Result< + poem_grpc::Response>, + poem_grpc::Status, + >, + > + Send; } #[allow(unused_imports)] #[derive(Clone)] pub struct BiRequestStreamServer(::std::sync::Arc); impl poem_grpc::Service for BiRequestStreamServer { - const NAME: &'static str = "BiRequestStream"; + const NAME: &'static str = ".BiRequestStream"; } #[allow(dead_code)] impl BiRequestStreamServer { @@ -118,35 +139,54 @@ impl poem::IntoEndpoint for BiRequestStreamServer { let mut route = poem::Route::new(); #[allow(non_camel_case_types)] struct BiRequestStreamrequest_bi_streamService(::std::sync::Arc); - #[poem::async_trait] - impl poem_grpc::service::BidirectionalStreamingService for BiRequestStreamrequest_bi_streamService { + impl< + T: BiRequestStream, + > poem_grpc::service::BidirectionalStreamingService + for BiRequestStreamrequest_bi_streamService { type Response = Payload; async fn call( &self, request: poem_grpc::Request>, - ) -> Result>, poem_grpc::Status> { + ) -> Result< + poem_grpc::Response>, + poem_grpc::Status, + > { self.0.request_bi_stream(request).await } } - route = route.at( - "/requestBiStream", - poem::endpoint::make({ - let svc = self.0.clone(); - move |req| { - let svc = svc.clone(); - async move { - let codec = as ::std::default::Default>::default(); - poem_grpc::server::GrpcServer::new(codec).bidirectional_streaming(BiRequestStreamrequest_bi_streamService(svc.clone()), req).await + route = route + .at( + "/requestBiStream", + poem::endpoint::make({ + let svc = self.0.clone(); + move |req| { + let svc = svc.clone(); + async move { + let codec = as ::std::default::Default>::default(); + poem_grpc::server::GrpcServer::new(codec) + .bidirectional_streaming( + BiRequestStreamrequest_bi_streamService(svc.clone()), + req, + ) + .await + } } + }), + ); + let ep = route + .before(|req| async move { + if req.version() != poem::http::Version::HTTP_2 { + return Err( + poem::Error::from_status( + poem::http::StatusCode::HTTP_VERSION_NOT_SUPPORTED, + ), + ); } - }), - ); - let ep = route.before(|req| async move { - if req.version() != poem::http::Version::HTTP_2 { - return Err(poem::Error::from_status(poem::http::StatusCode::HTTP_VERSION_NOT_SUPPORTED)); - } - Ok(req) - }); + Ok(req) + }); ep.boxed() } } diff --git a/backend/spi/spi-conf/src/serv/pg/conf_pg_config_serv.rs b/backend/spi/spi-conf/src/serv/pg/conf_pg_config_serv.rs index fbebf3618..2c279efbe 100644 --- a/backend/spi/spi-conf/src/serv/pg/conf_pg_config_serv.rs +++ b/backend/spi/spi-conf/src/serv/pg/conf_pg_config_serv.rs @@ -13,6 +13,7 @@ use tardis::{ Value, }, }, + log::warn, tokio::{sync::RwLock, time::Instant}, TardisFunsInst, }; @@ -39,8 +40,31 @@ fn md5(content: &str) -> String { use tardis::crypto::crypto_digest::TardisCryptoDigest; TardisCryptoDigest.md5(content).expect("md5 digest shouldn't fail") } - +pub async fn fix_md5(descriptor: &ConfigDescriptor, md5: &str, ctx: &TardisContext, bs_inst: &SpiBsInst) -> TardisResult<()> { + let data_id = &descriptor.data_id; + let group = &descriptor.group; + let namespace = &descriptor.namespace_id; + let typed_inst = bs_inst.inst::(); + let conns = conf_pg_initializer::init_table_and_conn(typed_inst, ctx, true).await?; + let (conn, table_name) = conns.config; + let fields_and_values = vec![("md5", Value::from(md5))]; + let key_params = vec![("data_id", Value::from(data_id)), ("grp", Value::from(group)), ("namespace_id", Value::from(namespace))]; + let (fields, placeholders, values) = super::gen_update_sql_stmt(fields_and_values, key_params); + conn + .execute_one( + &format!( + r#"UPDATE {table_name} +SET {fields} +WHERE {placeholders}"#, + ), + values, + ) + .await?; + MD5_CACHE.write().await.insert(descriptor.clone(), (md5.to_string(), Instant::now())); + Ok(()) +} pub async fn get_config(descriptor: &mut ConfigDescriptor, _funs: &TardisFunsInst, ctx: &TardisContext, bs_inst: &SpiBsInst) -> TardisResult { + use md5 as gen_md5; descriptor.fix_namespace_id(); let data_id = &descriptor.data_id; let group = &descriptor.group; @@ -51,7 +75,7 @@ pub async fn get_config(descriptor: &mut ConfigDescriptor, _funs: &TardisFunsIns let qry_result = conn .query_one( &format!( - r#"SELECT (content) FROM {table_name} cc + r#"SELECT (content, md5) FROM {table_name} cc WHERE cc.namespace_id=$1 AND cc.grp=$2 AND cc.data_id=$3 "#, ), @@ -60,10 +84,20 @@ WHERE cc.namespace_id=$1 AND cc.grp=$2 AND cc.data_id=$3 .await? .ok_or_else(|| TardisError::not_found("config not found", error::NAMESPACE_NOTFOUND))?; let content = qry_result.try_get::("", "content")?; + let md5 = qry_result.try_get::("", "md5")?; + // fix md5 automatically + let real_md5 = gen_md5(&content); + if md5 != real_md5 { + let update_result = fix_md5(descriptor, &real_md5, ctx, bs_inst).await; + if let Err(e) = update_result { + warn!("[Bios.spi-conf] update md5 failed: {}", e); + } + } Ok(content) } pub async fn get_config_detail(descriptor: &mut ConfigDescriptor, _funs: &TardisFunsInst, ctx: &TardisContext, bs_inst: &SpiBsInst) -> TardisResult { + use md5 as gen_md5; descriptor.fix_namespace_id(); let data_id = &descriptor.data_id; let group = &descriptor.group; @@ -98,12 +132,20 @@ WHERE c.namespace_id=$1 AND c.grp=$2 AND c.data_id=$3"#, tags: Option, }); let config_tags = tags.map(|tags| tags.split(',').filter(|s| !s.is_empty()).map(String::from).collect()).unwrap_or_default(); + // fix md5 automatically + let real_md5 = gen_md5(&content); + if md5 != real_md5 { + let update_result = fix_md5(descriptor, &real_md5, ctx, bs_inst).await; + if let Err(e) = update_result { + warn!("[Bios.spi-conf] update md5 failed: {}", e); + } + } Ok(ConfigItem { data_id: data_id.clone(), namespace: namespace.clone(), group: group.clone(), id: id.to_string(), - md5, + md5: real_md5, content, created_time, last_modified_time: modified_time, diff --git a/backend/spi/spi-conf/tests/config/conf-default.toml b/backend/spi/spi-conf/tests/config/conf-default.toml index 2bcff1682..286cc2821 100644 --- a/backend/spi/spi-conf/tests/config/conf-default.toml +++ b/backend/spi/spi-conf/tests/config/conf-default.toml @@ -65,4 +65,4 @@ uniform_error = false [fw.web_server.modules.spi-conf-nacos] [fw.log] -level = "info" +level = "debug" diff --git a/backend/spi/spi-conf/tests/spi_conf_api_test.rs b/backend/spi/spi-conf/tests/spi_conf_api_test.rs index d98752dd3..060ba3c38 100644 --- a/backend/spi/spi-conf/tests/spi_conf_api_test.rs +++ b/backend/spi/spi-conf/tests/spi_conf_api_test.rs @@ -36,8 +36,10 @@ async fn spi_conf_namespace_test() -> TardisResult<()> { groups: vec![], owner: "app001".to_string(), ..Default::default() + })?; let funs = TardisFuns::inst_with_db_conn(DOMAIN_CODE.to_string(), None); + std::io::stdin().read_line(&mut String::default()).expect("fail to read"); let RegisterResponse { username, password } = client .put( "/ci/auth/register_bundle", @@ -48,7 +50,6 @@ async fn spi_conf_namespace_test() -> TardisResult<()> { "type": "new", "value": { "name": "spi-nacos-app01", - "conn_uri": env::var("TARDIS_FW.DB.URL").unwrap(), } } }),