lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

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 }