lib

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

decode.rs (4022B)


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