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