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 domain::value_objects::WrapUpId;
|
||||||
|
|
||||||
use crate::context::AppContext;
|
use crate::context::AppContext;
|
||||||
|
use crate::wrapup::storage::WrapUpStorage;
|
||||||
|
|
||||||
pub async fn execute(ctx: &AppContext, id: WrapUpId) -> Result<(), DomainError> {
|
pub async fn execute(ctx: &AppContext, id: WrapUpId) -> Result<(), DomainError> {
|
||||||
let record = ctx
|
ctx.repos
|
||||||
.repos
|
|
||||||
.wrapup_repo
|
.wrapup_repo
|
||||||
.get_by_id(&id)
|
.get_by_id(&id)
|
||||||
.await?
|
.await?
|
||||||
.ok_or_else(|| DomainError::NotFound("wrap-up not found".into()))?;
|
.ok_or_else(|| DomainError::NotFound("wrap-up not found".into()))?;
|
||||||
|
|
||||||
let wrapup_key = format!("wrapups/{}", id.value());
|
let storage = WrapUpStorage::new(ctx.services.image_storage.clone());
|
||||||
let video_key = format!("{wrapup_key}/video.mp4");
|
let _ = storage.delete_video(&id).await;
|
||||||
let _ = ctx.services.image_storage.delete(&video_key).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::context::AppContext;
|
||||||
use crate::wrapup::{compute, queries::ComputeWrapUpQuery};
|
use crate::wrapup::{compute, queries::ComputeWrapUpQuery, storage::WrapUpStorage};
|
||||||
use domain::errors::DomainError;
|
use domain::errors::DomainError;
|
||||||
use domain::events::DomainEvent;
|
use domain::events::DomainEvent;
|
||||||
use domain::models::wrapup::{DateRange, WrapUpScope, WrapUpStatus};
|
use domain::models::wrapup::{DateRange, WrapUpScope, WrapUpStatus};
|
||||||
@@ -48,26 +48,18 @@ pub async fn execute(
|
|||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if let Some(ref renderer) = ctx.services.video_renderer {
|
if let Some(ref renderer) = ctx.services.video_renderer {
|
||||||
let poster_images = resolve_images(ctx, &report.poster_paths, "poster").await;
|
let asset_storage = WrapUpStorage::new(ctx.services.image_storage.clone());
|
||||||
let cast_keys: Vec<String> = report
|
let poster_images = asset_storage.resolve_poster_images(&report.poster_paths).await;
|
||||||
.top_cast_profile_paths
|
let cast_images = asset_storage
|
||||||
.iter()
|
.resolve_cast_images(&report.top_cast_profile_paths)
|
||||||
.map(|p| format!("cast{p}"))
|
.await;
|
||||||
.collect();
|
|
||||||
let cast_images = resolve_images(ctx, &cast_keys, "cast").await;
|
|
||||||
let assets = VideoRenderAssets {
|
let assets = VideoRenderAssets {
|
||||||
poster_images,
|
poster_images,
|
||||||
cast_images,
|
cast_images,
|
||||||
};
|
};
|
||||||
match renderer.render(&report, assets).await {
|
match renderer.render(&report, assets).await {
|
||||||
Ok(video_bytes) => {
|
Ok(video_bytes) => {
|
||||||
let video_key = format!("wrapups/{}/video.mp4", wrapup_id.value());
|
if let Err(e) = asset_storage.store_video(&wrapup_id, &video_bytes).await {
|
||||||
if let Err(e) = ctx
|
|
||||||
.services
|
|
||||||
.image_storage
|
|
||||||
.store(&video_key, &video_bytes)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
tracing::warn!("failed to store wrapup video: {e}");
|
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 handle_requested;
|
||||||
pub mod list_wrapups;
|
pub mod list_wrapups;
|
||||||
pub mod queries;
|
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