lib

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

encode.rs (5810B)


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