lib

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

decode.rs (4714B)


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