encode.rs (4271B)
1 #[cfg(not(feature = "std"))] 2 use alloc::{ 3 string::{String, ToString}, 4 vec::Vec, 5 }; 6 7 #[cfg(feature = "serde_json")] 8 use radroots_events::farm_crdt::KIND_FARM_CRDT_CHANGE; 9 use radroots_events::{ 10 farm_crdt::{RADROOTS_FARM_CRDT_CHANGE_SCHEMA, RADROOTS_FARM_CRDT_TAG, RadrootsFarmCrdtChange}, 11 farm_workspace::KIND_FARM_WORKSPACE_MANIFEST, 12 tags::{TAG_A, TAG_D, TAG_H, TAG_P, TAG_T}, 13 }; 14 15 use crate::d_tag::validate_d_tag; 16 use crate::error::EventEncodeError; 17 use crate::field_helpers::{ 18 address_string, push_optional_tag, push_tag, validate_non_empty_base64url, 19 validate_non_empty_field, 20 }; 21 #[cfg(feature = "serde_json")] 22 use crate::wire::WireEventParts; 23 24 pub fn farm_crdt_change_build_tags( 25 change: &RadrootsFarmCrdtChange, 26 ) -> Result<Vec<Vec<String>>, EventEncodeError> { 27 farm_crdt_change_build_tags_with_author(change, None) 28 } 29 30 pub fn farm_crdt_change_build_tags_with_author( 31 change: &RadrootsFarmCrdtChange, 32 author_pubkey: Option<&str>, 33 ) -> Result<Vec<Vec<String>>, EventEncodeError> { 34 validate_change(change)?; 35 if let Some(author_pubkey) = author_pubkey { 36 validate_non_empty_field(author_pubkey, "author_pubkey")?; 37 } 38 let workspace = address_string( 39 KIND_FARM_WORKSPACE_MANIFEST, 40 &change.workspace.pubkey, 41 &change.workspace.d_tag, 42 "workspace", 43 )?; 44 let mut tags = Vec::new(); 45 push_tag(&mut tags, TAG_H, change.farm_group_id.as_str()); 46 push_tag(&mut tags, TAG_D, change.document_id.as_str()); 47 push_tag(&mut tags, TAG_A, workspace); 48 push_optional_tag(&mut tags, TAG_P, author_pubkey); 49 push_tag(&mut tags, TAG_T, RADROOTS_FARM_CRDT_TAG); 50 Ok(tags) 51 } 52 53 #[cfg(feature = "serde_json")] 54 pub fn to_wire_parts(change: &RadrootsFarmCrdtChange) -> Result<WireEventParts, EventEncodeError> { 55 to_wire_parts_with_kind(change, KIND_FARM_CRDT_CHANGE) 56 } 57 58 #[cfg(feature = "serde_json")] 59 pub fn to_wire_parts_with_author( 60 change: &RadrootsFarmCrdtChange, 61 author_pubkey: &str, 62 ) -> Result<WireEventParts, EventEncodeError> { 63 to_wire_parts_with_kind_and_author(change, KIND_FARM_CRDT_CHANGE, Some(author_pubkey)) 64 } 65 66 #[cfg(feature = "serde_json")] 67 pub fn to_wire_parts_with_kind( 68 change: &RadrootsFarmCrdtChange, 69 kind: u32, 70 ) -> Result<WireEventParts, EventEncodeError> { 71 to_wire_parts_with_kind_and_author(change, kind, None) 72 } 73 74 #[cfg(feature = "serde_json")] 75 pub fn to_wire_parts_with_kind_and_author( 76 change: &RadrootsFarmCrdtChange, 77 kind: u32, 78 author_pubkey: Option<&str>, 79 ) -> Result<WireEventParts, EventEncodeError> { 80 if kind != KIND_FARM_CRDT_CHANGE { 81 return Err(EventEncodeError::InvalidKind(kind)); 82 } 83 let tags = farm_crdt_change_build_tags_with_author(change, author_pubkey)?; 84 let content = serde_json::to_string(change).map_err(|_| EventEncodeError::Json)?; 85 Ok(WireEventParts { 86 kind, 87 content, 88 tags, 89 }) 90 } 91 92 pub(crate) fn validate_change(change: &RadrootsFarmCrdtChange) -> Result<(), EventEncodeError> { 93 if change.schema != RADROOTS_FARM_CRDT_CHANGE_SCHEMA { 94 return Err(EventEncodeError::InvalidField("schema")); 95 } 96 validate_non_empty_field(&change.farm_group_id, "farm_group_id")?; 97 validate_d_tag(&change.document_id, "document_id")?; 98 validate_non_empty_field(&change.workspace.pubkey, "workspace.pubkey")?; 99 validate_d_tag(&change.workspace.d_tag, "workspace.d_tag")?; 100 validate_non_empty_field(&change.actor_id, "actor_id")?; 101 validate_non_empty_field(&change.change_hash, "change_hash")?; 102 for dependency in &change.dependencies { 103 validate_non_empty_field(dependency, "dependencies")?; 104 } 105 validate_non_empty_base64url(&change.encoded_change, "encoded_change")?; 106 if change.business_time_ms == 0 { 107 return Err(EventEncodeError::InvalidField("business_time_ms")); 108 } 109 if let Some(version) = change.crdt_backend_version.as_deref() { 110 validate_non_empty_field(version, "crdt_backend_version")?; 111 } 112 if let Some(member_id) = change.author_member_id.as_deref() { 113 validate_non_empty_field(member_id, "author_member_id")?; 114 } 115 if let Some(app_version) = change.app_version.as_deref() { 116 validate_non_empty_field(app_version, "app_version")?; 117 } 118 Ok(()) 119 }