decode.rs (5535B)
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_GENERIC_REPOST, KIND_POST, KIND_REPOST}, 9 post::repost::{GenericRepost, Repost}, 10 social::SocialTarget, 11 tag::name::{TAG_A, TAG_E, TAG_K, TAG_P}, 12 }; 13 14 use crate::error::EventParseError; 15 use crate::field_helpers::{parse_address_tag, required_tag_value, validate_lowercase_hex_64_tag}; 16 use crate::parsed::{RadrootsParsedData, RadrootsParsedEvent}; 17 use crate::social_helpers::first_tag_value; 18 19 pub fn repost_from_event( 20 kind: u32, 21 tags: &[Vec<String>], 22 content: &str, 23 ) -> Result<Repost, EventParseError> { 24 if kind != KIND_REPOST { 25 return Err(EventParseError::InvalidKind { 26 expected: "6", 27 got: kind, 28 }); 29 } 30 let event_tag = find_tag(tags, TAG_E).ok_or(EventParseError::MissingTag(TAG_E))?; 31 let id = event_tag 32 .get(1) 33 .cloned() 34 .ok_or(EventParseError::InvalidTag(TAG_E))?; 35 validate_lowercase_hex_64_tag(&id, TAG_E)?; 36 Ok(Repost { 37 target: SocialTarget::Event { 38 id, 39 author: first_tag_value(tags, TAG_P), 40 event_kind: Some(KIND_POST), 41 relays: relays_from_tag(event_tag, 2), 42 }, 43 content: optional_content(content), 44 }) 45 } 46 47 pub fn generic_repost_from_event( 48 kind: u32, 49 tags: &[Vec<String>], 50 content: &str, 51 ) -> Result<GenericRepost, EventParseError> { 52 if kind != KIND_GENERIC_REPOST { 53 return Err(EventParseError::InvalidKind { 54 expected: "16", 55 got: kind, 56 }); 57 } 58 let target_kind = required_tag_value(tags, TAG_K)? 59 .parse::<u32>() 60 .map_err(|err| EventParseError::InvalidNumber(TAG_K, err))?; 61 if target_kind == KIND_POST { 62 return Err(EventParseError::InvalidTag(TAG_K)); 63 } 64 let target = if let Some(tag) = find_tag(tags, TAG_A) { 65 let value = tag 66 .get(1) 67 .cloned() 68 .ok_or(EventParseError::InvalidTag(TAG_A))?; 69 let address = parse_address_tag(&value, TAG_A)?; 70 if address.kind != target_kind { 71 return Err(EventParseError::InvalidTag(TAG_A)); 72 } 73 SocialTarget::Address { 74 address: value, 75 author: Some(address.pubkey), 76 event_kind: Some(target_kind), 77 relays: relays_from_tag(tag, 2), 78 } 79 } else if let Some(tag) = find_tag(tags, TAG_E) { 80 let id = tag 81 .get(1) 82 .cloned() 83 .ok_or(EventParseError::InvalidTag(TAG_E))?; 84 validate_lowercase_hex_64_tag(&id, TAG_E)?; 85 SocialTarget::Event { 86 id, 87 author: first_tag_value(tags, TAG_P), 88 event_kind: Some(target_kind), 89 relays: relays_from_tag(tag, 2), 90 } 91 } else { 92 return Err(EventParseError::MissingTag(TAG_E)); 93 }; 94 Ok(GenericRepost { 95 target, 96 target_kind, 97 content: optional_content(content), 98 }) 99 } 100 101 pub fn repost_data_from_event( 102 id: String, 103 author: String, 104 published_at: u64, 105 kind: u32, 106 content: String, 107 tags: Vec<Vec<String>>, 108 ) -> Result<RadrootsParsedData<Repost>, EventParseError> { 109 let repost = repost_from_event(kind, &tags, &content)?; 110 Ok(RadrootsParsedData::new( 111 id, 112 author, 113 published_at, 114 kind, 115 repost, 116 )) 117 } 118 119 pub fn generic_repost_data_from_event( 120 id: String, 121 author: String, 122 published_at: u64, 123 kind: u32, 124 content: String, 125 tags: Vec<Vec<String>>, 126 ) -> Result<RadrootsParsedData<GenericRepost>, EventParseError> { 127 let repost = generic_repost_from_event(kind, &tags, &content)?; 128 Ok(RadrootsParsedData::new( 129 id, 130 author, 131 published_at, 132 kind, 133 repost, 134 )) 135 } 136 137 pub fn repost_parsed_from_event( 138 id: String, 139 author: String, 140 published_at: u64, 141 kind: u32, 142 content: String, 143 tags: Vec<Vec<String>>, 144 sig: String, 145 ) -> Result<RadrootsParsedEvent<Repost>, EventParseError> { 146 let data = repost_data_from_event( 147 id.clone(), 148 author.clone(), 149 published_at, 150 kind, 151 content.clone(), 152 tags.clone(), 153 )?; 154 RadrootsParsedEvent::from_event_parts(id, author, published_at, kind, content, tags, sig, data) 155 } 156 157 pub fn generic_repost_parsed_from_event( 158 id: String, 159 author: String, 160 published_at: u64, 161 kind: u32, 162 content: String, 163 tags: Vec<Vec<String>>, 164 sig: String, 165 ) -> Result<RadrootsParsedEvent<GenericRepost>, EventParseError> { 166 let data = generic_repost_data_from_event( 167 id.clone(), 168 author.clone(), 169 published_at, 170 kind, 171 content.clone(), 172 tags.clone(), 173 )?; 174 RadrootsParsedEvent::from_event_parts(id, author, published_at, kind, content, tags, sig, data) 175 } 176 177 fn find_tag<'a>(tags: &'a [Vec<String>], key: &'static str) -> Option<&'a Vec<String>> { 178 tags.iter() 179 .find(|tag| tag.first().map(|value| value.as_str()) == Some(key)) 180 } 181 182 fn relays_from_tag(tag: &[String], start: usize) -> Option<Vec<String>> { 183 let relays = tag 184 .iter() 185 .skip(start) 186 .filter(|value| !value.trim().is_empty()) 187 .cloned() 188 .collect::<Vec<_>>(); 189 if relays.is_empty() { 190 None 191 } else { 192 Some(relays) 193 } 194 } 195 196 fn optional_content(content: &str) -> Option<String> { 197 if content.is_empty() { 198 None 199 } else { 200 Some(content.to_string()) 201 } 202 }