decode.rs (3495B)
1 #[cfg(not(feature = "std"))] 2 use alloc::{string::ToString, vec::Vec}; 3 4 use radroots_events::{ 5 RadrootsNostrEvent, 6 article::RadrootsArticle, 7 farm::RadrootsFarmRef, 8 kinds::{KIND_ARTICLE, KIND_FARM}, 9 social::RadrootsSocialFarmAnchor, 10 tags::{TAG_A, TAG_D, TAG_IMAGE, TAG_PUBLISHED_AT, TAG_SUMMARY, TAG_T, TAG_TITLE}, 11 }; 12 13 use crate::d_tag::validate_d_tag_tag; 14 use crate::error::EventParseError; 15 use crate::field_helpers::{ 16 parse_address_tag_with_kind, required_tag_value, tag_values, validate_non_empty_tag_value, 17 }; 18 use crate::parsed::{RadrootsParsedData, RadrootsParsedEvent}; 19 use crate::social_helpers::{first_tag_value, location_from_tags}; 20 21 const EXPECTED_KIND: &str = "30023"; 22 23 pub fn article_from_event( 24 kind: u32, 25 tags: &[Vec<String>], 26 content: &str, 27 ) -> Result<RadrootsArticle, EventParseError> { 28 if kind != KIND_ARTICLE { 29 return Err(EventParseError::InvalidKind { 30 expected: EXPECTED_KIND, 31 got: kind, 32 }); 33 } 34 validate_non_empty_tag_value(content, "content")?; 35 let d_tag = required_tag_value(tags, TAG_D)?; 36 validate_d_tag_tag(&d_tag, TAG_D)?; 37 let title = required_tag_value(tags, TAG_TITLE)?; 38 let published_at = first_tag_value(tags, TAG_PUBLISHED_AT) 39 .map(|value| { 40 value 41 .parse::<u64>() 42 .map_err(|err| EventParseError::InvalidNumber(TAG_PUBLISHED_AT, err)) 43 }) 44 .transpose()?; 45 let farm = parse_farm_anchor(tags)?; 46 Ok(RadrootsArticle { 47 d_tag, 48 title, 49 content: content.to_string(), 50 summary: first_tag_value(tags, TAG_SUMMARY), 51 image: first_tag_value(tags, TAG_IMAGE), 52 published_at, 53 farm, 54 location: location_from_tags(tags), 55 topics: non_empty_vec(tag_values(tags, TAG_T)?), 56 }) 57 } 58 59 pub fn data_from_event( 60 id: String, 61 author: String, 62 published_at: u32, 63 kind: u32, 64 content: String, 65 tags: Vec<Vec<String>>, 66 ) -> Result<RadrootsParsedData<RadrootsArticle>, EventParseError> { 67 let article = article_from_event(kind, &tags, &content)?; 68 Ok(RadrootsParsedData::new( 69 id, 70 author, 71 published_at, 72 kind, 73 article, 74 )) 75 } 76 77 pub fn parsed_from_event( 78 id: String, 79 author: String, 80 published_at: u32, 81 kind: u32, 82 content: String, 83 tags: Vec<Vec<String>>, 84 sig: String, 85 ) -> Result<RadrootsParsedEvent<RadrootsArticle>, EventParseError> { 86 let data = data_from_event( 87 id.clone(), 88 author.clone(), 89 published_at, 90 kind, 91 content.clone(), 92 tags.clone(), 93 )?; 94 Ok(RadrootsParsedEvent { 95 event: RadrootsNostrEvent { 96 id, 97 author, 98 created_at: published_at, 99 kind, 100 content, 101 tags, 102 sig, 103 }, 104 data, 105 }) 106 } 107 108 fn parse_farm_anchor( 109 tags: &[Vec<String>], 110 ) -> Result<Option<RadrootsSocialFarmAnchor>, EventParseError> { 111 let Some(value) = first_tag_value(tags, TAG_A) else { 112 return Ok(None); 113 }; 114 let address = parse_address_tag_with_kind(&value, KIND_FARM, TAG_A)?; 115 Ok(Some(RadrootsSocialFarmAnchor { 116 farm: RadrootsFarmRef { 117 pubkey: address.pubkey, 118 d_tag: address.d_tag, 119 }, 120 relays: None, 121 })) 122 } 123 124 fn non_empty_vec(values: Vec<String>) -> Option<Vec<String>> { 125 if values.is_empty() { 126 None 127 } else { 128 Some(values) 129 } 130 }