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