encode.rs (3499B)
1 #[cfg(not(feature = "std"))] 2 use alloc::vec; 3 #[cfg(not(feature = "std"))] 4 use alloc::{ 5 format, 6 string::{String, ToString}, 7 vec::Vec, 8 }; 9 10 use radroots_event::envelope::kind::KIND_MESSAGE_FILE; 11 use radroots_event::social::message_file::{MessageFile, MessageFileDimensions}; 12 13 use crate::error::EventEncodeError; 14 use crate::message::tags::{build_recipient_tags, build_reply_tag, build_subject_tag}; 15 use radroots_event::wire::Nip01EventWireParts; 16 17 const DEFAULT_KIND: u32 = KIND_MESSAGE_FILE; 18 19 fn validate_required(value: &str, field: &'static str) -> Result<(), EventEncodeError> { 20 if value.trim().is_empty() { 21 return Err(EventEncodeError::EmptyRequiredField(field)); 22 } 23 Ok(()) 24 } 25 26 fn push_required_tag( 27 tags: &mut Vec<Vec<String>>, 28 key: &'static str, 29 value: &str, 30 field: &'static str, 31 ) -> Result<(), EventEncodeError> { 32 validate_required(value, field)?; 33 tags.push(vec![key.to_string(), value.to_string()]); 34 Ok(()) 35 } 36 37 fn push_optional_tag(tags: &mut Vec<Vec<String>>, key: &'static str, value: &Option<String>) { 38 if let Some(value) = value { 39 tags.push(vec![key.to_string(), value.clone()]); 40 } 41 } 42 43 fn push_dimensions_tag(tags: &mut Vec<Vec<String>>, dimensions: &Option<MessageFileDimensions>) { 44 if let Some(dimensions) = dimensions { 45 tags.push(vec![ 46 "dim".to_string(), 47 format!("{}x{}", dimensions.w, dimensions.h), 48 ]); 49 } 50 } 51 52 pub fn message_file_build_tags( 53 message: &MessageFile, 54 ) -> Result<Vec<Vec<String>>, EventEncodeError> { 55 let mut tags = build_recipient_tags(&message.recipients)?; 56 if let Some(tag) = build_reply_tag(&message.reply_to)? { 57 tags.push(tag); 58 } 59 if let Some(tag) = build_subject_tag(&message.subject)? { 60 tags.push(tag); 61 } 62 63 push_required_tag(&mut tags, "file-type", &message.file_type, "file_type")?; 64 push_required_tag( 65 &mut tags, 66 "encryption-algorithm", 67 &message.encryption_algorithm, 68 "encryption_algorithm", 69 )?; 70 push_required_tag( 71 &mut tags, 72 "decryption-key", 73 &message.decryption_key, 74 "decryption_key", 75 )?; 76 push_required_tag( 77 &mut tags, 78 "decryption-nonce", 79 &message.decryption_nonce, 80 "decryption_nonce", 81 )?; 82 push_required_tag(&mut tags, "x", &message.encrypted_hash, "encrypted_hash")?; 83 84 push_optional_tag(&mut tags, "ox", &message.original_hash); 85 if let Some(size) = message.size { 86 tags.push(vec!["size".to_string(), size.to_string()]); 87 } 88 push_dimensions_tag(&mut tags, &message.dimensions); 89 push_optional_tag(&mut tags, "blurhash", &message.blurhash); 90 push_optional_tag(&mut tags, "thumb", &message.thumb); 91 for fallback in &message.fallbacks { 92 validate_required(fallback, "fallback")?; 93 tags.push(vec!["fallback".to_string(), fallback.clone()]); 94 } 95 96 Ok(tags) 97 } 98 99 pub fn to_wire_parts(message: &MessageFile) -> Result<Nip01EventWireParts, EventEncodeError> { 100 validate_required(&message.file_url, "file_url")?; 101 let tags = message_file_build_tags(message)?; 102 Ok(Nip01EventWireParts { 103 kind: DEFAULT_KIND, 104 content: message.file_url.clone(), 105 tags, 106 }) 107 } 108 109 pub fn to_wire_parts_with_kind( 110 message: &MessageFile, 111 kind: u32, 112 ) -> Result<Nip01EventWireParts, EventEncodeError> { 113 if kind != DEFAULT_KIND { 114 return Err(EventEncodeError::InvalidKind(kind)); 115 } 116 to_wire_parts(message) 117 }