lib

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

encode.rs (5838B)


      1 #[cfg(not(feature = "std"))]
      2 use alloc::{format, string::ToString, vec, vec::Vec};
      3 
      4 use radroots_events::{
      5     kinds::{KIND_GENERIC_REPOST, KIND_POST, KIND_REPOST},
      6     repost::{RadrootsGenericRepost, RadrootsRepost},
      7     social::RadrootsSocialTarget,
      8     tags::{TAG_A, TAG_E, TAG_K, TAG_P},
      9 };
     10 
     11 use crate::error::EventEncodeError;
     12 use crate::field_helpers::{
     13     parse_address_tag, push_tag, validate_lowercase_hex_64, validate_non_empty_field,
     14 };
     15 use crate::wire::WireEventParts;
     16 
     17 pub fn repost_build_tags(repost: &RadrootsRepost) -> Result<Vec<Vec<String>>, EventEncodeError> {
     18     let mut tags = Vec::new();
     19     push_event_target(&mut tags, &repost.target, KIND_POST, "target")?;
     20     Ok(tags)
     21 }
     22 
     23 pub fn generic_repost_build_tags(
     24     repost: &RadrootsGenericRepost,
     25 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
     26     validate_generic_target_kind(repost.target_kind)?;
     27     let mut tags = Vec::new();
     28     push_generic_target(&mut tags, &repost.target, repost.target_kind)?;
     29     push_tag(&mut tags, TAG_K, repost.target_kind.to_string());
     30     Ok(tags)
     31 }
     32 
     33 pub fn repost_to_wire_parts(repost: &RadrootsRepost) -> Result<WireEventParts, EventEncodeError> {
     34     repost_to_wire_parts_with_kind(repost, KIND_REPOST)
     35 }
     36 
     37 pub fn generic_repost_to_wire_parts(
     38     repost: &RadrootsGenericRepost,
     39 ) -> Result<WireEventParts, EventEncodeError> {
     40     generic_repost_to_wire_parts_with_kind(repost, KIND_GENERIC_REPOST)
     41 }
     42 
     43 pub fn repost_to_wire_parts_with_kind(
     44     repost: &RadrootsRepost,
     45     kind: u32,
     46 ) -> Result<WireEventParts, EventEncodeError> {
     47     if kind != KIND_REPOST {
     48         return Err(EventEncodeError::InvalidKind(kind));
     49     }
     50     Ok(WireEventParts {
     51         kind,
     52         content: repost.content.clone().unwrap_or_default(),
     53         tags: repost_build_tags(repost)?,
     54     })
     55 }
     56 
     57 pub fn generic_repost_to_wire_parts_with_kind(
     58     repost: &RadrootsGenericRepost,
     59     kind: u32,
     60 ) -> Result<WireEventParts, EventEncodeError> {
     61     if kind != KIND_GENERIC_REPOST {
     62         return Err(EventEncodeError::InvalidKind(kind));
     63     }
     64     Ok(WireEventParts {
     65         kind,
     66         content: repost.content.clone().unwrap_or_default(),
     67         tags: generic_repost_build_tags(repost)?,
     68     })
     69 }
     70 
     71 fn push_event_target(
     72     tags: &mut Vec<Vec<String>>,
     73     target: &RadrootsSocialTarget,
     74     expected_kind: u32,
     75     field: &'static str,
     76 ) -> Result<(), EventEncodeError> {
     77     let RadrootsSocialTarget::Event {
     78         id,
     79         author,
     80         event_kind,
     81         relays,
     82     } = target
     83     else {
     84         return Err(EventEncodeError::InvalidField(field));
     85     };
     86     validate_lowercase_hex_64(id, "target.id")?;
     87     validate_event_kind(*event_kind, expected_kind)?;
     88     let mut event_tag = vec![TAG_E.to_string(), id.clone()];
     89     if let Some(relays) = relays.as_ref() {
     90         event_tag.extend(
     91             relays
     92                 .iter()
     93                 .filter(|relay| !relay.trim().is_empty())
     94                 .cloned(),
     95         );
     96     }
     97     tags.push(event_tag);
     98     if let Some(author) = author.as_deref() {
     99         validate_non_empty_field(author, "target.author")?;
    100         push_tag(tags, TAG_P, author);
    101     }
    102     Ok(())
    103 }
    104 
    105 fn push_generic_target(
    106     tags: &mut Vec<Vec<String>>,
    107     target: &RadrootsSocialTarget,
    108     expected_kind: u32,
    109 ) -> Result<(), EventEncodeError> {
    110     match target {
    111         RadrootsSocialTarget::Event {
    112             id,
    113             author,
    114             event_kind,
    115             relays,
    116         } => {
    117             validate_lowercase_hex_64(id, "target.id")?;
    118             validate_event_kind(*event_kind, expected_kind)?;
    119             let mut event_tag = vec![TAG_E.to_string(), id.clone()];
    120             if let Some(relays) = relays.as_ref() {
    121                 event_tag.extend(
    122                     relays
    123                         .iter()
    124                         .filter(|relay| !relay.trim().is_empty())
    125                         .cloned(),
    126                 );
    127             }
    128             tags.push(event_tag);
    129             if let Some(author) = author.as_deref() {
    130                 validate_non_empty_field(author, "target.author")?;
    131                 push_tag(tags, TAG_P, author);
    132             }
    133             Ok(())
    134         }
    135         RadrootsSocialTarget::Address {
    136             address,
    137             author,
    138             event_kind,
    139             relays,
    140         } => {
    141             let address = parse_address_tag(address, "target.address")
    142                 .map_err(|_| EventEncodeError::InvalidField("target.address"))?;
    143             if address.kind != expected_kind {
    144                 return Err(EventEncodeError::InvalidField("target_kind"));
    145             }
    146             validate_event_kind(*event_kind, expected_kind)?;
    147             let mut tag = vec![
    148                 TAG_A.to_string(),
    149                 format!("{}:{}:{}", address.kind, address.pubkey, address.d_tag),
    150             ];
    151             if let Some(relays) = relays.as_ref() {
    152                 tag.extend(
    153                     relays
    154                         .iter()
    155                         .filter(|relay| !relay.trim().is_empty())
    156                         .cloned(),
    157                 );
    158             }
    159             tags.push(tag);
    160             if let Some(author) = author.as_deref() {
    161                 validate_non_empty_field(author, "target.author")?;
    162             }
    163             Ok(())
    164         }
    165         RadrootsSocialTarget::External { .. } => Err(EventEncodeError::InvalidField("target")),
    166     }
    167 }
    168 
    169 fn validate_event_kind(
    170     event_kind: Option<u32>,
    171     expected_kind: u32,
    172 ) -> Result<(), EventEncodeError> {
    173     if event_kind == Some(expected_kind) {
    174         Ok(())
    175     } else {
    176         Err(EventEncodeError::InvalidField("target_kind"))
    177     }
    178 }
    179 
    180 fn validate_generic_target_kind(target_kind: u32) -> Result<(), EventEncodeError> {
    181     if target_kind == KIND_POST {
    182         Err(EventEncodeError::InvalidField("target_kind"))
    183     } else {
    184         Ok(())
    185     }
    186 }