refactor: extract storage key conventions into WrapUpStorage
Some checks failed
CI / Check / Test (push) Failing after 43s
Some checks failed
CI / Check / Test (push) Failing after 43s
This commit is contained in:
@@ -2,18 +2,17 @@ use domain::errors::DomainError;
|
||||
use domain::value_objects::WrapUpId;
|
||||
|
||||
use crate::context::AppContext;
|
||||
use crate::wrapup::storage::WrapUpStorage;
|
||||
|
||||
pub async fn execute(ctx: &AppContext, id: WrapUpId) -> Result<(), DomainError> {
|
||||
let record = ctx
|
||||
.repos
|
||||
ctx.repos
|
||||
.wrapup_repo
|
||||
.get_by_id(&id)
|
||||
.await?
|
||||
.ok_or_else(|| DomainError::NotFound("wrap-up not found".into()))?;
|
||||
|
||||
let wrapup_key = format!("wrapups/{}", id.value());
|
||||
let video_key = format!("{wrapup_key}/video.mp4");
|
||||
let _ = ctx.services.image_storage.delete(&video_key).await;
|
||||
let storage = WrapUpStorage::new(ctx.services.image_storage.clone());
|
||||
let _ = storage.delete_video(&id).await;
|
||||
|
||||
ctx.repos.wrapup_repo.delete(&record.id).await
|
||||
ctx.repos.wrapup_repo.delete(&id).await
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::context::AppContext;
|
||||
use crate::wrapup::{compute, queries::ComputeWrapUpQuery};
|
||||
use crate::wrapup::{compute, queries::ComputeWrapUpQuery, storage::WrapUpStorage};
|
||||
use domain::errors::DomainError;
|
||||
use domain::events::DomainEvent;
|
||||
use domain::models::wrapup::{DateRange, WrapUpScope, WrapUpStatus};
|
||||
@@ -48,26 +48,18 @@ pub async fn execute(
|
||||
.await?;
|
||||
|
||||
if let Some(ref renderer) = ctx.services.video_renderer {
|
||||
let poster_images = resolve_images(ctx, &report.poster_paths, "poster").await;
|
||||
let cast_keys: Vec<String> = report
|
||||
.top_cast_profile_paths
|
||||
.iter()
|
||||
.map(|p| format!("cast{p}"))
|
||||
.collect();
|
||||
let cast_images = resolve_images(ctx, &cast_keys, "cast").await;
|
||||
let asset_storage = WrapUpStorage::new(ctx.services.image_storage.clone());
|
||||
let poster_images = asset_storage.resolve_poster_images(&report.poster_paths).await;
|
||||
let cast_images = asset_storage
|
||||
.resolve_cast_images(&report.top_cast_profile_paths)
|
||||
.await;
|
||||
let assets = VideoRenderAssets {
|
||||
poster_images,
|
||||
cast_images,
|
||||
};
|
||||
match renderer.render(&report, assets).await {
|
||||
Ok(video_bytes) => {
|
||||
let video_key = format!("wrapups/{}/video.mp4", wrapup_id.value());
|
||||
if let Err(e) = ctx
|
||||
.services
|
||||
.image_storage
|
||||
.store(&video_key, &video_bytes)
|
||||
.await
|
||||
{
|
||||
if let Err(e) = asset_storage.store_video(&wrapup_id, &video_bytes).await {
|
||||
tracing::warn!("failed to store wrapup video: {e}");
|
||||
}
|
||||
}
|
||||
@@ -92,15 +84,3 @@ pub async fn execute(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn resolve_images(ctx: &AppContext, paths: &[String], label: &str) -> Vec<(String, Vec<u8>)> {
|
||||
let mut images = Vec::new();
|
||||
for path in paths.iter().take(20) {
|
||||
match ctx.services.image_storage.get(path).await {
|
||||
Ok(bytes) => images.push((path.clone(), bytes)),
|
||||
Err(e) => tracing::debug!("{label} fetch skipped for {path}: {e}"),
|
||||
}
|
||||
}
|
||||
tracing::info!("resolved {}/{} {label} images", images.len(), paths.len());
|
||||
images
|
||||
}
|
||||
|
||||
@@ -7,3 +7,4 @@ pub mod get_wrapup;
|
||||
pub mod handle_requested;
|
||||
pub mod list_wrapups;
|
||||
pub mod queries;
|
||||
pub mod storage;
|
||||
|
||||
60
crates/application/src/wrapup/storage.rs
Normal file
60
crates/application/src/wrapup/storage.rs
Normal file
@@ -0,0 +1,60 @@
|
||||
use domain::errors::DomainError;
|
||||
use domain::ports::ImageStorage;
|
||||
use domain::value_objects::WrapUpId;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct WrapUpStorage {
|
||||
inner: Arc<dyn ImageStorage>,
|
||||
}
|
||||
|
||||
impl WrapUpStorage {
|
||||
pub fn new(storage: Arc<dyn ImageStorage>) -> Self {
|
||||
Self { inner: storage }
|
||||
}
|
||||
|
||||
pub async fn store_video(&self, id: &WrapUpId, bytes: &[u8]) -> Result<(), DomainError> {
|
||||
let key = format!("wrapups/{}/video.mp4", id.value());
|
||||
self.inner.store(&key, bytes).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_video(&self, id: &WrapUpId) -> Result<(), DomainError> {
|
||||
let key = format!("wrapups/{}/video.mp4", id.value());
|
||||
self.inner.delete(&key).await
|
||||
}
|
||||
|
||||
pub fn cast_image_key(profile_path: &str) -> String {
|
||||
format!("cast{profile_path}")
|
||||
}
|
||||
|
||||
pub async fn resolve_cast_images(
|
||||
&self,
|
||||
profile_paths: &[String],
|
||||
) -> Vec<(String, Vec<u8>)> {
|
||||
let mut images = Vec::new();
|
||||
for path in profile_paths.iter().take(20) {
|
||||
let key = Self::cast_image_key(path);
|
||||
match self.inner.get(&key).await {
|
||||
Ok(bytes) => images.push((key, bytes)),
|
||||
Err(e) => tracing::debug!("cast fetch skipped for {key}: {e}"),
|
||||
}
|
||||
}
|
||||
tracing::info!("resolved {}/{} cast images", images.len(), profile_paths.len());
|
||||
images
|
||||
}
|
||||
|
||||
pub async fn resolve_poster_images(
|
||||
&self,
|
||||
paths: &[String],
|
||||
) -> Vec<(String, Vec<u8>)> {
|
||||
let mut images = Vec::new();
|
||||
for path in paths.iter().take(20) {
|
||||
match self.inner.get(path).await {
|
||||
Ok(bytes) => images.push((path.clone(), bytes)),
|
||||
Err(e) => tracing::debug!("poster fetch skipped for {path}: {e}"),
|
||||
}
|
||||
}
|
||||
tracing::info!("resolved {}/{} poster images", images.len(), paths.len());
|
||||
images
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user