lib

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

event_ref.rs (5528B)


      1 #[cfg(not(feature = "std"))]
      2 use alloc::{
      3     string::{String, ToString},
      4     vec::Vec,
      5 };
      6 
      7 use radroots_events::RadrootsNostrEventRef;
      8 
      9 use crate::error::EventParseError;
     10 
     11 fn looks_like_relay_url(s: &str) -> bool {
     12     s.starts_with("ws://") || s.starts_with("wss://")
     13 }
     14 
     15 pub fn build_event_ref_tag(tag: &str, event: &RadrootsNostrEventRef) -> Vec<String> {
     16     let relays_len = event.relays.as_ref().map(|r| r.len()).unwrap_or(0);
     17     let mut out = Vec::with_capacity(5 + relays_len);
     18     out.push(tag.to_string());
     19     out.push(event.id.clone());
     20     out.push(event.author.clone());
     21     out.push(event.kind.to_string());
     22     out.push(event.d_tag.clone().unwrap_or_default());
     23     if let Some(relays) = &event.relays {
     24         out.extend(relays.iter().cloned());
     25     }
     26     out
     27 }
     28 
     29 pub fn parse_event_ref_tag(
     30     tag: &[String],
     31     tag_name: &'static str,
     32 ) -> Result<RadrootsNostrEventRef, EventParseError> {
     33     if tag.first().map(|s| s.as_str()) != Some(tag_name) {
     34         return Err(EventParseError::InvalidTag(tag_name));
     35     }
     36     let id = tag.get(1).ok_or(EventParseError::InvalidTag(tag_name))?;
     37     let author = tag.get(2).ok_or(EventParseError::InvalidTag(tag_name))?;
     38     let kind_s = tag.get(3).ok_or(EventParseError::InvalidTag(tag_name))?;
     39     let kind: u32 = kind_s
     40         .parse()
     41         .map_err(|e| EventParseError::InvalidNumber(tag_name, e))?;
     42 
     43     let (d_tag, relays_start) = match tag.get(4) {
     44         Some(v) if tag.len() == 5 && looks_like_relay_url(v) => (None, 4),
     45         Some(v) if v.is_empty() => (None, 5),
     46         Some(v) => (Some(v.clone()), 5),
     47         None => (None, 4),
     48     };
     49 
     50     let relays = if tag.len() > relays_start {
     51         Some(tag[relays_start..].to_vec())
     52     } else {
     53         None
     54     };
     55 
     56     Ok(RadrootsNostrEventRef {
     57         id: id.clone(),
     58         author: author.clone(),
     59         kind,
     60         d_tag,
     61         relays,
     62     })
     63 }
     64 
     65 pub fn find_event_ref_tag<'a>(
     66     tags: &'a [Vec<String>],
     67     tag_name: &'static str,
     68 ) -> Option<&'a Vec<String>> {
     69     tags.iter()
     70         .find(|t| t.first().map(|s| s.as_str()) == Some(tag_name))
     71 }
     72 
     73 pub fn push_nip10_ref_tags(
     74     tags: &mut Vec<Vec<String>>,
     75     event: &RadrootsNostrEventRef,
     76     tag_e: &'static str,
     77     tag_p: &'static str,
     78     tag_k: &'static str,
     79     tag_a: &'static str,
     80 ) {
     81     let relays_len = event.relays.as_ref().map(|r| r.len()).unwrap_or(0);
     82     let kind_str = event.kind.to_string();
     83 
     84     let mut e_tag = Vec::with_capacity(2 + relays_len);
     85     e_tag.push(tag_e.to_string());
     86     e_tag.push(event.id.clone());
     87     if let Some(relays) = &event.relays {
     88         e_tag.extend(relays.iter().cloned());
     89     }
     90     tags.push(e_tag);
     91 
     92     let p_tag = vec![tag_p.to_string(), event.author.clone()];
     93     tags.push(p_tag);
     94 
     95     let k_tag = vec![tag_k.to_string(), kind_str.clone()];
     96     tags.push(k_tag);
     97 
     98     if let Some(d_tag) = event.d_tag.as_deref().filter(|v| !v.is_empty()) {
     99         let mut addr = String::with_capacity(kind_str.len() + event.author.len() + d_tag.len() + 2);
    100         addr.push_str(&kind_str);
    101         addr.push(':');
    102         addr.push_str(&event.author);
    103         addr.push(':');
    104         addr.push_str(d_tag);
    105 
    106         let mut a_tag = Vec::with_capacity(2 + relays_len);
    107         a_tag.push(tag_a.to_string());
    108         a_tag.push(addr);
    109         if let Some(relays) = &event.relays {
    110             a_tag.extend(relays.iter().cloned());
    111         }
    112         tags.push(a_tag);
    113     }
    114 }
    115 
    116 pub fn parse_nip10_ref_tags(
    117     tags: &[Vec<String>],
    118     tag_e: &'static str,
    119     tag_p: &'static str,
    120     tag_k: &'static str,
    121     tag_a: &'static str,
    122 ) -> Result<RadrootsNostrEventRef, EventParseError> {
    123     let e_tag = find_event_ref_tag(tags, tag_e).ok_or(EventParseError::MissingTag(tag_e))?;
    124     let id = e_tag.get(1).ok_or(EventParseError::InvalidTag(tag_e))?;
    125     if id.trim().is_empty() {
    126         return Err(EventParseError::InvalidTag(tag_e));
    127     }
    128     let relays = if e_tag.len() > 2 {
    129         Some(e_tag[2..].to_vec())
    130     } else {
    131         None
    132     };
    133 
    134     let p_tag = find_event_ref_tag(tags, tag_p).ok_or(EventParseError::MissingTag(tag_p))?;
    135     let author = p_tag.get(1).ok_or(EventParseError::InvalidTag(tag_p))?;
    136     if author.trim().is_empty() {
    137         return Err(EventParseError::InvalidTag(tag_p));
    138     }
    139 
    140     let k_tag = find_event_ref_tag(tags, tag_k).ok_or(EventParseError::MissingTag(tag_k))?;
    141     let kind_key = k_tag.get(1).ok_or(EventParseError::InvalidTag(tag_k))?;
    142     let kind: u32 = kind_key
    143         .parse()
    144         .map_err(|e| EventParseError::InvalidNumber(tag_k, e))?;
    145 
    146     let mut d_tag: Option<String> = None;
    147     let mut addr_relays: Option<Vec<String>> = None;
    148     for tag in tags
    149         .iter()
    150         .filter(|t| t.first().map(|s| s.as_str()) == Some(tag_a))
    151     {
    152         let value = match tag.get(1) {
    153             Some(v) => v,
    154             None => continue,
    155         };
    156         let mut parts = value.splitn(3, ':');
    157         let kind_part = parts.next();
    158         let author_part = parts.next();
    159         let d_part = parts.next();
    160         if kind_part != Some(kind_key.as_str()) || author_part != Some(author.as_str()) {
    161             continue;
    162         }
    163         if let Some(d) = d_part
    164             && !d.is_empty()
    165         {
    166             d_tag = Some(d.to_string());
    167         }
    168         if tag.len() > 2 {
    169             addr_relays = Some(tag[2..].to_vec());
    170         }
    171         break;
    172     }
    173 
    174     let relays = relays.or(addr_relays);
    175 
    176     Ok(RadrootsNostrEventRef {
    177         id: id.clone(),
    178         author: author.clone(),
    179         kind,
    180         d_tag,
    181         relays,
    182     })
    183 }