lib

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

encode.rs (11531B)


      1 #[cfg(not(feature = "std"))]
      2 use alloc::{
      3     string::{String, ToString},
      4     vec,
      5     vec::Vec,
      6 };
      7 
      8 use radroots_events::{
      9     group::{
     10         KIND_GROUP_ADMINS, KIND_GROUP_CREATE_GROUP, KIND_GROUP_CREATE_INVITE,
     11         KIND_GROUP_DELETE_EVENT, KIND_GROUP_DELETE_GROUP, KIND_GROUP_EDIT_METADATA,
     12         KIND_GROUP_JOIN_REQUEST, KIND_GROUP_LEAVE_REQUEST, KIND_GROUP_MEMBERS, KIND_GROUP_METADATA,
     13         KIND_GROUP_PUT_USER, KIND_GROUP_REMOVE_USER, KIND_GROUP_ROLES, RadrootsGroupAdmins,
     14         RadrootsGroupCreateGroup, RadrootsGroupCreateInvite, RadrootsGroupDeleteEvent,
     15         RadrootsGroupDeleteGroup, RadrootsGroupEditMetadata, RadrootsGroupEditableMetadata,
     16         RadrootsGroupJoinRequest, RadrootsGroupLeaveRequest, RadrootsGroupMembers,
     17         RadrootsGroupMetadata, RadrootsGroupPutUser, RadrootsGroupRemoveUser, RadrootsGroupRole,
     18         RadrootsGroupRoles, RadrootsGroupUserRef,
     19     },
     20     tags::{TAG_D, TAG_E, TAG_H, TAG_P},
     21 };
     22 
     23 use crate::error::EventEncodeError;
     24 use crate::field_helpers::{
     25     push_optional_tag, push_tag, push_tag_values, validate_non_empty_field,
     26 };
     27 use crate::wire::WireEventParts;
     28 
     29 const TAG_ABOUT: &str = "about";
     30 const TAG_CLOSED: &str = "closed";
     31 const TAG_CODE: &str = "code";
     32 const TAG_HIDDEN: &str = "hidden";
     33 const TAG_NAME: &str = "name";
     34 const TAG_PICTURE: &str = "picture";
     35 const TAG_PRIVATE: &str = "private";
     36 const TAG_RESTRICTED: &str = "restricted";
     37 const TAG_ROLE: &str = "role";
     38 const TAG_SUPPORTED_KINDS: &str = "supported_kinds";
     39 
     40 pub fn group_put_user_build_tags(
     41     event: &RadrootsGroupPutUser,
     42 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
     43     let mut tags = h_tags(&event.group_id)?;
     44     push_user_tag(&mut tags, &event.pubkey, &event.roles)?;
     45     Ok(tags)
     46 }
     47 
     48 pub fn group_remove_user_build_tags(
     49     event: &RadrootsGroupRemoveUser,
     50 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
     51     let mut tags = h_tags(&event.group_id)?;
     52     push_tag(&mut tags, TAG_P, event.pubkey.as_str());
     53     validate_non_empty_field(&event.pubkey, "pubkey")?;
     54     Ok(tags)
     55 }
     56 
     57 pub fn group_create_group_build_tags(
     58     event: &RadrootsGroupCreateGroup,
     59 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
     60     let mut tags = h_tags(&event.group_id)?;
     61     push_metadata_tags(&mut tags, &event.metadata)?;
     62     Ok(tags)
     63 }
     64 
     65 pub fn group_edit_metadata_build_tags(
     66     event: &RadrootsGroupEditMetadata,
     67 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
     68     let mut tags = h_tags(&event.group_id)?;
     69     push_metadata_tags(&mut tags, &event.metadata)?;
     70     Ok(tags)
     71 }
     72 
     73 pub fn group_delete_group_build_tags(
     74     event: &RadrootsGroupDeleteGroup,
     75 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
     76     h_tags(&event.group_id)
     77 }
     78 
     79 pub fn group_delete_event_build_tags(
     80     event: &RadrootsGroupDeleteEvent,
     81 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
     82     let mut tags = h_tags(&event.group_id)?;
     83     validate_non_empty_field(&event.event_id, "event_id")?;
     84     push_tag(&mut tags, TAG_E, event.event_id.as_str());
     85     Ok(tags)
     86 }
     87 
     88 pub fn group_create_invite_build_tags(
     89     event: &RadrootsGroupCreateInvite,
     90 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
     91     let mut tags = h_tags(&event.group_id)?;
     92     validate_non_empty_field(&event.code, "code")?;
     93     push_tag(&mut tags, TAG_CODE, event.code.as_str());
     94     Ok(tags)
     95 }
     96 
     97 pub fn group_join_request_build_tags(
     98     event: &RadrootsGroupJoinRequest,
     99 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
    100     let mut tags = h_tags(&event.group_id)?;
    101     push_optional_tag(&mut tags, TAG_CODE, event.code.as_deref());
    102     validate_optional(event.code.as_deref(), "code")?;
    103     Ok(tags)
    104 }
    105 
    106 pub fn group_leave_request_build_tags(
    107     event: &RadrootsGroupLeaveRequest,
    108 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
    109     h_tags(&event.group_id)
    110 }
    111 
    112 pub fn group_metadata_build_tags(
    113     event: &RadrootsGroupMetadata,
    114 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
    115     let mut tags = d_tags(&event.d_tag)?;
    116     push_metadata_tags(&mut tags, &event.metadata)?;
    117     Ok(tags)
    118 }
    119 
    120 pub fn group_admins_build_tags(
    121     event: &RadrootsGroupAdmins,
    122 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
    123     let mut tags = d_tags(&event.d_tag)?;
    124     push_user_refs(&mut tags, &event.admins)?;
    125     Ok(tags)
    126 }
    127 
    128 pub fn group_members_build_tags(
    129     event: &RadrootsGroupMembers,
    130 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
    131     let mut tags = d_tags(&event.d_tag)?;
    132     push_user_refs(&mut tags, &event.members)?;
    133     Ok(tags)
    134 }
    135 
    136 pub fn group_roles_build_tags(
    137     event: &RadrootsGroupRoles,
    138 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
    139     let mut tags = d_tags(&event.d_tag)?;
    140     for role in &event.roles {
    141         validate_role(role)?;
    142         let mut values = vec![role.name.clone()];
    143         if let Some(description) = role.description.as_deref() {
    144             values.push(description.to_string());
    145         }
    146         values.extend(role.permissions.iter().cloned());
    147         push_tag_values(&mut tags, TAG_ROLE, values);
    148     }
    149     Ok(tags)
    150 }
    151 
    152 pub fn group_put_user_to_wire_parts(
    153     event: &RadrootsGroupPutUser,
    154 ) -> Result<WireEventParts, EventEncodeError> {
    155     message_wire(
    156         KIND_GROUP_PUT_USER,
    157         group_put_user_build_tags(event)?,
    158         event.message.as_deref(),
    159     )
    160 }
    161 
    162 pub fn group_remove_user_to_wire_parts(
    163     event: &RadrootsGroupRemoveUser,
    164 ) -> Result<WireEventParts, EventEncodeError> {
    165     message_wire(
    166         KIND_GROUP_REMOVE_USER,
    167         group_remove_user_build_tags(event)?,
    168         event.message.as_deref(),
    169     )
    170 }
    171 
    172 pub fn group_create_group_to_wire_parts(
    173     event: &RadrootsGroupCreateGroup,
    174 ) -> Result<WireEventParts, EventEncodeError> {
    175     message_wire(
    176         KIND_GROUP_CREATE_GROUP,
    177         group_create_group_build_tags(event)?,
    178         event.message.as_deref(),
    179     )
    180 }
    181 
    182 pub fn group_edit_metadata_to_wire_parts(
    183     event: &RadrootsGroupEditMetadata,
    184 ) -> Result<WireEventParts, EventEncodeError> {
    185     message_wire(
    186         KIND_GROUP_EDIT_METADATA,
    187         group_edit_metadata_build_tags(event)?,
    188         event.message.as_deref(),
    189     )
    190 }
    191 
    192 pub fn group_delete_group_to_wire_parts(
    193     event: &RadrootsGroupDeleteGroup,
    194 ) -> Result<WireEventParts, EventEncodeError> {
    195     message_wire(
    196         KIND_GROUP_DELETE_GROUP,
    197         group_delete_group_build_tags(event)?,
    198         event.message.as_deref(),
    199     )
    200 }
    201 
    202 pub fn group_delete_event_to_wire_parts(
    203     event: &RadrootsGroupDeleteEvent,
    204 ) -> Result<WireEventParts, EventEncodeError> {
    205     message_wire(
    206         KIND_GROUP_DELETE_EVENT,
    207         group_delete_event_build_tags(event)?,
    208         event.message.as_deref(),
    209     )
    210 }
    211 
    212 pub fn group_create_invite_to_wire_parts(
    213     event: &RadrootsGroupCreateInvite,
    214 ) -> Result<WireEventParts, EventEncodeError> {
    215     message_wire(
    216         KIND_GROUP_CREATE_INVITE,
    217         group_create_invite_build_tags(event)?,
    218         event.message.as_deref(),
    219     )
    220 }
    221 
    222 pub fn group_join_request_to_wire_parts(
    223     event: &RadrootsGroupJoinRequest,
    224 ) -> Result<WireEventParts, EventEncodeError> {
    225     message_wire(
    226         KIND_GROUP_JOIN_REQUEST,
    227         group_join_request_build_tags(event)?,
    228         event.message.as_deref(),
    229     )
    230 }
    231 
    232 pub fn group_leave_request_to_wire_parts(
    233     event: &RadrootsGroupLeaveRequest,
    234 ) -> Result<WireEventParts, EventEncodeError> {
    235     message_wire(
    236         KIND_GROUP_LEAVE_REQUEST,
    237         group_leave_request_build_tags(event)?,
    238         event.message.as_deref(),
    239     )
    240 }
    241 
    242 pub fn group_metadata_to_wire_parts(
    243     event: &RadrootsGroupMetadata,
    244 ) -> Result<WireEventParts, EventEncodeError> {
    245     empty_wire(KIND_GROUP_METADATA, group_metadata_build_tags(event)?)
    246 }
    247 
    248 pub fn group_admins_to_wire_parts(
    249     event: &RadrootsGroupAdmins,
    250 ) -> Result<WireEventParts, EventEncodeError> {
    251     message_wire(
    252         KIND_GROUP_ADMINS,
    253         group_admins_build_tags(event)?,
    254         event.description.as_deref(),
    255     )
    256 }
    257 
    258 pub fn group_members_to_wire_parts(
    259     event: &RadrootsGroupMembers,
    260 ) -> Result<WireEventParts, EventEncodeError> {
    261     message_wire(
    262         KIND_GROUP_MEMBERS,
    263         group_members_build_tags(event)?,
    264         event.description.as_deref(),
    265     )
    266 }
    267 
    268 pub fn group_roles_to_wire_parts(
    269     event: &RadrootsGroupRoles,
    270 ) -> Result<WireEventParts, EventEncodeError> {
    271     message_wire(
    272         KIND_GROUP_ROLES,
    273         group_roles_build_tags(event)?,
    274         event.description.as_deref(),
    275     )
    276 }
    277 
    278 fn h_tags(group_id: &str) -> Result<Vec<Vec<String>>, EventEncodeError> {
    279     validate_non_empty_field(group_id, "group_id")?;
    280     let mut tags = Vec::new();
    281     push_tag(&mut tags, TAG_H, group_id);
    282     Ok(tags)
    283 }
    284 
    285 fn d_tags(d_tag: &str) -> Result<Vec<Vec<String>>, EventEncodeError> {
    286     validate_non_empty_field(d_tag, "d_tag")?;
    287     let mut tags = Vec::new();
    288     push_tag(&mut tags, TAG_D, d_tag);
    289     Ok(tags)
    290 }
    291 
    292 fn push_metadata_tags(
    293     tags: &mut Vec<Vec<String>>,
    294     metadata: &RadrootsGroupEditableMetadata,
    295 ) -> Result<(), EventEncodeError> {
    296     push_optional_tag(tags, TAG_NAME, metadata.name.as_deref());
    297     push_optional_tag(tags, TAG_ABOUT, metadata.about.as_deref());
    298     push_optional_tag(tags, TAG_PICTURE, metadata.picture.as_deref());
    299     if metadata.is_private {
    300         push_marker_tag(tags, TAG_PRIVATE);
    301     }
    302     if metadata.is_restricted {
    303         push_marker_tag(tags, TAG_RESTRICTED);
    304     }
    305     if metadata.is_closed {
    306         push_marker_tag(tags, TAG_CLOSED);
    307     }
    308     if metadata.is_hidden {
    309         push_marker_tag(tags, TAG_HIDDEN);
    310     }
    311     if let Some(supported_kinds) = metadata.supported_kinds.as_deref() {
    312         push_tag_values(
    313             tags,
    314             TAG_SUPPORTED_KINDS,
    315             supported_kinds.iter().map(ToString::to_string),
    316         );
    317     }
    318     validate_optional(metadata.name.as_deref(), "name")?;
    319     validate_optional(metadata.about.as_deref(), "about")?;
    320     validate_optional(metadata.picture.as_deref(), "picture")?;
    321     Ok(())
    322 }
    323 
    324 fn push_marker_tag(tags: &mut Vec<Vec<String>>, key: &str) {
    325     tags.push(vec![key.to_string()]);
    326 }
    327 
    328 fn push_user_refs(
    329     tags: &mut Vec<Vec<String>>,
    330     users: &[RadrootsGroupUserRef],
    331 ) -> Result<(), EventEncodeError> {
    332     for user in users {
    333         push_user_tag(tags, &user.pubkey, &user.roles)?;
    334     }
    335     Ok(())
    336 }
    337 
    338 fn push_user_tag(
    339     tags: &mut Vec<Vec<String>>,
    340     pubkey: &str,
    341     roles: &[String],
    342 ) -> Result<(), EventEncodeError> {
    343     validate_non_empty_field(pubkey, "pubkey")?;
    344     for role in roles {
    345         validate_non_empty_field(role, "roles")?;
    346     }
    347     let mut values = vec![pubkey.to_string()];
    348     values.extend(roles.iter().cloned());
    349     push_tag_values(tags, TAG_P, values);
    350     Ok(())
    351 }
    352 
    353 fn validate_role(role: &RadrootsGroupRole) -> Result<(), EventEncodeError> {
    354     validate_non_empty_field(&role.name, "role.name")?;
    355     validate_optional(role.description.as_deref(), "role.description")?;
    356     for permission in &role.permissions {
    357         validate_non_empty_field(permission, "role.permissions")?;
    358     }
    359     Ok(())
    360 }
    361 
    362 fn validate_optional(value: Option<&str>, field: &'static str) -> Result<(), EventEncodeError> {
    363     if let Some(value) = value {
    364         validate_non_empty_field(value, field)?;
    365     }
    366     Ok(())
    367 }
    368 
    369 fn empty_wire(kind: u32, tags: Vec<Vec<String>>) -> Result<WireEventParts, EventEncodeError> {
    370     Ok(WireEventParts {
    371         kind,
    372         content: String::new(),
    373         tags,
    374     })
    375 }
    376 
    377 fn message_wire(
    378     kind: u32,
    379     tags: Vec<Vec<String>>,
    380     message: Option<&str>,
    381 ) -> Result<WireEventParts, EventEncodeError> {
    382     validate_optional(message, "message")?;
    383     Ok(WireEventParts {
    384         kind,
    385         content: message.unwrap_or_default().to_string(),
    386         tags,
    387     })
    388 }