lib

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

decode.rs (5921B)


      1 #[cfg(not(feature = "std"))]
      2 use alloc::{string::ToString, vec::Vec};
      3 
      4 use radroots_events::{
      5     RadrootsNostrEvent,
      6     kinds::{KIND_GENERIC_REPOST, KIND_POST, KIND_REPOST},
      7     repost::{RadrootsGenericRepost, RadrootsRepost},
      8     social::RadrootsSocialTarget,
      9     tags::{TAG_A, TAG_E, TAG_K, TAG_P},
     10 };
     11 
     12 use crate::error::EventParseError;
     13 use crate::field_helpers::{parse_address_tag, required_tag_value, validate_lowercase_hex_64_tag};
     14 use crate::parsed::{RadrootsParsedData, RadrootsParsedEvent};
     15 use crate::social_helpers::first_tag_value;
     16 
     17 pub fn repost_from_event(
     18     kind: u32,
     19     tags: &[Vec<String>],
     20     content: &str,
     21 ) -> Result<RadrootsRepost, EventParseError> {
     22     if kind != KIND_REPOST {
     23         return Err(EventParseError::InvalidKind {
     24             expected: "6",
     25             got: kind,
     26         });
     27     }
     28     let event_tag = find_tag(tags, TAG_E).ok_or(EventParseError::MissingTag(TAG_E))?;
     29     let id = event_tag
     30         .get(1)
     31         .cloned()
     32         .ok_or(EventParseError::InvalidTag(TAG_E))?;
     33     validate_lowercase_hex_64_tag(&id, TAG_E)?;
     34     Ok(RadrootsRepost {
     35         target: RadrootsSocialTarget::Event {
     36             id,
     37             author: first_tag_value(tags, TAG_P),
     38             event_kind: Some(KIND_POST),
     39             relays: relays_from_tag(event_tag, 2),
     40         },
     41         content: optional_content(content),
     42     })
     43 }
     44 
     45 pub fn generic_repost_from_event(
     46     kind: u32,
     47     tags: &[Vec<String>],
     48     content: &str,
     49 ) -> Result<RadrootsGenericRepost, EventParseError> {
     50     if kind != KIND_GENERIC_REPOST {
     51         return Err(EventParseError::InvalidKind {
     52             expected: "16",
     53             got: kind,
     54         });
     55     }
     56     let target_kind = required_tag_value(tags, TAG_K)?
     57         .parse::<u32>()
     58         .map_err(|err| EventParseError::InvalidNumber(TAG_K, err))?;
     59     if target_kind == KIND_POST {
     60         return Err(EventParseError::InvalidTag(TAG_K));
     61     }
     62     let target = if let Some(tag) = find_tag(tags, TAG_A) {
     63         let value = tag
     64             .get(1)
     65             .cloned()
     66             .ok_or(EventParseError::InvalidTag(TAG_A))?;
     67         let address = parse_address_tag(&value, TAG_A)?;
     68         if address.kind != target_kind {
     69             return Err(EventParseError::InvalidTag(TAG_A));
     70         }
     71         RadrootsSocialTarget::Address {
     72             address: value,
     73             author: Some(address.pubkey),
     74             event_kind: Some(target_kind),
     75             relays: relays_from_tag(tag, 2),
     76         }
     77     } else if let Some(tag) = find_tag(tags, TAG_E) {
     78         let id = tag
     79             .get(1)
     80             .cloned()
     81             .ok_or(EventParseError::InvalidTag(TAG_E))?;
     82         validate_lowercase_hex_64_tag(&id, TAG_E)?;
     83         RadrootsSocialTarget::Event {
     84             id,
     85             author: first_tag_value(tags, TAG_P),
     86             event_kind: Some(target_kind),
     87             relays: relays_from_tag(tag, 2),
     88         }
     89     } else {
     90         return Err(EventParseError::MissingTag(TAG_E));
     91     };
     92     Ok(RadrootsGenericRepost {
     93         target,
     94         target_kind,
     95         content: optional_content(content),
     96     })
     97 }
     98 
     99 pub fn repost_data_from_event(
    100     id: String,
    101     author: String,
    102     published_at: u32,
    103     kind: u32,
    104     content: String,
    105     tags: Vec<Vec<String>>,
    106 ) -> Result<RadrootsParsedData<RadrootsRepost>, EventParseError> {
    107     let repost = repost_from_event(kind, &tags, &content)?;
    108     Ok(RadrootsParsedData::new(
    109         id,
    110         author,
    111         published_at,
    112         kind,
    113         repost,
    114     ))
    115 }
    116 
    117 pub fn generic_repost_data_from_event(
    118     id: String,
    119     author: String,
    120     published_at: u32,
    121     kind: u32,
    122     content: String,
    123     tags: Vec<Vec<String>>,
    124 ) -> Result<RadrootsParsedData<RadrootsGenericRepost>, EventParseError> {
    125     let repost = generic_repost_from_event(kind, &tags, &content)?;
    126     Ok(RadrootsParsedData::new(
    127         id,
    128         author,
    129         published_at,
    130         kind,
    131         repost,
    132     ))
    133 }
    134 
    135 pub fn repost_parsed_from_event(
    136     id: String,
    137     author: String,
    138     published_at: u32,
    139     kind: u32,
    140     content: String,
    141     tags: Vec<Vec<String>>,
    142     sig: String,
    143 ) -> Result<RadrootsParsedEvent<RadrootsRepost>, EventParseError> {
    144     let data = repost_data_from_event(
    145         id.clone(),
    146         author.clone(),
    147         published_at,
    148         kind,
    149         content.clone(),
    150         tags.clone(),
    151     )?;
    152     Ok(RadrootsParsedEvent {
    153         event: RadrootsNostrEvent {
    154             id,
    155             author,
    156             created_at: published_at,
    157             kind,
    158             content,
    159             tags,
    160             sig,
    161         },
    162         data,
    163     })
    164 }
    165 
    166 pub fn generic_repost_parsed_from_event(
    167     id: String,
    168     author: String,
    169     published_at: u32,
    170     kind: u32,
    171     content: String,
    172     tags: Vec<Vec<String>>,
    173     sig: String,
    174 ) -> Result<RadrootsParsedEvent<RadrootsGenericRepost>, EventParseError> {
    175     let data = generic_repost_data_from_event(
    176         id.clone(),
    177         author.clone(),
    178         published_at,
    179         kind,
    180         content.clone(),
    181         tags.clone(),
    182     )?;
    183     Ok(RadrootsParsedEvent {
    184         event: RadrootsNostrEvent {
    185             id,
    186             author,
    187             created_at: published_at,
    188             kind,
    189             content,
    190             tags,
    191             sig,
    192         },
    193         data,
    194     })
    195 }
    196 
    197 fn find_tag<'a>(tags: &'a [Vec<String>], key: &'static str) -> Option<&'a Vec<String>> {
    198     tags.iter()
    199         .find(|tag| tag.first().map(|value| value.as_str()) == Some(key))
    200 }
    201 
    202 fn relays_from_tag(tag: &[String], start: usize) -> Option<Vec<String>> {
    203     let relays = tag
    204         .iter()
    205         .skip(start)
    206         .filter(|value| !value.trim().is_empty())
    207         .cloned()
    208         .collect::<Vec<_>>();
    209     if relays.is_empty() {
    210         None
    211     } else {
    212         Some(relays)
    213     }
    214 }
    215 
    216 fn optional_content(content: &str) -> Option<String> {
    217     if content.is_empty() {
    218         None
    219     } else {
    220         Some(content.to_string())
    221     }
    222 }