refactor: introduce IngestTransaction port to reduce IngestAssetHandler from 7 to 4 ports
This commit is contained in:
@@ -5,10 +5,7 @@ use domain::{
|
||||
},
|
||||
errors::DomainError,
|
||||
events::DomainEvent,
|
||||
ports::{
|
||||
AssetRepository, EventPublisher, FileStoragePort, IngestSessionRepository,
|
||||
LibraryPathRepository, QuotaRepository, UsageLedgerRepository,
|
||||
},
|
||||
ports::{EventPublisher, FileStoragePort, IngestTransaction, LibraryPathRepository},
|
||||
value_objects::{Checksum, DateTimeStamp, SystemId},
|
||||
};
|
||||
use sha2::{Digest, Sha256};
|
||||
@@ -26,31 +23,22 @@ pub struct IngestAssetCommand {
|
||||
}
|
||||
|
||||
pub struct IngestAssetHandler {
|
||||
ingest_repo: Arc<dyn IngestSessionRepository>,
|
||||
tx: Arc<dyn IngestTransaction>,
|
||||
path_repo: Arc<dyn LibraryPathRepository>,
|
||||
quota_repo: Arc<dyn QuotaRepository>,
|
||||
ledger_repo: Arc<dyn UsageLedgerRepository>,
|
||||
asset_repo: Arc<dyn AssetRepository>,
|
||||
file_storage: Arc<dyn FileStoragePort>,
|
||||
event_pub: Arc<dyn EventPublisher>,
|
||||
}
|
||||
|
||||
impl IngestAssetHandler {
|
||||
pub fn new(
|
||||
ingest_repo: Arc<dyn IngestSessionRepository>,
|
||||
tx: Arc<dyn IngestTransaction>,
|
||||
path_repo: Arc<dyn LibraryPathRepository>,
|
||||
quota_repo: Arc<dyn QuotaRepository>,
|
||||
ledger_repo: Arc<dyn UsageLedgerRepository>,
|
||||
asset_repo: Arc<dyn AssetRepository>,
|
||||
file_storage: Arc<dyn FileStoragePort>,
|
||||
event_pub: Arc<dyn EventPublisher>,
|
||||
) -> Self {
|
||||
Self {
|
||||
ingest_repo,
|
||||
tx,
|
||||
path_repo,
|
||||
quota_repo,
|
||||
ledger_repo,
|
||||
asset_repo,
|
||||
file_storage,
|
||||
event_pub,
|
||||
}
|
||||
@@ -79,9 +67,9 @@ impl IngestAssetHandler {
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(quota) = self.quota_repo.find_by_owner(&cmd.uploader_id).await? {
|
||||
if let Some(quota) = self.tx.find_quota(&cmd.uploader_id).await? {
|
||||
let current = self
|
||||
.ledger_repo
|
||||
.tx
|
||||
.sum_usage(&cmd.uploader_id, UsageType::StorageBytes, None)
|
||||
.await?;
|
||||
let result = domain::storage::services::check_quota(
|
||||
@@ -131,10 +119,10 @@ impl IngestAssetHandler {
|
||||
cmd.uploader_id,
|
||||
);
|
||||
|
||||
self.asset_repo.save(&asset).await?;
|
||||
self.tx.save_asset(&asset).await?;
|
||||
|
||||
session.advance_to(IngestStatus::AwaitingProcessing)?;
|
||||
self.ingest_repo.save(&session).await?;
|
||||
self.tx.save_session(&session).await?;
|
||||
|
||||
let entry = UsageLedgerEntry::new(
|
||||
cmd.uploader_id,
|
||||
@@ -142,7 +130,7 @@ impl IngestAssetHandler {
|
||||
cmd.file_size,
|
||||
format!("Ingested {}", cmd.filename),
|
||||
);
|
||||
self.ledger_repo.record(&entry).await?;
|
||||
self.tx.record_usage(&entry).await?;
|
||||
|
||||
self.event_pub
|
||||
.publish(&DomainEvent::AssetIngested {
|
||||
|
||||
@@ -9,10 +9,10 @@ use domain::{
|
||||
errors::DomainError,
|
||||
ports::{
|
||||
AlbumRepository, AssetMetadataRepository, AssetRepository, DuplicateRepository,
|
||||
GroupRepository, IngestSessionRepository, JobBatchRepository, JobRepository,
|
||||
LibraryPathRepository, PipelineRepository, PluginRepository, QuotaRepository,
|
||||
RoleRepository, ShareRepository, SidecarRepository, StorageVolumeRepository, TagRepository,
|
||||
UsageLedgerRepository, UserRepository,
|
||||
GroupRepository, IngestSessionRepository, IngestTransaction, JobBatchRepository,
|
||||
JobRepository, LibraryPathRepository, PipelineRepository, PluginRepository,
|
||||
QuotaRepository, RoleRepository, ShareRepository, SidecarRepository,
|
||||
StorageVolumeRepository, TagRepository, UsageLedgerRepository, UserRepository,
|
||||
},
|
||||
value_objects::{Checksum, DateTimeStamp, Email, SystemId},
|
||||
};
|
||||
@@ -1126,3 +1126,93 @@ impl PipelineRepository for InMemoryPipelineRepository {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// --- InMemoryIngestTransaction ---
|
||||
|
||||
pub struct InMemoryIngestTransaction {
|
||||
assets: Mutex<HashMap<String, Asset>>,
|
||||
sessions: Mutex<HashMap<String, IngestSession>>,
|
||||
quotas: Mutex<HashMap<String, QuotaDefinition>>,
|
||||
ledger: Mutex<Vec<UsageLedgerEntry>>,
|
||||
}
|
||||
|
||||
impl InMemoryIngestTransaction {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
assets: Mutex::new(HashMap::new()),
|
||||
sessions: Mutex::new(HashMap::new()),
|
||||
quotas: Mutex::new(HashMap::new()),
|
||||
ledger: Mutex::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Pre-seed a quota for testing.
|
||||
pub async fn insert_quota(&self, quota: &QuotaDefinition) {
|
||||
self.quotas
|
||||
.lock()
|
||||
.await
|
||||
.insert(quota.owner_scope.to_string(), quota.clone());
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for InMemoryIngestTransaction {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl IngestTransaction for InMemoryIngestTransaction {
|
||||
async fn save_asset(&self, asset: &Asset) -> Result<(), DomainError> {
|
||||
self.assets
|
||||
.lock()
|
||||
.await
|
||||
.insert(asset.asset_id.to_string(), asset.clone());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn save_session(&self, session: &IngestSession) -> Result<(), DomainError> {
|
||||
self.sessions
|
||||
.lock()
|
||||
.await
|
||||
.insert(session.session_id.to_string(), session.clone());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn find_quota(
|
||||
&self,
|
||||
owner_id: &SystemId,
|
||||
) -> Result<Option<QuotaDefinition>, DomainError> {
|
||||
Ok(self
|
||||
.quotas
|
||||
.lock()
|
||||
.await
|
||||
.values()
|
||||
.find(|q| &q.owner_scope == owner_id)
|
||||
.cloned())
|
||||
}
|
||||
|
||||
async fn sum_usage(
|
||||
&self,
|
||||
user_id: &SystemId,
|
||||
usage_type: UsageType,
|
||||
since: Option<DateTimeStamp>,
|
||||
) -> Result<u64, DomainError> {
|
||||
let entries = self.ledger.lock().await;
|
||||
let total = entries
|
||||
.iter()
|
||||
.filter(|e| &e.user_id == user_id && e.usage_type == usage_type)
|
||||
.filter(|e| match &since {
|
||||
Some(ts) => &e.timestamp >= ts,
|
||||
None => true,
|
||||
})
|
||||
.map(|e| e.consumed_amount)
|
||||
.sum();
|
||||
Ok(total)
|
||||
}
|
||||
|
||||
async fn record_usage(&self, entry: &UsageLedgerEntry) -> Result<(), DomainError> {
|
||||
self.ledger.lock().await.push(entry.clone());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user