encode.rs (3695B)
1 #[cfg(not(feature = "std"))] 2 use alloc::{ 3 string::{String, ToString}, 4 vec::Vec, 5 }; 6 7 use radroots_event::{ 8 envelope::kind::KIND_PUBLIC_FILE_METADATA, 9 media::file_metadata::FileMetadata, 10 tag::name::{ 11 TAG_ALT, TAG_BLURHASH, TAG_DIMENSIONS, TAG_FALLBACK, TAG_MAGNET, TAG_MIME, 12 TAG_ORIGINAL_SHA256, TAG_SERVICE, TAG_SHA256, TAG_SIZE, TAG_SUMMARY, TAG_URL, 13 }, 14 }; 15 16 use crate::error::EventEncodeError; 17 use crate::field_helpers::{ 18 push_optional_tag, push_tag, validate_lowercase_hex_64, validate_non_empty_field, 19 }; 20 use crate::social_helpers::{dimensions_tag, push_thumbnail, validate_http_url}; 21 use radroots_event::wire::Nip01EventWireParts; 22 23 const DEFAULT_KIND: u32 = KIND_PUBLIC_FILE_METADATA; 24 25 pub fn file_metadata_build_tags( 26 metadata: &FileMetadata, 27 ) -> Result<Vec<Vec<String>>, EventEncodeError> { 28 validate_metadata(metadata)?; 29 let mut tags = Vec::new(); 30 push_tag(&mut tags, TAG_URL, metadata.url.as_str()); 31 push_tag(&mut tags, TAG_MIME, metadata.mime_type.as_str()); 32 push_tag(&mut tags, TAG_SHA256, metadata.sha256.as_str()); 33 push_optional_tag( 34 &mut tags, 35 TAG_ORIGINAL_SHA256, 36 metadata.original_sha256.as_deref(), 37 ); 38 if let Some(size) = metadata.size { 39 push_tag(&mut tags, TAG_SIZE, size.to_string()); 40 } 41 if let Some(dimensions) = metadata.dimensions.as_ref() { 42 push_tag(&mut tags, TAG_DIMENSIONS, dimensions_tag(dimensions)); 43 } 44 push_optional_tag(&mut tags, TAG_BLURHASH, metadata.blurhash.as_deref()); 45 if let Some(thumbnails) = metadata.thumbnails.as_ref() { 46 for thumbnail in thumbnails { 47 push_thumbnail(&mut tags, thumbnail); 48 } 49 } 50 push_optional_tag(&mut tags, TAG_SUMMARY, metadata.summary.as_deref()); 51 push_optional_tag(&mut tags, TAG_ALT, metadata.alt.as_deref()); 52 push_optional_tag(&mut tags, TAG_FALLBACK, metadata.fallback.as_deref()); 53 push_optional_tag(&mut tags, TAG_MAGNET, metadata.magnet.as_deref()); 54 if let Some(content_hashes) = metadata.content_hashes.as_ref() { 55 for hash in content_hashes { 56 push_optional_tag(&mut tags, "i", Some(hash.as_str())); 57 } 58 } 59 if let Some(services) = metadata.services.as_ref() { 60 for service in services { 61 push_optional_tag(&mut tags, TAG_SERVICE, Some(service.as_str())); 62 } 63 } 64 Ok(tags) 65 } 66 67 pub fn to_wire_parts(metadata: &FileMetadata) -> Result<Nip01EventWireParts, EventEncodeError> { 68 to_wire_parts_with_kind(metadata, DEFAULT_KIND) 69 } 70 71 pub fn to_wire_parts_with_kind( 72 metadata: &FileMetadata, 73 kind: u32, 74 ) -> Result<Nip01EventWireParts, EventEncodeError> { 75 if kind != DEFAULT_KIND { 76 return Err(EventEncodeError::InvalidKind(kind)); 77 } 78 Ok(Nip01EventWireParts { 79 kind, 80 content: metadata.content.clone().unwrap_or_default(), 81 tags: file_metadata_build_tags(metadata)?, 82 }) 83 } 84 85 fn validate_metadata(metadata: &FileMetadata) -> Result<(), EventEncodeError> { 86 validate_http_url(&metadata.url, "url")?; 87 validate_non_empty_field(&metadata.mime_type, "mime_type")?; 88 validate_lowercase_hex_64(&metadata.sha256, "sha256")?; 89 if let Some(hash) = metadata.original_sha256.as_deref() { 90 validate_lowercase_hex_64(hash, "original_sha256")?; 91 } 92 if let Some(dimensions) = metadata.dimensions.as_ref() 93 && (dimensions.width == 0 || dimensions.height == 0) 94 { 95 return Err(EventEncodeError::InvalidField("dimensions")); 96 } 97 if let Some(thumbnails) = metadata.thumbnails.as_ref() { 98 for thumbnail in thumbnails { 99 validate_http_url(&thumbnail.url, "thumb")?; 100 } 101 } 102 Ok(()) 103 }