decode.rs (4275B)
1 #[cfg(not(feature = "std"))] 2 use alloc::{string::String, vec::Vec}; 3 4 use radroots_events::{ 5 RadrootsNostrEvent, kinds::is_nip51_list_set_kind, list::RadrootsListEntry, 6 list_set::RadrootsListSet, 7 }; 8 9 use crate::error::EventParseError; 10 #[cfg(feature = "serde_json")] 11 use crate::list::decode::list_entries_from_tags; 12 use crate::parsed::{RadrootsParsedData, RadrootsParsedEvent}; 13 14 const TAG_D: &str = "d"; 15 const TAG_TITLE: &str = "title"; 16 const TAG_DESCRIPTION: &str = "description"; 17 const TAG_IMAGE: &str = "image"; 18 19 fn entry_from_tag(tag: &[String]) -> Result<RadrootsListEntry, EventParseError> { 20 let name = &tag[0]; 21 let value = &tag[1]; 22 if value.trim().is_empty() { 23 return Err(EventParseError::InvalidTag("tag")); 24 } 25 Ok(RadrootsListEntry { 26 tag: name.clone(), 27 values: tag[1..].to_vec(), 28 }) 29 } 30 31 fn take_first_non_empty(tag: &[String]) -> Option<String> { 32 tag.get(1).filter(|v| !v.trim().is_empty()).cloned() 33 } 34 35 pub fn list_set_from_tags( 36 kind: u32, 37 content: String, 38 tags: &[Vec<String>], 39 ) -> Result<RadrootsListSet, EventParseError> { 40 if !is_nip51_list_set_kind(kind) { 41 return Err(EventParseError::InvalidKind { 42 expected: "nip51 list set kind", 43 got: kind, 44 }); 45 } 46 let mut d_tag: Option<String> = None; 47 let mut title: Option<String> = None; 48 let mut description: Option<String> = None; 49 let mut image: Option<String> = None; 50 let mut entries = Vec::new(); 51 52 for tag in tags.iter().filter(|t| t.len() >= 2) { 53 let name = &tag[0]; 54 if name.trim().is_empty() { 55 return Err(EventParseError::InvalidTag("tag")); 56 } 57 match name.as_str() { 58 TAG_D => { 59 if d_tag.is_none() { 60 let value = &tag[1]; 61 if value.trim().is_empty() { 62 return Err(EventParseError::InvalidTag("d")); 63 } 64 d_tag = Some(value.clone()); 65 } 66 } 67 TAG_TITLE => { 68 if title.is_none() { 69 title = take_first_non_empty(tag); 70 } 71 } 72 TAG_DESCRIPTION => { 73 if description.is_none() { 74 description = take_first_non_empty(tag); 75 } 76 } 77 TAG_IMAGE => { 78 if image.is_none() { 79 image = take_first_non_empty(tag); 80 } 81 } 82 _ => { 83 entries.push(entry_from_tag(tag)?); 84 } 85 } 86 } 87 88 let d_tag = d_tag.ok_or(EventParseError::MissingTag("d"))?; 89 if !super::list_set_base64_id_is_valid(&d_tag) { 90 return Err(EventParseError::InvalidTag("d")); 91 } 92 Ok(RadrootsListSet { 93 d_tag, 94 content, 95 entries, 96 title, 97 description, 98 image, 99 }) 100 } 101 102 pub fn data_from_event( 103 id: String, 104 author: String, 105 published_at: u32, 106 kind: u32, 107 content: String, 108 tags: Vec<Vec<String>>, 109 ) -> Result<RadrootsParsedData<RadrootsListSet>, EventParseError> { 110 let list_set = list_set_from_tags(kind, content, &tags)?; 111 Ok(RadrootsParsedData::new( 112 id, 113 author, 114 published_at, 115 kind, 116 list_set, 117 )) 118 } 119 120 pub fn parsed_from_event( 121 id: String, 122 author: String, 123 published_at: u32, 124 kind: u32, 125 content: String, 126 tags: Vec<Vec<String>>, 127 sig: String, 128 ) -> Result<RadrootsParsedEvent<RadrootsListSet>, EventParseError> { 129 let data = data_from_event( 130 id.clone(), 131 author.clone(), 132 published_at, 133 kind, 134 content.clone(), 135 tags.clone(), 136 )?; 137 Ok(RadrootsParsedEvent { 138 event: RadrootsNostrEvent { 139 id, 140 author, 141 created_at: published_at, 142 kind, 143 content, 144 tags, 145 sig, 146 }, 147 data, 148 }) 149 } 150 151 #[cfg(feature = "serde_json")] 152 pub fn list_set_private_entries_from_json( 153 content: &str, 154 ) -> Result<Vec<RadrootsListEntry>, EventParseError> { 155 let tags: Vec<Vec<String>> = 156 serde_json::from_str(content).map_err(|_| EventParseError::InvalidJson("content"))?; 157 list_entries_from_tags(&tags) 158 }