lib

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

decode.rs (4965B)


      1 #![cfg(feature = "serde_json")]
      2 
      3 #[cfg(not(feature = "std"))]
      4 use alloc::{
      5     string::{String, ToString},
      6     vec::Vec,
      7 };
      8 
      9 use radroots_events::{
     10     RadrootsNostrEvent,
     11     farm_workspace::{
     12         KIND_FARM_WORKSPACE_MANIFEST, RADROOTS_FARM_WORKSPACE_TAG, RadrootsFarmWorkspaceManifest,
     13     },
     14     kinds::KIND_FARM,
     15     tags::{TAG_A, TAG_D, TAG_H, TAG_P, TAG_T},
     16 };
     17 
     18 use crate::d_tag::validate_d_tag_tag;
     19 use crate::error::EventParseError;
     20 use crate::farm_workspace::encode::validate_manifest;
     21 use crate::field_helpers::{
     22     optional_tag_value, parse_address_tag_with_kind, required_tag_value, tag_values,
     23 };
     24 use crate::parsed::{RadrootsParsedData, RadrootsParsedEvent};
     25 
     26 const EXPECTED_KIND: &str = "30078";
     27 
     28 pub fn farm_workspace_from_event(
     29     kind: u32,
     30     tags: &[Vec<String>],
     31     content: &str,
     32 ) -> Result<RadrootsFarmWorkspaceManifest, EventParseError> {
     33     if kind != KIND_FARM_WORKSPACE_MANIFEST {
     34         return Err(EventParseError::InvalidKind {
     35             expected: EXPECTED_KIND,
     36             got: kind,
     37         });
     38     }
     39     if content.trim().is_empty() {
     40         return Err(EventParseError::InvalidJson("content"));
     41     }
     42     let d_tag = required_tag_value(tags, TAG_D)?;
     43     validate_d_tag_tag(&d_tag, TAG_D)?;
     44     let farm_group_id = required_tag_value(tags, TAG_H)?;
     45     let manifest: RadrootsFarmWorkspaceManifest =
     46         serde_json::from_str(content).map_err(|_| EventParseError::InvalidJson("content"))?;
     47     validate_manifest(&manifest).map_err(encode_error_to_parse_error)?;
     48 
     49     if manifest.d_tag != d_tag {
     50         return Err(EventParseError::InvalidTag(TAG_D));
     51     }
     52     if manifest.farm_group_id != farm_group_id {
     53         return Err(EventParseError::InvalidTag(TAG_H));
     54     }
     55     if let Some(owner_pubkey) = optional_tag_value(tags, TAG_P)?
     56         && owner_pubkey != manifest.owner_pubkey
     57     {
     58         return Err(EventParseError::InvalidTag(TAG_P));
     59     }
     60     let marker_tags = tag_values(tags, TAG_T)?;
     61     if !marker_tags
     62         .iter()
     63         .any(|value| value == RADROOTS_FARM_WORKSPACE_TAG)
     64     {
     65         return Err(EventParseError::MissingTag(TAG_T));
     66     }
     67     if let Some(farm) = manifest.farm.as_ref() {
     68         let farm_address = optional_tag_value(tags, TAG_A)?;
     69         if let Some(value) = farm_address {
     70             let address = parse_address_tag_with_kind(&value, KIND_FARM, TAG_A)?;
     71             if address.pubkey != farm.pubkey || address.d_tag != farm.d_tag {
     72                 return Err(EventParseError::InvalidTag(TAG_A));
     73             }
     74         }
     75     }
     76 
     77     Ok(manifest)
     78 }
     79 
     80 pub fn data_from_event(
     81     id: String,
     82     author: String,
     83     published_at: u32,
     84     kind: u32,
     85     content: String,
     86     tags: Vec<Vec<String>>,
     87 ) -> Result<RadrootsParsedData<RadrootsFarmWorkspaceManifest>, EventParseError> {
     88     let manifest = farm_workspace_from_event(kind, &tags, &content)?;
     89     Ok(RadrootsParsedData::new(
     90         id,
     91         author,
     92         published_at,
     93         kind,
     94         manifest,
     95     ))
     96 }
     97 
     98 pub fn parsed_from_event(
     99     id: String,
    100     author: String,
    101     published_at: u32,
    102     kind: u32,
    103     content: String,
    104     tags: Vec<Vec<String>>,
    105     sig: String,
    106 ) -> Result<RadrootsParsedEvent<RadrootsFarmWorkspaceManifest>, EventParseError> {
    107     let data = data_from_event(
    108         id.clone(),
    109         author.clone(),
    110         published_at,
    111         kind,
    112         content.clone(),
    113         tags.clone(),
    114     )?;
    115     Ok(RadrootsParsedEvent {
    116         event: RadrootsNostrEvent {
    117             id,
    118             author,
    119             created_at: published_at,
    120             kind,
    121             content,
    122             tags,
    123             sig,
    124         },
    125         data,
    126     })
    127 }
    128 
    129 fn encode_error_to_parse_error(error: crate::error::EventEncodeError) -> EventParseError {
    130     match error {
    131         crate::error::EventEncodeError::InvalidKind(kind) => EventParseError::InvalidKind {
    132             expected: EXPECTED_KIND,
    133             got: kind,
    134         },
    135         crate::error::EventEncodeError::EmptyRequiredField(field)
    136         | crate::error::EventEncodeError::InvalidField(field) => match field {
    137             "d_tag" | "farm.d_tag" => EventParseError::InvalidTag(TAG_D),
    138             "farm_group_id" => EventParseError::InvalidTag(TAG_H),
    139             "owner_pubkey" => EventParseError::InvalidTag(TAG_P),
    140             _ => EventParseError::InvalidJson(field),
    141         },
    142         crate::error::EventEncodeError::Json => EventParseError::InvalidJson("content"),
    143     }
    144 }
    145 
    146 #[cfg(test)]
    147 mod tests {
    148     use super::*;
    149     use crate::error::EventEncodeError;
    150 
    151     #[test]
    152     fn encode_error_mapper_covers_kind_and_json_edges() {
    153         assert!(matches!(
    154             encode_error_to_parse_error(EventEncodeError::InvalidKind(1)),
    155             EventParseError::InvalidKind {
    156                 expected: EXPECTED_KIND,
    157                 got: 1
    158             }
    159         ));
    160         assert!(matches!(
    161             encode_error_to_parse_error(EventEncodeError::Json),
    162             EventParseError::InvalidJson("content")
    163         ));
    164     }
    165 }