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