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