lib

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

decode.rs (5535B)


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