diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_image_payload.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_image_payload.rs index 9ed3bfa2f1..a0b3b3ee63 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_image_payload.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_image_payload.rs @@ -1,12 +1,11 @@ +use crate::http_server::common_responses::advanced_common_web_error::AdvancedCommonWebError; use crate::http_server::endpoints::webhooks::process_success::resolve_file_metadata::resolve_file_metadata; use crate::state::server_state::ServerState; use crate::util::http_download_url_to_bytes::http_download_url_to_bytes; -use anyhow::anyhow; use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath; use enums::by_table::media_files::media_file_class::MediaFileClass; use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; use enums::by_table::media_files::media_file_type::MediaFileType; -use errors::AnyhowResult; use fal_client::webhook_api::hydrated::hydrated_webhook_contents::ImageData; use hashing::sha256::sha256_hash_bytes::sha256_hash_bytes; use images::encoding::webp_bytes_to_png_bytes::webp_bytes_to_png_bytes; @@ -23,15 +22,21 @@ pub async fn process_image_payload( image_data: &ImageData, job: &FalJobDetails, server_state: &ServerState, -) -> AnyhowResult { +) -> Result { let image_url = image_data.url .as_deref() - .ok_or_else(|| anyhow!("no `url` in image payload"))?; + .ok_or_else(|| { + warn!("No `url` in image payload"); + AdvancedCommonWebError::server_error_with_message("no `url` in image payload") + })?; // Download with a retry if the first attempt returns suspiciously few bytes. let mut file_bytes = http_download_url_to_bytes(image_url) .await - .map_err(|e| anyhow!("Failed to download image: {:?}", e))?; + .map_err(|err| { + warn!("Failed to download image from {}: {:?}", image_url, err); + AdvancedCommonWebError::from_anyhow_error(err) + })?; if file_bytes.len() <= 10 { warn!( @@ -41,16 +46,24 @@ pub async fn process_image_payload( ); file_bytes = http_download_url_to_bytes(image_url) .await - .map_err(|e| anyhow!("Failed to download image on retry: {:?}", e))?; + .map_err(|err| { + warn!("Failed to download image on retry from {}: {:?}", image_url, err); + AdvancedCommonWebError::from_anyhow_error(err) + })?; } // Resolve mime type: magic bytes first, fal content_type as fallback. let metadata = resolve_file_metadata(&file_bytes, image_data.content_type.as_deref()) - .ok_or_else(|| anyhow!( - "Could not determine file type for image (bytes: {}, fal content_type: {:?})", - file_bytes.len(), - image_data.content_type, - ))?; + .ok_or_else(|| { + warn!( + "Could not determine file type for image (bytes: {}, fal content_type: {:?})", + file_bytes.len(), + image_data.content_type, + ); + AdvancedCommonWebError::server_error_with_message( + &format!("Could not determine file type for image (bytes: {}, fal content_type: {:?})", + file_bytes.len(), image_data.content_type)) + })?; info!("File type: {}, extension: {:?}, source: {:?}", metadata.mime_type, metadata.file_extension, metadata.source); @@ -59,10 +72,18 @@ pub async fn process_image_payload( FileExtension::Webp => { info!("Artcraft can't handle WebP images yet; converting to PNG..."); - let converted = webp_bytes_to_png_bytes(&file_bytes)?; + let converted = webp_bytes_to_png_bytes(&file_bytes) + .map_err(|e| { + warn!("Failed to convert WebP to PNG: {:?}", e); + AdvancedCommonWebError::from_error(e) + })?; let converted_metadata = resolve_file_metadata(&converted, Some("image/png")) - .ok_or_else(|| anyhow!("Failed to determine file type after WebP→PNG conversion"))?; + .ok_or_else(|| { + warn!("Failed to determine file type after WebP→PNG conversion"); + AdvancedCommonWebError::server_error_with_message( + "Failed to determine file type after WebP→PNG conversion") + })?; info!("Converted file type: {}, extension: {:?}", converted_metadata.mime_type, converted_metadata.file_extension); @@ -93,16 +114,28 @@ async fn upload_single_image_bytes( file_bytes: &[u8], mime_type: &str, file_extension: FileExtension, -) -> AnyhowResult { +) -> Result { let media_file_type = MediaFileType::try_from_mime_type(mime_type) - .ok_or_else(|| anyhow!("Unsupported media file type: {}", mime_type))?; + .ok_or_else(|| { + warn!("Unsupported media file type: {}", mime_type); + AdvancedCommonWebError::server_error_with_message( + &format!("Unsupported media file type: {}", mime_type)) + })?; let extension_with_period = file_extension.extension_with_period(); let file_size_bytes = file_bytes.len(); - let file_hash = sha256_hash_bytes(&file_bytes)?; - let image_info = ImageInfo::decode_image_from_bytes(&file_bytes)?; + let file_hash = sha256_hash_bytes(&file_bytes) + .map_err(|e| { + warn!("Failed to hash image bytes: {:?}", e); + AdvancedCommonWebError::from_anyhow_error(e) + })?; + let image_info = ImageInfo::decode_image_from_bytes(&file_bytes) + .map_err(|e| { + warn!("Failed to decode image info: {:?}", e); + AdvancedCommonWebError::from_error(e) + })?; let public_upload_path = MediaFileBucketPath::generate_new(PREFIX, Some(&extension_with_period)); @@ -112,7 +145,11 @@ async fn upload_single_image_bytes( public_upload_path.get_full_object_path_str(), file_bytes.as_ref(), mime_type) - .await?; + .await + .map_err(|e| { + warn!("Failed to upload image to bucket: {:?}", e); + AdvancedCommonWebError::from_anyhow_error(e) + })?; let media_token = MediaFileInsertBuilder::new() .maybe_creator_user(job.maybe_creator_user_token.as_ref()) @@ -130,8 +167,12 @@ async fn upload_single_image_bytes( .frame_height(image_info.height()) .checksum_sha2(&file_hash) .insert_pool(&server_state.mysql_pool) - .await?; - + .await + .map_err(|err| { + warn!("Failed to insert image media file record: {:?}", err); + AdvancedCommonWebError::from_error(err) + })?; + info!("Image media file uploaded with token: {}", media_token); Ok(media_token) diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_images_payload.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_images_payload.rs index 029a348c41..f0c689faac 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_images_payload.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_images_payload.rs @@ -1,12 +1,11 @@ +use crate::http_server::common_responses::advanced_common_web_error::AdvancedCommonWebError; use crate::http_server::endpoints::webhooks::process_success::resolve_file_metadata::resolve_file_metadata; use crate::state::server_state::ServerState; use crate::util::http_download_url_to_bytes::http_download_url_to_bytes; -use anyhow::anyhow; use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath; use enums::by_table::media_files::media_file_class::MediaFileClass; use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; use enums::by_table::media_files::media_file_type::MediaFileType; -use errors::AnyhowResult; use fal_client::webhook_api::hydrated::hydrated_webhook_contents::ImagesData; use hashing::sha256::sha256_hash_bytes::sha256_hash_bytes; use images::encoding::webp_bytes_to_png_bytes::webp_bytes_to_png_bytes; @@ -24,7 +23,7 @@ pub async fn process_images_payload( images_data: &[ImagesData], job: &FalJobDetails, server_state: &ServerState, -) -> AnyhowResult<(Option, Option)> { +) -> Result<(Option, Option), AdvancedCommonWebError> { let mut maybe_media_token = None; @@ -52,15 +51,22 @@ async fn upload_image( server_state: &ServerState, image: &ImagesData, maybe_batch_token: Option<&BatchGenerationToken>, -) -> AnyhowResult { +) -> Result { let image_url = image.url .as_deref() - .ok_or_else(|| anyhow!("no `url` in image payload"))?; + .ok_or_else(|| { + warn!("No `url` in image payload"); + AdvancedCommonWebError::server_error_with_message("no `url` in image payload") + })?; // Download with a retry if the first attempt returns suspiciously few bytes. let mut file_bytes = http_download_url_to_bytes(image_url) .await - .map_err(|e| anyhow!("Failed to download image: {:?}", e))?; + .map_err(|e| { + warn!("Failed to download image from {}: {:?}", image_url, e); + AdvancedCommonWebError::server_error_with_message( + &format!("Failed to download image: {:?}", e)) + })?; if file_bytes.len() <= 10 { warn!( @@ -70,16 +76,25 @@ async fn upload_image( ); file_bytes = http_download_url_to_bytes(image_url) .await - .map_err(|e| anyhow!("Failed to download image on retry: {:?}", e))?; + .map_err(|e| { + warn!("Failed to download image on retry from {}: {:?}", image_url, e); + AdvancedCommonWebError::server_error_with_message( + &format!("Failed to download image on retry: {:?}", e)) + })?; } // Resolve mime type: magic bytes first, fal content_type as fallback. let metadata = resolve_file_metadata(&file_bytes, image.content_type.as_deref()) - .ok_or_else(|| anyhow!( - "Could not determine file type for image (bytes: {}, fal content_type: {:?})", - file_bytes.len(), - image.content_type, - ))?; + .ok_or_else(|| { + warn!( + "Could not determine file type for image (bytes: {}, fal content_type: {:?})", + file_bytes.len(), + image.content_type, + ); + AdvancedCommonWebError::server_error_with_message( + &format!("Could not determine file type for image (bytes: {}, fal content_type: {:?})", + file_bytes.len(), image.content_type)) + })?; info!("File type: {}, extension: {:?}, source: {:?}", metadata.mime_type, metadata.file_extension, metadata.source); @@ -88,10 +103,18 @@ async fn upload_image( FileExtension::Webp => { info!("Artcraft can't handle WebP images yet; converting to PNG..."); - let converted = webp_bytes_to_png_bytes(&file_bytes)?; + let converted = webp_bytes_to_png_bytes(&file_bytes) + .map_err(|e| { + warn!("Failed to convert WebP to PNG: {:?}", e); + AdvancedCommonWebError::from_error(e) + })?; let converted_metadata = resolve_file_metadata(&converted, Some("image/png")) - .ok_or_else(|| anyhow!("Failed to determine file type after WebP→PNG conversion"))?; + .ok_or_else(|| { + warn!("Failed to determine file type after WebP→PNG conversion"); + AdvancedCommonWebError::server_error_with_message( + "Failed to determine file type after WebP→PNG conversion") + })?; info!("Converted file type: {}, extension: {:?}", converted_metadata.mime_type, converted_metadata.file_extension); @@ -99,7 +122,6 @@ async fn upload_image( upload_image_bytes( job, server_state, - image, &converted, &converted_metadata.mime_type, converted_metadata.file_extension, @@ -110,7 +132,6 @@ async fn upload_image( upload_image_bytes( job, server_state, - image, &file_bytes, &metadata.mime_type, metadata.file_extension, @@ -123,23 +144,34 @@ async fn upload_image( async fn upload_image_bytes( job: &FalJobDetails, server_state: &ServerState, - _image: &ImagesData, file_bytes: &[u8], mime_type: &str, file_extension: FileExtension, maybe_batch_token: Option<&BatchGenerationToken>, -) -> AnyhowResult { +) -> Result { let media_file_type = MediaFileType::try_from_mime_type(mime_type) - .ok_or_else(|| anyhow!("Unsupported media file type: {}", mime_type))?; + .ok_or_else(|| { + warn!("Unsupported media file type: {}", mime_type); + AdvancedCommonWebError::server_error_with_message( + &format!("Unsupported media file type: {}", mime_type)) + })?; info!("MediaFileType: {:?}", media_file_type); let extension_with_period = file_extension.extension_with_period(); let file_size_bytes = file_bytes.len(); - let file_hash = sha256_hash_bytes(&file_bytes)?; - let image_info = ImageInfo::decode_image_from_bytes(&file_bytes)?; + let file_hash = sha256_hash_bytes(&file_bytes) + .map_err(|e| { + warn!("Failed to hash image bytes: {:?}", e); + AdvancedCommonWebError::from_anyhow_error(e) + })?; + let image_info = ImageInfo::decode_image_from_bytes(&file_bytes) + .map_err(|e| { + warn!("Failed to decode image info: {:?}", e); + AdvancedCommonWebError::from_error(e) + })?; let public_upload_path = MediaFileBucketPath::generate_new(PREFIX, Some(&extension_with_period)); @@ -149,7 +181,11 @@ async fn upload_image_bytes( public_upload_path.get_full_object_path_str(), file_bytes.as_ref(), mime_type) - .await?; + .await + .map_err(|e| { + warn!("Failed to upload image to bucket: {:?}", e); + AdvancedCommonWebError::from_anyhow_error(e) + })?; let mut query_builder = MediaFileInsertBuilder::new() .maybe_creator_user(job.maybe_creator_user_token.as_ref()) @@ -173,7 +209,11 @@ async fn upload_image_bytes( let media_token = query_builder .insert_pool(&server_state.mysql_pool) - .await?; + .await + .map_err(|e| { + warn!("Failed to insert image media file record: {:?}", e); + AdvancedCommonWebError::from_error(e) + })?; info!("Image media file uploaded with token: {} ; possible batch token: {:?}", media_token, maybe_batch_token); diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_model_glb_payload.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_model_glb_payload.rs index ee6184551d..2d668c8846 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_model_glb_payload.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_model_glb_payload.rs @@ -1,13 +1,12 @@ +use crate::http_server::common_responses::advanced_common_web_error::AdvancedCommonWebError; use crate::http_server::endpoints::webhooks::process_success::resolve_file_metadata::resolve_file_metadata; use crate::state::server_state::ServerState; use crate::util::http_download_url_to_bytes::http_download_url_to_bytes; -use anyhow::anyhow; use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath; use enums::by_table::media_files::media_file_class::MediaFileClass; use enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory; use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; use enums::by_table::media_files::media_file_type::MediaFileType; -use errors::AnyhowResult; use fal_client::webhook_api::hydrated::hydrated_webhook_contents::{ModelGlbData, ThumbnailData}; use hashing::sha256::sha256_hash_bytes::sha256_hash_bytes; use log::{info, warn}; @@ -20,7 +19,7 @@ const PREFIX : Option<&str> = Some("artcraft_"); /* Example payload, from Hunyuan 3d 3.0, - + { "model_glb": { "url": "https://v3b.fal.media/files/b/0a8afeff/8uc6VVLTpmVrupLqxxwOg_model.glb", @@ -52,7 +51,7 @@ const PREFIX : Option<&str> = Some("artcraft_"); }, "seed": null } - + */ pub async fn process_model_glb_payload( @@ -60,15 +59,21 @@ pub async fn process_model_glb_payload( maybe_thumbnail_data: Option<&ThumbnailData>, job: &FalJobDetails, server_state: &ServerState, -) -> AnyhowResult { +) -> Result { let mesh_url = model_glb_data.url .as_deref() - .ok_or_else(|| anyhow!("no `url` in model glb payload"))?; + .ok_or_else(|| { + warn!("No `url` in model glb payload"); + AdvancedCommonWebError::server_error_with_message("no `url` in model glb payload") + })?; // Download with a retry if the first attempt returns suspiciously few bytes. let mut file_bytes = http_download_url_to_bytes(mesh_url) .await - .map_err(|e| anyhow!("Failed to download mesh: {:?}", e))?; + .map_err(|err| { + warn!("Failed to download mesh from {}: {:?}", mesh_url, err); + AdvancedCommonWebError::from_anyhow_error(err) + })?; if file_bytes.len() <= 10 { warn!( @@ -78,28 +83,45 @@ pub async fn process_model_glb_payload( ); file_bytes = http_download_url_to_bytes(mesh_url) .await - .map_err(|e| anyhow!("Failed to download mesh on retry: {:?}", e))?; + .map_err(|e| { + warn!("Failed to download mesh on retry from {}: {:?}", mesh_url, e); + AdvancedCommonWebError::server_error_with_message( + &format!("Failed to download mesh on retry: {:?}", e)) + })?; } // Resolve mime type: magic bytes first, fal content_type as fallback. let metadata = resolve_file_metadata(&file_bytes, model_glb_data.content_type.as_deref()) - .ok_or_else(|| anyhow!( - "Could not determine file type for mesh (bytes: {}, fal content_type: {:?})", - file_bytes.len(), - model_glb_data.content_type, - ))?; + .ok_or_else(|| { + warn!( + "Could not determine file type for mesh (bytes: {}, fal content_type: {:?})", + file_bytes.len(), + model_glb_data.content_type, + ); + AdvancedCommonWebError::server_error_with_message( + &format!("Could not determine file type for mesh (bytes: {}, fal content_type: {:?})", + file_bytes.len(), model_glb_data.content_type)) + })?; let mime_type = metadata.mime_type.as_str(); info!("Mime type of mesh: {}, source: {:?}", mime_type, metadata.source); let media_file_type = MediaFileType::try_from_mime_type(mime_type) - .ok_or_else(|| anyhow!("Unsupported media file type: {}", mime_type))?; + .ok_or_else(|| { + warn!("Unsupported media file type: {}", mime_type); + AdvancedCommonWebError::server_error_with_message( + &format!("Unsupported media file type: {}", mime_type)) + })?; let extension_with_period = metadata.file_extension.extension_with_period(); let file_size_bytes = file_bytes.len(); - let file_hash = sha256_hash_bytes(&file_bytes)?; + let file_hash = sha256_hash_bytes(&file_bytes) + .map_err(|e| { + warn!("Failed to hash mesh bytes: {:?}", e); + AdvancedCommonWebError::from_anyhow_error(e) + })?; let public_upload_path = MediaFileBucketPath::generate_new(PREFIX, Some(&extension_with_period)); @@ -109,7 +131,11 @@ pub async fn process_model_glb_payload( public_upload_path.get_full_object_path_str(), file_bytes.as_ref(), &mime_type) - .await?; + .await + .map_err(|e| { + warn!("Failed to upload mesh to bucket: {:?}", e); + AdvancedCommonWebError::from_anyhow_error(e) + })?; let media_token = MediaFileInsertBuilder::new() .maybe_creator_user(job.maybe_creator_user_token.as_ref()) @@ -126,17 +152,21 @@ pub async fn process_model_glb_payload( .maybe_prompt_token(job.maybe_prompt_token.as_ref()) .checksum_sha2(&file_hash) .insert_pool(&server_state.mysql_pool) - .await?; - + .await + .map_err(|e| { + warn!("Failed to insert glb media file record: {:?}", e); + AdvancedCommonWebError::from_error(e) + })?; + info!("Glb media file uploaded with token: {}", media_token); - + let result = try_to_attach_thumbnail( maybe_thumbnail_data, job, server_state, &media_token, ).await; - + // NB: Fail open if let Err(err) = result { warn!("Could not attach thumbnail as cover image to media file: {:?}", err); @@ -150,20 +180,31 @@ async fn try_to_attach_thumbnail( job: &FalJobDetails, server_state: &ServerState, glb_media_token: &MediaFileToken, -) -> AnyhowResult<()> { +) -> Result<(), AdvancedCommonWebError> { let thumbnail_data = maybe_thumbnail_data - .ok_or_else(|| anyhow!("no thumbnail data in extracted contents"))?; + .ok_or_else(|| { + warn!("No thumbnail data in extracted contents"); + AdvancedCommonWebError::server_error_with_message( + "no thumbnail data in extracted contents") + })?; info!("Fal Thumbnail Data: {:?}", thumbnail_data); let thumbnail_url = thumbnail_data.url .as_deref() - .ok_or_else(|| anyhow!("no `url` in thumbnail payload"))?; + .ok_or_else(|| { + warn!("No `url` in thumbnail payload"); + AdvancedCommonWebError::server_error_with_message("no `url` in thumbnail payload") + })?; // Download with a retry if the first attempt returns suspiciously few bytes. let mut file_bytes = http_download_url_to_bytes(thumbnail_url) .await - .map_err(|e| anyhow!("Failed to download thumbnail image: {:?}", e))?; + .map_err(|e| { + warn!("Failed to download thumbnail image from {}: {:?}", thumbnail_url, e); + AdvancedCommonWebError::server_error_with_message( + &format!("Failed to download thumbnail image: {:?}", e)) + })?; if file_bytes.len() <= 10 { warn!( @@ -173,28 +214,45 @@ async fn try_to_attach_thumbnail( ); file_bytes = http_download_url_to_bytes(thumbnail_url) .await - .map_err(|e| anyhow!("Failed to download thumbnail on retry: {:?}", e))?; + .map_err(|e| { + warn!("Failed to download thumbnail on retry from {}: {:?}", thumbnail_url, e); + AdvancedCommonWebError::server_error_with_message( + &format!("Failed to download thumbnail on retry: {:?}", e)) + })?; } // Resolve mime type: magic bytes first, fal content_type as fallback. let metadata = resolve_file_metadata(&file_bytes, thumbnail_data.content_type.as_deref()) - .ok_or_else(|| anyhow!( - "Could not determine file type for thumbnail (bytes: {}, fal content_type: {:?})", - file_bytes.len(), - thumbnail_data.content_type, - ))?; + .ok_or_else(|| { + warn!( + "Could not determine file type for thumbnail (bytes: {}, fal content_type: {:?})", + file_bytes.len(), + thumbnail_data.content_type, + ); + AdvancedCommonWebError::server_error_with_message( + &format!("Could not determine file type for thumbnail (bytes: {}, fal content_type: {:?})", + file_bytes.len(), thumbnail_data.content_type)) + })?; let mime_type = metadata.mime_type.as_str(); info!("Mime type of thumbnail image: {}, source: {:?}", mime_type, metadata.source); let media_file_type = MediaFileType::try_from_mime_type(mime_type) - .ok_or_else(|| anyhow!("Unsupported media file type: {}", mime_type))?; + .ok_or_else(|| { + warn!("Unsupported thumbnail media file type: {}", mime_type); + AdvancedCommonWebError::server_error_with_message( + &format!("Unsupported media file type: {}", mime_type)) + })?; let extension_with_period = metadata.file_extension.extension_with_period(); let file_size_bytes = file_bytes.len(); - let file_hash = sha256_hash_bytes(&file_bytes)?; + let file_hash = sha256_hash_bytes(&file_bytes) + .map_err(|e| { + warn!("Failed to hash thumbnail bytes: {:?}", e); + AdvancedCommonWebError::from_anyhow_error(e) + })?; let public_upload_path = MediaFileBucketPath::generate_new(PREFIX, Some(&extension_with_period)); @@ -204,7 +262,11 @@ async fn try_to_attach_thumbnail( public_upload_path.get_full_object_path_str(), file_bytes.as_ref(), &mime_type) - .await?; + .await + .map_err(|e| { + warn!("Failed to upload thumbnail to bucket: {:?}", e); + AdvancedCommonWebError::from_anyhow_error(e) + })?; let thumbnail_media_token = MediaFileInsertBuilder::new() .maybe_creator_user(job.maybe_creator_user_token.as_ref()) @@ -222,7 +284,11 @@ async fn try_to_attach_thumbnail( .is_intermediate_system_file(true) .checksum_sha2(&file_hash) .insert_pool(&server_state.mysql_pool) - .await?; + .await + .map_err(|e| { + warn!("Failed to insert thumbnail media file record: {:?}", e); + AdvancedCommonWebError::from_error(e) + })?; let query_result = set_media_file_cover_image(UpdateArgs { media_file_token: glb_media_token, @@ -230,5 +296,9 @@ async fn try_to_attach_thumbnail( mysql_pool: &server_state.mysql_pool, }).await; + if let Err(err) = query_result { + warn!("Failed to set cover image on media file {}: {:?}", glb_media_token, err); + } + Ok(()) } diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_model_mesh_payload.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_model_mesh_payload.rs index 21426c8c84..482c8f3ad3 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_model_mesh_payload.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_model_mesh_payload.rs @@ -1,13 +1,12 @@ +use crate::http_server::common_responses::advanced_common_web_error::AdvancedCommonWebError; use crate::http_server::endpoints::webhooks::process_success::resolve_file_metadata::resolve_file_metadata; use crate::state::server_state::ServerState; use crate::util::http_download_url_to_bytes::http_download_url_to_bytes; -use anyhow::anyhow; use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath; use enums::by_table::media_files::media_file_class::MediaFileClass; use enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory; use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; use enums::by_table::media_files::media_file_type::MediaFileType; -use errors::AnyhowResult; use fal_client::webhook_api::hydrated::hydrated_webhook_contents::ModelMeshData; use hashing::sha256::sha256_hash_bytes::sha256_hash_bytes; use log::{info, warn}; @@ -21,15 +20,21 @@ pub async fn process_model_mesh_payload( model_mesh_data: &ModelMeshData, job: &FalJobDetails, server_state: &ServerState, -) -> AnyhowResult { +) -> Result { let mesh_url = model_mesh_data.url .as_deref() - .ok_or_else(|| anyhow!("no `url` in model mesh payload"))?; + .ok_or_else(|| { + warn!("No `url` in model mesh payload"); + AdvancedCommonWebError::server_error_with_message("no `url` in model mesh payload") + })?; // Download with a retry if the first attempt returns suspiciously few bytes. let mut file_bytes = http_download_url_to_bytes(mesh_url) .await - .map_err(|e| anyhow!("Failed to download mesh: {:?}", e))?; + .map_err(|err| { + warn!("Failed to download mesh from {}: {:?}", mesh_url, err); + AdvancedCommonWebError::from_anyhow_error(err) + })?; if file_bytes.len() <= 10 { warn!( @@ -39,28 +44,44 @@ pub async fn process_model_mesh_payload( ); file_bytes = http_download_url_to_bytes(mesh_url) .await - .map_err(|e| anyhow!("Failed to download mesh on retry: {:?}", e))?; + .map_err(|err| { + warn!("Failed to download mesh on retry from {}: {:?}", mesh_url, err); + AdvancedCommonWebError::from_anyhow_error(err) + })?; } // Resolve mime type: magic bytes first, fal content_type as fallback. let metadata = resolve_file_metadata(&file_bytes, model_mesh_data.content_type.as_deref()) - .ok_or_else(|| anyhow!( - "Could not determine file type for mesh (bytes: {}, fal content_type: {:?})", - file_bytes.len(), - model_mesh_data.content_type, - ))?; + .ok_or_else(|| { + warn!( + "Could not determine file type for mesh (bytes: {}, fal content_type: {:?})", + file_bytes.len(), + model_mesh_data.content_type, + ); + AdvancedCommonWebError::server_error_with_message( + &format!("Could not determine file type for mesh (bytes: {}, fal content_type: {:?})", + file_bytes.len(), model_mesh_data.content_type)) + })?; let mime_type = metadata.mime_type.as_str(); info!("Mime type of mesh: {}, source: {:?}", mime_type, metadata.source); let media_file_type = MediaFileType::try_from_mime_type(mime_type) - .ok_or_else(|| anyhow!("Unsupported media file type: {}", mime_type))?; + .ok_or_else(|| { + warn!("Unsupported media file type: {}", mime_type); + AdvancedCommonWebError::server_error_with_message( + &format!("Unsupported media file type: {}", mime_type)) + })?; let extension_with_period = metadata.file_extension.extension_with_period(); let file_size_bytes = file_bytes.len(); - let file_hash = sha256_hash_bytes(&file_bytes)?; + let file_hash = sha256_hash_bytes(&file_bytes) + .map_err(|err| { + warn!("Failed to hash mesh bytes: {:?}", err); + AdvancedCommonWebError::from_anyhow_error(err) + })?; let public_upload_path = MediaFileBucketPath::generate_new(PREFIX, Some(&extension_with_period)); @@ -70,7 +91,11 @@ pub async fn process_model_mesh_payload( public_upload_path.get_full_object_path_str(), file_bytes.as_ref(), &mime_type) - .await?; + .await + .map_err(|err| { + warn!("Failed to upload mesh to bucket: {:?}", err); + AdvancedCommonWebError::from_anyhow_error(err) + })?; let media_token = MediaFileInsertBuilder::new() .maybe_creator_user(job.maybe_creator_user_token.as_ref()) @@ -87,8 +112,12 @@ pub async fn process_model_mesh_payload( .maybe_prompt_token(job.maybe_prompt_token.as_ref()) .checksum_sha2(&file_hash) .insert_pool(&server_state.mysql_pool) - .await?; - + .await + .map_err(|err| { + warn!("Failed to insert mesh media file record: {:?}", err); + AdvancedCommonWebError::from_error(err) + })?; + info!("Mesh media file uploaded with token: {}", media_token); Ok(media_token) diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_video_payload.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_video_payload.rs index fb0d07129e..f5dc1249f8 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_video_payload.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/webhooks/process_success/process_video_payload.rs @@ -1,12 +1,11 @@ +use crate::http_server::common_responses::advanced_common_web_error::AdvancedCommonWebError; use crate::http_server::endpoints::webhooks::process_success::resolve_file_metadata::resolve_file_metadata; use crate::state::server_state::ServerState; use crate::util::http_download_url_to_bytes::http_download_url_to_bytes; -use anyhow::anyhow; use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath; use enums::by_table::media_files::media_file_class::MediaFileClass; use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; use enums::by_table::media_files::media_file_type::MediaFileType; -use errors::AnyhowResult; use fal_client::webhook_api::hydrated::hydrated_webhook_contents::VideoData; use filesys::path_to_string::path_to_string; use hashing::sha256::sha256_hash_bytes::sha256_hash_bytes; @@ -25,15 +24,21 @@ pub async fn process_video_payload( video_data: &VideoData, job: &FalJobDetails, server_state: &ServerState, -) -> AnyhowResult { +) -> Result { let video_url = video_data.url .as_deref() - .ok_or_else(|| anyhow!("no `url` in video payload"))?; + .ok_or_else(|| { + warn!("No `url` in video payload"); + AdvancedCommonWebError::server_error_with_message("no `url` in video payload") + })?; // Download with a retry if the first attempt returns suspiciously few bytes. let mut file_bytes = http_download_url_to_bytes(video_url) .await - .map_err(|e| anyhow!("Failed to download video: {:?}", e))?; + .map_err(|err| { + warn!("Failed to download video from {}: {:?}", video_url, err); + AdvancedCommonWebError::from_anyhow_error(err) + })?; if file_bytes.len() <= 10 { warn!( @@ -43,16 +48,24 @@ pub async fn process_video_payload( ); file_bytes = http_download_url_to_bytes(video_url) .await - .map_err(|e| anyhow!("Failed to download video on retry: {:?}", e))?; + .map_err(|err| { + warn!("Failed to download video on retry from {}: {:?}", video_url, err); + AdvancedCommonWebError::from_anyhow_error(err) + })?; } // Resolve mime type: magic bytes first, fal content_type as fallback. let metadata = resolve_file_metadata(&file_bytes, video_data.content_type.as_deref()) - .ok_or_else(|| anyhow!( - "Could not determine file type for video (bytes: {}, fal content_type: {:?})", - file_bytes.len(), - video_data.content_type, - ))?; + .ok_or_else(|| { + warn!( + "Could not determine file type for video (bytes: {}, fal content_type: {:?})", + file_bytes.len(), + video_data.content_type, + ); + AdvancedCommonWebError::server_error_with_message( + &format!("Could not determine file type for video (bytes: {}, fal content_type: {:?})", + file_bytes.len(), video_data.content_type)) + })?; info!("File type: {}, extension: {:?}, source: {:?}", metadata.mime_type, metadata.file_extension, metadata.source); @@ -60,26 +73,34 @@ pub async fn process_video_payload( let mime_type = metadata.mime_type.as_str(); let media_file_type = MediaFileType::try_from_mime_type(mime_type) - .ok_or_else(|| anyhow!("Unsupported media file type: {}", mime_type))?; + .ok_or_else(|| { + warn!("Unsupported media file type: {}", mime_type); + AdvancedCommonWebError::server_error_with_message( + &format!("Unsupported media file type: {}", mime_type)) + })?; let extension_with_period = metadata.file_extension.extension_with_period(); let file_size_bytes = file_bytes.len(); - let file_hash = sha256_hash_bytes(&file_bytes)?; + let file_hash = sha256_hash_bytes(&file_bytes) + .map_err(|e| { + warn!("Failed to hash video bytes: {:?}", e); + AdvancedCommonWebError::from_anyhow_error(e) + })?; let mut maybe_duration_millis = None; let mut maybe_frame_width = None; let mut maybe_frame_height = None; - + if let Ok(mut file) = NamedTempFile::new() { - // NB: Fallible + // NB: Fallible let _r = file.write_all(&file_bytes); - + if let Ok(video_info) = ffprobe_get_info(&file.path()) { maybe_duration_millis = video_info.duration .as_ref() .map(|duration| duration.millis as u64); - + maybe_frame_width = video_info.dimensions .as_ref() .map(|ref dims| dims.width as u32); @@ -98,7 +119,11 @@ pub async fn process_video_payload( public_upload_path.get_full_object_path_str(), file_bytes.as_ref(), &mime_type) - .await?; + .await + .map_err(|e| { + warn!("Failed to upload video to bucket: {:?}", e); + AdvancedCommonWebError::from_anyhow_error(e) + })?; let media_token = MediaFileInsertBuilder::new() .maybe_creator_user(job.maybe_creator_user_token.as_ref()) @@ -117,8 +142,12 @@ pub async fn process_video_payload( .checksum_sha2(&file_hash) .maybe_prompt_token(job.maybe_prompt_token.as_ref()) .insert_pool(&server_state.mysql_pool) - .await?; - + .await + .map_err(|e| { + warn!("Failed to insert video media file record: {:?}", e); + AdvancedCommonWebError::from_error(e) + })?; + info!("Video media file uploaded with token: {}", media_token); let thumbnail_task_result =