decode.rs (4773B)
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_REACTION, post::reaction::Reaction, social::SocialTarget, 9 tag::name::TAG_E_ROOT, 10 }; 11 12 use crate::error::EventParseError; 13 use crate::field_helpers::{parse_address_tag, validate_lowercase_hex_64_tag}; 14 use crate::parsed::{RadrootsParsedData, RadrootsParsedEvent}; 15 16 const DEFAULT_KIND: u32 = KIND_REACTION; 17 18 pub fn reaction_from_tags( 19 kind: u32, 20 tags: &[Vec<String>], 21 content: &str, 22 ) -> Result<Reaction, EventParseError> { 23 if kind != DEFAULT_KIND { 24 return Err(EventParseError::InvalidKind { 25 expected: "7", 26 got: kind, 27 }); 28 } 29 if tags 30 .iter() 31 .any(|tag| tag.first().map(|value| value.as_str()) == Some(TAG_E_ROOT)) 32 { 33 return Err(EventParseError::InvalidTag(TAG_E_ROOT)); 34 } 35 let target = parse_reaction_target(tags)?; 36 Ok(Reaction { 37 target, 38 content: content.to_string(), 39 }) 40 } 41 42 pub fn data_from_event( 43 id: String, 44 author: String, 45 published_at: u64, 46 kind: u32, 47 content: String, 48 tags: Vec<Vec<String>>, 49 ) -> Result<RadrootsParsedData<Reaction>, EventParseError> { 50 let reaction = reaction_from_tags(kind, &tags, &content)?; 51 Ok(RadrootsParsedData::new( 52 id, 53 author, 54 published_at, 55 kind, 56 reaction, 57 )) 58 } 59 60 pub fn parsed_from_event( 61 id: String, 62 author: String, 63 published_at: u64, 64 kind: u32, 65 content: String, 66 tags: Vec<Vec<String>>, 67 sig: String, 68 ) -> Result<RadrootsParsedEvent<Reaction>, EventParseError> { 69 let data = data_from_event( 70 id.clone(), 71 author.clone(), 72 published_at, 73 kind, 74 content.clone(), 75 tags.clone(), 76 )?; 77 RadrootsParsedEvent::from_event_parts(id, author, published_at, kind, content, tags, sig, data) 78 } 79 80 fn parse_reaction_target(tags: &[Vec<String>]) -> Result<SocialTarget, EventParseError> { 81 let event_tag = find_tag(tags, "e"); 82 let address_tag = find_tag(tags, "a"); 83 match (event_tag, address_tag) { 84 (Some(_), Some(_)) => Err(EventParseError::InvalidTag("e")), 85 (None, None) => Err(EventParseError::MissingTag("e")), 86 (Some(tag), None) => { 87 let id = tag 88 .get(1) 89 .cloned() 90 .ok_or(EventParseError::InvalidTag("e"))?; 91 validate_lowercase_hex_64_tag(&id, "e")?; 92 let relays = if tag.len() > 2 { 93 Some(tag[2..].to_vec()) 94 } else { 95 None 96 }; 97 Ok(SocialTarget::Event { 98 id, 99 author: optional_tag_value(tags, "p")?, 100 event_kind: optional_numeric_tag(tags, "k")?, 101 relays, 102 }) 103 } 104 (None, Some(tag)) => { 105 let value = tag 106 .get(1) 107 .cloned() 108 .ok_or(EventParseError::InvalidTag("a"))?; 109 let address = parse_address_tag(&value, "a")?; 110 let kind = optional_numeric_tag(tags, "k")?.unwrap_or(address.kind); 111 if kind != address.kind { 112 return Err(EventParseError::InvalidTag("k")); 113 } 114 let author = optional_tag_value(tags, "p")?.unwrap_or_else(|| address.pubkey.clone()); 115 if author != address.pubkey { 116 return Err(EventParseError::InvalidTag("p")); 117 } 118 let relays = if tag.len() > 2 { 119 Some(tag[2..].to_vec()) 120 } else { 121 None 122 }; 123 Ok(SocialTarget::Address { 124 address: value, 125 author: Some(author), 126 event_kind: Some(kind), 127 relays, 128 }) 129 } 130 } 131 } 132 133 fn find_tag<'a>(tags: &'a [Vec<String>], key: &'static str) -> Option<&'a Vec<String>> { 134 tags.iter() 135 .find(|tag| tag.first().map(|value| value.as_str()) == Some(key)) 136 } 137 138 fn optional_tag_value( 139 tags: &[Vec<String>], 140 key: &'static str, 141 ) -> Result<Option<String>, EventParseError> { 142 let Some(tag) = find_tag(tags, key) else { 143 return Ok(None); 144 }; 145 let value = tag 146 .get(1) 147 .cloned() 148 .ok_or(EventParseError::InvalidTag(key))?; 149 if value.trim().is_empty() { 150 return Err(EventParseError::InvalidTag(key)); 151 } 152 Ok(Some(value)) 153 } 154 155 fn optional_numeric_tag( 156 tags: &[Vec<String>], 157 key: &'static str, 158 ) -> Result<Option<u32>, EventParseError> { 159 optional_tag_value(tags, key)? 160 .map(|value| { 161 value 162 .parse::<u32>() 163 .map_err(|err| EventParseError::InvalidNumber(key, err)) 164 }) 165 .transpose() 166 }