refactor(app): add iam and notify interface boundaries (#1948)

This commit is contained in:
安正超
2026-02-25 09:49:02 +08:00
committed by GitHub
parent b48f273c7d
commit 0d9e5f1e93
4 changed files with 88 additions and 13 deletions
+9 -5
View File
@@ -271,14 +271,18 @@ impl DefaultAdminUsecase {
} }
pub fn execute_collect_dependency_readiness(&self) -> DependencyReadiness { pub fn execute_collect_dependency_readiness(&self) -> DependencyReadiness {
if let Some(context) = &self.context { let iam_ready = self
let _ = context.object_store(); .context
let _ = context.iam(); .as_ref()
} .map(|context| {
let _ = context.object_store();
context.iam().is_ready()
})
.unwrap_or(false);
DependencyReadiness { DependencyReadiness {
storage_ready: new_object_layer_fn().is_some(), storage_ready: new_object_layer_fn().is_some(),
iam_ready: rustfs_iam::get().is_ok(), iam_ready,
} }
} }
} }
+9 -4
View File
@@ -15,7 +15,7 @@
//! Bucket application use-case contracts. //! Bucket application use-case contracts.
#![allow(dead_code)] #![allow(dead_code)]
use crate::app::context::{AppContext, get_global_app_context}; use crate::app::context::{AppContext, default_notify_interface, get_global_app_context};
use crate::auth::get_condition_values; use crate::auth::get_condition_values;
use crate::error::ApiError; use crate::error::ApiError;
use crate::server::RemoteAddr; use crate::server::RemoteAddr;
@@ -46,7 +46,6 @@ use rustfs_ecstore::client::object_api_utils::to_s3s_etag;
use rustfs_ecstore::error::StorageError; use rustfs_ecstore::error::StorageError;
use rustfs_ecstore::new_object_layer_fn; use rustfs_ecstore::new_object_layer_fn;
use rustfs_ecstore::store_api::{BucketOptions, DeleteBucketOptions, MakeBucketOptions, StorageAPI}; use rustfs_ecstore::store_api::{BucketOptions, DeleteBucketOptions, MakeBucketOptions, StorageAPI};
use rustfs_notify::notifier_global;
use rustfs_policy::policy::{ use rustfs_policy::policy::{
action::{Action, S3Action}, action::{Action, S3Action},
{BucketPolicy, BucketPolicyArgs, Effect, Validator}, {BucketPolicy, BucketPolicyArgs, Effect, Validator},
@@ -1189,7 +1188,12 @@ impl DefaultBucketUsecase {
.map_err(ApiError::from)?; .map_err(ApiError::from)?;
let region = resolve_notification_region(rustfs_ecstore::global::get_global_region(), request_region); let region = resolve_notification_region(rustfs_ecstore::global::get_global_region(), request_region);
let clear_rules = notifier_global::clear_bucket_notification_rules(&bucket); let notify = self
.context
.as_ref()
.map(|context| context.notify())
.unwrap_or_else(default_notify_interface);
let clear_rules = notify.clear_bucket_notification_rules(&bucket);
let parse_rules = async { let parse_rules = async {
let mut event_rules = Vec::new(); let mut event_rules = Vec::new();
@@ -1223,7 +1227,8 @@ impl DefaultBucketUsecase {
event_rules_result.map_err(|e| s3_error!(InvalidArgument, "Invalid ARN in notification configuration: {e}"))?; event_rules_result.map_err(|e| s3_error!(InvalidArgument, "Invalid ARN in notification configuration: {e}"))?;
warn!("notify event rules: {:?}", &event_rules); warn!("notify event rules: {:?}", &event_rules);
notifier_global::add_event_specific_rules(&bucket, &region, &event_rules) notify
.add_event_specific_rules(&bucket, &region, &event_rules)
.await .await
.map_err(|e| s3_error!(InternalError, "Failed to add rules: {e}"))?; .map_err(|e| s3_error!(InternalError, "Failed to add rules: {e}"))?;
+62 -1
View File
@@ -17,14 +17,18 @@
//! for storage, IAM, and KMS handles. //! for storage, IAM, and KMS handles.
#![allow(dead_code)] #![allow(dead_code)]
use async_trait::async_trait;
use rustfs_ecstore::store::ECStore; use rustfs_ecstore::store::ECStore;
use rustfs_iam::{store::object::ObjectStore, sys::IamSys}; use rustfs_iam::{store::object::ObjectStore, sys::IamSys};
use rustfs_kms::KmsServiceManager; use rustfs_kms::KmsServiceManager;
use rustfs_notify::{EventArgs, NotificationError, notifier_global};
use rustfs_targets::{EventName, arn::TargetID};
use std::sync::{Arc, OnceLock}; use std::sync::{Arc, OnceLock};
/// IAM interface for application-layer use-cases. /// IAM interface for application-layer use-cases.
pub trait IamInterface: Send + Sync { pub trait IamInterface: Send + Sync {
fn handle(&self) -> Arc<IamSys<ObjectStore>>; fn handle(&self) -> Arc<IamSys<ObjectStore>>;
fn is_ready(&self) -> bool;
} }
/// KMS interface for application-layer use-cases. /// KMS interface for application-layer use-cases.
@@ -32,6 +36,21 @@ pub trait KmsInterface: Send + Sync {
fn handle(&self) -> Arc<KmsServiceManager>; fn handle(&self) -> Arc<KmsServiceManager>;
} }
/// Notify interface for application-layer use-cases.
#[async_trait]
pub trait NotifyInterface: Send + Sync {
async fn notify(&self, args: EventArgs);
async fn add_event_specific_rules(
&self,
bucket_name: &str,
region: &str,
event_rules: &[(Vec<EventName>, String, String, Vec<TargetID>)],
) -> Result<(), NotificationError>;
async fn clear_bucket_notification_rules(&self, bucket_name: &str) -> Result<(), NotificationError>;
}
/// Default IAM interface adapter. /// Default IAM interface adapter.
pub struct IamHandle { pub struct IamHandle {
iam: Arc<IamSys<ObjectStore>>, iam: Arc<IamSys<ObjectStore>>,
@@ -47,6 +66,10 @@ impl IamInterface for IamHandle {
fn handle(&self) -> Arc<IamSys<ObjectStore>> { fn handle(&self) -> Arc<IamSys<ObjectStore>> {
self.iam.clone() self.iam.clone()
} }
fn is_ready(&self) -> bool {
rustfs_iam::get().is_ok()
}
} }
/// Default KMS interface adapter. /// Default KMS interface adapter.
@@ -66,17 +89,47 @@ impl KmsInterface for KmsHandle {
} }
} }
/// Default notify interface adapter.
#[derive(Default)]
pub struct NotifyHandle;
#[async_trait]
impl NotifyInterface for NotifyHandle {
async fn notify(&self, args: EventArgs) {
notifier_global::notify(args).await;
}
async fn add_event_specific_rules(
&self,
bucket_name: &str,
region: &str,
event_rules: &[(Vec<EventName>, String, String, Vec<TargetID>)],
) -> Result<(), NotificationError> {
notifier_global::add_event_specific_rules(bucket_name, region, event_rules).await
}
async fn clear_bucket_notification_rules(&self, bucket_name: &str) -> Result<(), NotificationError> {
notifier_global::clear_bucket_notification_rules(bucket_name).await
}
}
/// Application-layer context with explicit dependencies. /// Application-layer context with explicit dependencies.
#[derive(Clone)] #[derive(Clone)]
pub struct AppContext { pub struct AppContext {
object_store: Arc<ECStore>, object_store: Arc<ECStore>,
iam: Arc<dyn IamInterface>, iam: Arc<dyn IamInterface>,
kms: Arc<dyn KmsInterface>, kms: Arc<dyn KmsInterface>,
notify: Arc<dyn NotifyInterface>,
} }
impl AppContext { impl AppContext {
pub fn new(object_store: Arc<ECStore>, iam: Arc<dyn IamInterface>, kms: Arc<dyn KmsInterface>) -> Self { pub fn new(object_store: Arc<ECStore>, iam: Arc<dyn IamInterface>, kms: Arc<dyn KmsInterface>) -> Self {
Self { object_store, iam, kms } Self {
object_store,
iam,
kms,
notify: default_notify_interface(),
}
} }
pub fn with_default_interfaces( pub fn with_default_interfaces(
@@ -98,6 +151,14 @@ impl AppContext {
pub fn kms(&self) -> Arc<dyn KmsInterface> { pub fn kms(&self) -> Arc<dyn KmsInterface> {
self.kms.clone() self.kms.clone()
} }
pub fn notify(&self) -> Arc<dyn NotifyInterface> {
self.notify.clone()
}
}
pub fn default_notify_interface() -> Arc<dyn NotifyInterface> {
Arc::new(NotifyHandle)
} }
static GLOBAL_APP_CONTEXT: OnceLock<Arc<AppContext>> = OnceLock::new(); static GLOBAL_APP_CONTEXT: OnceLock<Arc<AppContext>> = OnceLock::new();
+8 -3
View File
@@ -15,7 +15,7 @@
//! Object application use-case contracts. //! Object application use-case contracts.
#![allow(dead_code)] #![allow(dead_code)]
use crate::app::context::{AppContext, get_global_app_context}; use crate::app::context::{AppContext, default_notify_interface, get_global_app_context};
use crate::config::workload_profiles::get_global_buffer_config; use crate::config::workload_profiles::get_global_buffer_config;
use crate::error::ApiError; use crate::error::ApiError;
use crate::storage::access::{ReqInfo, authorize_request, has_bypass_governance_header}; use crate::storage::access::{ReqInfo, authorize_request, has_bypass_governance_header};
@@ -72,7 +72,7 @@ use rustfs_filemeta::{
REPLICATE_INCOMING_DELETE, ReplicationStatusType, ReplicationType, RestoreStatusOps, VersionPurgeStatusType, REPLICATE_INCOMING_DELETE, ReplicationStatusType, ReplicationType, RestoreStatusOps, VersionPurgeStatusType,
parse_restore_obj_status, parse_restore_obj_status,
}; };
use rustfs_notify::{EventArgsBuilder, notifier_global}; use rustfs_notify::EventArgsBuilder;
use rustfs_policy::policy::action::{Action, S3Action}; use rustfs_policy::policy::action::{Action, S3Action};
use rustfs_rio::{CompressReader, DecryptReader, EncryptReader, EtagReader, HardLimitReader, HashReader, Reader, WarpReader}; use rustfs_rio::{CompressReader, DecryptReader, EncryptReader, EtagReader, HardLimitReader, HashReader, Reader, WarpReader};
use rustfs_s3select_api::{ use rustfs_s3select_api::{
@@ -2647,6 +2647,11 @@ impl DefaultObjectUsecase {
} }
let req_headers = req.headers.clone(); let req_headers = req.headers.clone();
let notify = self
.context
.as_ref()
.map(|context| context.notify())
.unwrap_or_else(default_notify_interface);
tokio::spawn(async move { tokio::spawn(async move {
for res in delete_results { for res in delete_results {
if let Some(dobj) = res.delete_object { if let Some(dobj) = res.delete_object {
@@ -2671,7 +2676,7 @@ impl DefaultObjectUsecase {
.user_agent(get_request_user_agent(&req_headers)) .user_agent(get_request_user_agent(&req_headers))
.build(); .build();
notifier_global::notify(event_args).await; notify.notify(event_args).await;
} }
} }
}); });