lib

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

encode.rs (3261B)


      1 #[cfg(not(feature = "std"))]
      2 use alloc::{string::String, vec::Vec};
      3 
      4 use radroots_events::{
      5     kinds::{KIND_LIST_READ_WRITE_RELAYS, is_nip51_list_set_kind, is_nip51_standard_list_kind},
      6     list::{RadrootsList, RadrootsListEntry},
      7     tags::TAG_R,
      8 };
      9 
     10 use crate::error::EventEncodeError;
     11 use crate::wire::WireEventParts;
     12 
     13 fn entry_tag(entry: &RadrootsListEntry) -> Result<Vec<String>, EventEncodeError> {
     14     if entry.tag.trim().is_empty() {
     15         return Err(EventEncodeError::EmptyRequiredField("entry.tag"));
     16     }
     17     let first = entry
     18         .values
     19         .first()
     20         .ok_or(EventEncodeError::EmptyRequiredField("entry.values"))?;
     21     if first.trim().is_empty() {
     22         return Err(EventEncodeError::EmptyRequiredField("entry.values"));
     23     }
     24     let mut tag = Vec::with_capacity(1 + entry.values.len());
     25     tag.push(entry.tag.clone());
     26     tag.extend(entry.values.iter().cloned());
     27     Ok(tag)
     28 }
     29 
     30 pub fn list_entries_to_tags(
     31     entries: &[RadrootsListEntry],
     32 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
     33     let mut tags = Vec::with_capacity(entries.len());
     34     for entry in entries {
     35         tags.push(entry_tag(entry)?);
     36     }
     37     Ok(tags)
     38 }
     39 
     40 pub fn list_build_tags(list: &RadrootsList) -> Result<Vec<Vec<String>>, EventEncodeError> {
     41     list_entries_to_tags(&list.entries)
     42 }
     43 
     44 pub fn to_wire_parts_with_kind(
     45     list: &RadrootsList,
     46     kind: u32,
     47 ) -> Result<WireEventParts, EventEncodeError> {
     48     if !is_supported_list_kind(kind) {
     49         return Err(EventEncodeError::InvalidKind(kind));
     50     }
     51     if kind == KIND_LIST_READ_WRITE_RELAYS {
     52         validate_relay_entries(&list.entries)?;
     53     }
     54     let tags = list_build_tags(list)?;
     55     Ok(WireEventParts {
     56         kind,
     57         content: list.content.clone(),
     58         tags,
     59     })
     60 }
     61 
     62 fn is_supported_list_kind(kind: u32) -> bool {
     63     is_nip51_standard_list_kind(kind) || is_nip51_list_set_kind(kind)
     64 }
     65 
     66 fn validate_relay_entries(entries: &[RadrootsListEntry]) -> Result<(), EventEncodeError> {
     67     if entries.is_empty() {
     68         return Err(EventEncodeError::EmptyRequiredField("relay.entries"));
     69     }
     70     for entry in entries {
     71         if entry.tag != TAG_R {
     72             return Err(EventEncodeError::InvalidField("relay.tag"));
     73         }
     74         let Some(url) = entry.values.first() else {
     75             return Err(EventEncodeError::EmptyRequiredField("relay.url"));
     76         };
     77         if !is_ws_relay_url(url) {
     78             return Err(EventEncodeError::InvalidField("relay.url"));
     79         }
     80         if entry.values.len() > 2 {
     81             return Err(EventEncodeError::InvalidField("relay.marker"));
     82         }
     83         if let Some(marker) = entry.values.get(1)
     84             && marker != "read"
     85             && marker != "write"
     86         {
     87             return Err(EventEncodeError::InvalidField("relay.marker"));
     88         }
     89     }
     90     Ok(())
     91 }
     92 
     93 fn is_ws_relay_url(value: &str) -> bool {
     94     (value.starts_with("wss://") && value.len() > "wss://".len())
     95         || (value.starts_with("ws://") && value.len() > "ws://".len())
     96 }
     97 
     98 #[cfg(feature = "serde_json")]
     99 pub fn list_private_entries_json(
    100     entries: &[RadrootsListEntry],
    101 ) -> Result<String, EventEncodeError> {
    102     let tags = list_entries_to_tags(entries)?;
    103     serde_json::to_string(&tags).map_err(|_| EventEncodeError::Json)
    104 }