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 }