encode.rs (5810B)
1 #[cfg(not(feature = "std"))] 2 use alloc::{ 3 format, 4 string::{String, ToString}, 5 vec, 6 vec::Vec, 7 }; 8 9 use radroots_event::{ 10 envelope::kind::{KIND_GENERIC_REPOST, KIND_POST, KIND_REPOST}, 11 post::repost::{GenericRepost, Repost}, 12 social::SocialTarget, 13 tag::name::{TAG_A, TAG_E, TAG_K, TAG_P}, 14 }; 15 16 use crate::error::EventEncodeError; 17 use crate::field_helpers::{ 18 parse_address_tag, push_tag, validate_lowercase_hex_64, validate_non_empty_field, 19 }; 20 use radroots_event::wire::Nip01EventWireParts; 21 22 pub fn repost_build_tags(repost: &Repost) -> Result<Vec<Vec<String>>, EventEncodeError> { 23 let mut tags = Vec::new(); 24 push_event_target(&mut tags, &repost.target, KIND_POST, "target")?; 25 Ok(tags) 26 } 27 28 pub fn generic_repost_build_tags( 29 repost: &GenericRepost, 30 ) -> Result<Vec<Vec<String>>, EventEncodeError> { 31 validate_generic_target_kind(repost.target_kind)?; 32 let mut tags = Vec::new(); 33 push_generic_target(&mut tags, &repost.target, repost.target_kind)?; 34 push_tag(&mut tags, TAG_K, repost.target_kind.to_string()); 35 Ok(tags) 36 } 37 38 pub fn repost_to_wire_parts(repost: &Repost) -> Result<Nip01EventWireParts, EventEncodeError> { 39 repost_to_wire_parts_with_kind(repost, KIND_REPOST) 40 } 41 42 pub fn generic_repost_to_wire_parts( 43 repost: &GenericRepost, 44 ) -> Result<Nip01EventWireParts, EventEncodeError> { 45 generic_repost_to_wire_parts_with_kind(repost, KIND_GENERIC_REPOST) 46 } 47 48 pub fn repost_to_wire_parts_with_kind( 49 repost: &Repost, 50 kind: u32, 51 ) -> Result<Nip01EventWireParts, EventEncodeError> { 52 if kind != KIND_REPOST { 53 return Err(EventEncodeError::InvalidKind(kind)); 54 } 55 Ok(Nip01EventWireParts { 56 kind, 57 content: repost.content.clone().unwrap_or_default(), 58 tags: repost_build_tags(repost)?, 59 }) 60 } 61 62 pub fn generic_repost_to_wire_parts_with_kind( 63 repost: &GenericRepost, 64 kind: u32, 65 ) -> Result<Nip01EventWireParts, EventEncodeError> { 66 if kind != KIND_GENERIC_REPOST { 67 return Err(EventEncodeError::InvalidKind(kind)); 68 } 69 Ok(Nip01EventWireParts { 70 kind, 71 content: repost.content.clone().unwrap_or_default(), 72 tags: generic_repost_build_tags(repost)?, 73 }) 74 } 75 76 fn push_event_target( 77 tags: &mut Vec<Vec<String>>, 78 target: &SocialTarget, 79 expected_kind: u32, 80 field: &'static str, 81 ) -> Result<(), EventEncodeError> { 82 let SocialTarget::Event { 83 id, 84 author, 85 event_kind, 86 relays, 87 } = target 88 else { 89 return Err(EventEncodeError::InvalidField(field)); 90 }; 91 validate_lowercase_hex_64(id, "target.id")?; 92 validate_event_kind(*event_kind, expected_kind)?; 93 let mut event_tag = vec![TAG_E.to_string(), id.clone()]; 94 if let Some(relays) = relays.as_ref() { 95 event_tag.extend( 96 relays 97 .iter() 98 .filter(|relay| !relay.trim().is_empty()) 99 .cloned(), 100 ); 101 } 102 tags.push(event_tag); 103 if let Some(author) = author.as_deref() { 104 validate_non_empty_field(author, "target.author")?; 105 push_tag(tags, TAG_P, author); 106 } 107 Ok(()) 108 } 109 110 fn push_generic_target( 111 tags: &mut Vec<Vec<String>>, 112 target: &SocialTarget, 113 expected_kind: u32, 114 ) -> Result<(), EventEncodeError> { 115 match target { 116 SocialTarget::Event { 117 id, 118 author, 119 event_kind, 120 relays, 121 } => { 122 validate_lowercase_hex_64(id, "target.id")?; 123 validate_event_kind(*event_kind, expected_kind)?; 124 let mut event_tag = vec![TAG_E.to_string(), id.clone()]; 125 if let Some(relays) = relays.as_ref() { 126 event_tag.extend( 127 relays 128 .iter() 129 .filter(|relay| !relay.trim().is_empty()) 130 .cloned(), 131 ); 132 } 133 tags.push(event_tag); 134 if let Some(author) = author.as_deref() { 135 validate_non_empty_field(author, "target.author")?; 136 push_tag(tags, TAG_P, author); 137 } 138 Ok(()) 139 } 140 SocialTarget::Address { 141 address, 142 author, 143 event_kind, 144 relays, 145 } => { 146 let address = parse_address_tag(address, "target.address") 147 .map_err(|_| EventEncodeError::InvalidField("target.address"))?; 148 if address.kind != expected_kind { 149 return Err(EventEncodeError::InvalidField("target_kind")); 150 } 151 validate_event_kind(*event_kind, expected_kind)?; 152 let mut tag = vec![ 153 TAG_A.to_string(), 154 format!("{}:{}:{}", address.kind, address.pubkey, address.d_tag), 155 ]; 156 if let Some(relays) = relays.as_ref() { 157 tag.extend( 158 relays 159 .iter() 160 .filter(|relay| !relay.trim().is_empty()) 161 .cloned(), 162 ); 163 } 164 tags.push(tag); 165 if let Some(author) = author.as_deref() { 166 validate_non_empty_field(author, "target.author")?; 167 } 168 Ok(()) 169 } 170 SocialTarget::External { .. } => Err(EventEncodeError::InvalidField("target")), 171 } 172 } 173 174 fn validate_event_kind( 175 event_kind: Option<u32>, 176 expected_kind: u32, 177 ) -> Result<(), EventEncodeError> { 178 if event_kind == Some(expected_kind) { 179 Ok(()) 180 } else { 181 Err(EventEncodeError::InvalidField("target_kind")) 182 } 183 } 184 185 fn validate_generic_target_kind(target_kind: u32) -> Result<(), EventEncodeError> { 186 if target_kind == KIND_POST { 187 Err(EventEncodeError::InvalidField("target_kind")) 188 } else { 189 Ok(()) 190 } 191 }