From 0ecb780e3bd986674fc9a7a836aae5e9d5603247 Mon Sep 17 00:00:00 2001 From: remiroyc Date: Mon, 2 Sep 2024 23:34:46 +0200 Subject: [PATCH] fix(ark-metadata): upload file --- crates/ark-metadata/src/metadata_manager.rs | 79 ++++++++++++--------- crates/ark-metadata/src/utils.rs | 41 ++++++----- 2 files changed, 70 insertions(+), 50 deletions(-) diff --git a/crates/ark-metadata/src/metadata_manager.rs b/crates/ark-metadata/src/metadata_manager.rs index cba5c5675..07f9bcf74 100644 --- a/crates/ark-metadata/src/metadata_manager.rs +++ b/crates/ark-metadata/src/metadata_manager.rs @@ -16,7 +16,7 @@ use reqwest::Client as ReqwestClient; use starknet::core::types::{BlockId, BlockTag, FieldElement}; use starknet::macros::selector; use std::{str::FromStr, time::Duration}; -use tracing::{debug, error, trace}; +use tracing::{debug, error, trace, warn}; /// `MetadataManager` is responsible for managing metadata information related to tokens. /// It works with the underlying storage and Starknet client to fetch and update token metadata. @@ -285,43 +285,58 @@ impl<'a, T: Storage, C: StarknetClient, F: FileManager, E: ElasticsearchManager> .timeout(timeout) .send() .await?; + + if !response.status().is_success() { + warn!("Failed to fetch image from URL: {}", url); + return Err(anyhow!("Failed to fetch image from URL: {}", url)); + } + let headers = response.headers().clone(); let bytes = response.bytes().await?; let (content_type_from_headers, content_length) = extract_metadata_from_headers(&headers)?; - let (file_ext, content_type): (&str, &str) = match url.split('.').last() { - Some(fe) => { - let content_type = get_content_type_from_extension(fe); - (fe, content_type) - } - None => { - let file_extension = - file_extension_from_mime_type(content_type_from_headers.as_str()); - (file_extension, content_type_from_headers.as_str()) - } - }; - - debug!( - "Image: Content-Type={}, Content-Length={:?}, File-Ext={}", - content_type, content_length, file_ext - ); - - let media_key = self - .file_manager - .save(&FileInfo { - name: format!("{}.{}", token_id, file_ext), - content: bytes.to_vec(), - dir_path: None, + if let Some(last_part) = url.split('/').last() { + let (file_name, content_type) = if last_part.contains('.') { + if let Some(file_extension) = last_part.split('.').last() { + let content_type = get_content_type_from_extension(file_extension); + (file_extension.to_string(), content_type.to_string()) + } else { + return Err(anyhow!("Failed to extract file extension from URL")); + } + } else { + match file_extension_from_mime_type(content_type_from_headers.as_str()) { + Some(file_extension) => { + let file_name = format!("{}.{}", token_id, file_extension); + (file_name, file_extension.to_string()) + } + None => (token_id.to_string(), content_type_from_headers), + } + }; + + debug!( + "Image: Content-Type={}, Content-Length={:?}, Filename={:?}", + content_type, content_length, file_name + ); + + let media_key = self + .file_manager + .save(&FileInfo { + name: file_name.clone(), + content: bytes.to_vec(), + dir_path: None, + }) + .await?; + + Ok(MetadataMedia { + file_type: content_type, + content_length, + is_cache_updated: true, + media_key: Some(media_key), }) - .await?; - - Ok(MetadataMedia { - file_type: content_type.to_string(), - content_length, - is_cache_updated: true, - media_key: Some(media_key), - }) + } else { + Err(anyhow!("Failed to extract file name from URL")) + } } } } diff --git a/crates/ark-metadata/src/utils.rs b/crates/ark-metadata/src/utils.rs index 3fa3e2468..dda2f2fb5 100644 --- a/crates/ark-metadata/src/utils.rs +++ b/crates/ark-metadata/src/utils.rs @@ -10,7 +10,7 @@ use reqwest::Client; use serde_json::Value; use std::str::FromStr; use std::time::Duration; -use tracing::{debug, error, trace}; +use tracing::{debug, error, trace, warn}; pub async fn get_token_metadata( client: &Client, @@ -19,7 +19,8 @@ pub async fn get_token_metadata( request_timeout_duration: Duration, request_referrer: &str, ) -> Result { - let metadata_type = get_metadata_type(uri); + let parsed_uri = uri.replace("https://gateway.pinata.cloud/ipfs/", "ipfs://"); + let metadata_type = get_metadata_type(parsed_uri.as_str()); let metadata = match metadata_type { MetadataType::Ipfs(uri) => { let ipfs_hash = uri.trim_start_matches("ipfs://"); @@ -129,22 +130,25 @@ async fn fetch_metadata( } } -pub fn file_extension_from_mime_type(mime_type: &str) -> &str { +pub fn file_extension_from_mime_type(mime_type: &str) -> Option<&str> { match mime_type { - "model/gltf-binary" => "glb", - "image/png" => "png", - "image/jpeg" => "jpg", - "image/gif" => "gif", - "image/bmp" => "bmp", - "image/webp" => "webp", - "image/svg+xml" => "svg", - "video/mp4" => "mp4", - "video/quicktime" => "mov", - "video/x-msvideo" => "avi", - "video/x-matroska" => "mkv", - "video/ogg" => "ogv", - "video/webm" => "webm", - _ => "", + "model/gltf-binary" => Some("glb"), + "image/png" => Some("png"), + "image/jpeg" => Some("jpg"), + "image/gif" => Some("gif"), + "image/bmp" => Some("bmp"), + "image/webp" => Some("webp"), + "image/svg+xml" => Some("svg"), + "video/mp4" => Some("mp4"), + "video/quicktime" => Some("mov"), + "video/x-msvideo" => Some("avi"), + "video/x-matroska" => Some("mkv"), + "video/ogg" => Some("ogv"), + "video/webm" => Some("webm"), + _ => { + warn!("Unknown MIME type: {}", mime_type); + None + } } } @@ -194,7 +198,8 @@ fn fetch_onchain_metadata(uri: &str) -> Result { image: json_value .get("image") .and_then(|v| v.as_str()) - .map(String::from), + .map(String::from) + .map(|image| image.replace("https://gateway.pinata.cloud/ipfs/", "ipfs://")), description: json_value .get("description") .and_then(|v| v.as_str())