lib

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

encode.rs (9702B)


      1 #[cfg(not(feature = "std"))]
      2 use alloc::{
      3     string::{String, ToString},
      4     vec,
      5     vec::Vec,
      6 };
      7 
      8 use radroots_event::{
      9     calendar::{
     10         AuthoredCalendar, AuthoredCalendarDateEvent, AuthoredCalendarEventRsvp,
     11         AuthoredCalendarTimeEvent, CalendarEventAuthorReference, CalendarEventFreeBusy,
     12         CalendarEventReference, CalendarEventRevisionReference, CalendarEventRsvpStatus,
     13         CalendarParticipant, CalendarRequest, CalendarUri, covered_utc_days,
     14     },
     15     envelope::kind::{
     16         KIND_CALENDAR, KIND_CALENDAR_DATE_EVENT, KIND_CALENDAR_EVENT_RSVP, KIND_CALENDAR_TIME_EVENT,
     17     },
     18     tag::name::{
     19         TAG_A, TAG_D, TAG_D_DAY, TAG_DESCRIPTION, TAG_E, TAG_END, TAG_END_TZID, TAG_FREE_BUSY,
     20         TAG_G, TAG_IMAGE, TAG_LOCATION, TAG_P, TAG_R, TAG_START, TAG_START_TZID, TAG_STATUS,
     21         TAG_SUMMARY, TAG_T, TAG_TITLE,
     22     },
     23 };
     24 
     25 use crate::error::EventEncodeError;
     26 use crate::field_helpers::{push_optional_tag, push_tag};
     27 use crate::social_helpers::push_participants;
     28 use radroots_event::wire::Nip01EventWireParts;
     29 
     30 pub fn calendar_date_event_build_tags(
     31     event: &AuthoredCalendarDateEvent,
     32 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
     33     validate_authored_date_event(event)?;
     34     let mut tags = Vec::new();
     35     push_tag(&mut tags, TAG_D, event.d_tag().as_str());
     36     push_tag(&mut tags, TAG_TITLE, event.title());
     37     push_tag(&mut tags, TAG_START, event.start().as_str());
     38     push_optional_tag(&mut tags, TAG_END, event.end().map(|end| end.as_str()));
     39     push_authored_calendar_common_tags(
     40         &mut tags,
     41         event.locations(),
     42         event.geohash(),
     43         event.summary(),
     44         event.image().map(|image| image.descriptor().url().as_str()),
     45         event.participants(),
     46         event.categories(),
     47         event.references(),
     48         event.calendar_requests(),
     49     );
     50     Ok(tags)
     51 }
     52 
     53 pub fn calendar_time_event_build_tags(
     54     event: &AuthoredCalendarTimeEvent,
     55 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
     56     validate_authored_time_event(event)?;
     57     let mut tags = Vec::new();
     58     push_tag(&mut tags, TAG_D, event.d_tag().as_str());
     59     push_tag(&mut tags, TAG_TITLE, event.title());
     60     push_tag(&mut tags, TAG_START, event.start().to_string());
     61     if let Some(end) = event.end() {
     62         push_tag(&mut tags, TAG_END, end.to_string());
     63     }
     64     for day in covered_utc_days(event.start(), event.end())
     65         .map_err(|_| EventEncodeError::InvalidField("end"))?
     66     {
     67         push_tag(&mut tags, TAG_D_DAY, day.to_string());
     68     }
     69     push_optional_tag(
     70         &mut tags,
     71         TAG_START_TZID,
     72         event.start_tzid().map(|tzid| tzid.as_str()),
     73     );
     74     push_optional_tag(
     75         &mut tags,
     76         TAG_END_TZID,
     77         event.end_tzid().map(|tzid| tzid.as_str()),
     78     );
     79     push_authored_calendar_common_tags(
     80         &mut tags,
     81         event.locations(),
     82         event.geohash(),
     83         event.summary(),
     84         event.image().map(|image| image.descriptor().url().as_str()),
     85         event.participants(),
     86         event.categories(),
     87         event.references(),
     88         event.calendar_requests(),
     89     );
     90     Ok(tags)
     91 }
     92 
     93 pub fn calendar_collection_build_tags(
     94     calendar: &AuthoredCalendar,
     95 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
     96     let mut tags = Vec::new();
     97     push_tag(&mut tags, TAG_D, calendar.uid().as_str());
     98     push_tag(&mut tags, TAG_TITLE, calendar.title());
     99     for event in calendar.event_references() {
    100         push_calendar_event_reference(&mut tags, event);
    101     }
    102     push_optional_tag(&mut tags, TAG_DESCRIPTION, calendar.list_description());
    103     push_optional_tag(
    104         &mut tags,
    105         TAG_IMAGE,
    106         calendar
    107             .image()
    108             .map(|image| image.descriptor().url().as_str()),
    109     );
    110     Ok(tags)
    111 }
    112 
    113 pub fn rsvp_build_tags(
    114     rsvp: &AuthoredCalendarEventRsvp,
    115 ) -> Result<Vec<Vec<String>>, EventEncodeError> {
    116     let mut tags = Vec::new();
    117     push_tag(&mut tags, TAG_D, rsvp.uid().as_str());
    118     push_calendar_event_reference(&mut tags, rsvp.event_reference());
    119     push_tag(&mut tags, TAG_STATUS, rsvp_status_as_str(rsvp.status()));
    120     if let Some(reference) = rsvp.revision_reference() {
    121         push_calendar_revision_reference(&mut tags, reference);
    122     }
    123     if let Some(free_busy) = rsvp.observed_free_busy() {
    124         push_tag(&mut tags, TAG_FREE_BUSY, free_busy_as_str(free_busy));
    125     }
    126     if let Some(author_hint) = rsvp.author_hint() {
    127         push_calendar_author_reference(&mut tags, author_hint);
    128     }
    129     Ok(tags)
    130 }
    131 
    132 pub fn date_to_wire_parts(
    133     event: &AuthoredCalendarDateEvent,
    134 ) -> Result<Nip01EventWireParts, EventEncodeError> {
    135     date_to_wire_parts_with_kind(event, KIND_CALENDAR_DATE_EVENT)
    136 }
    137 
    138 pub fn time_to_wire_parts(
    139     event: &AuthoredCalendarTimeEvent,
    140 ) -> Result<Nip01EventWireParts, EventEncodeError> {
    141     time_to_wire_parts_with_kind(event, KIND_CALENDAR_TIME_EVENT)
    142 }
    143 
    144 pub fn calendar_to_wire_parts(
    145     calendar: &AuthoredCalendar,
    146 ) -> Result<Nip01EventWireParts, EventEncodeError> {
    147     calendar_to_wire_parts_with_kind(calendar, KIND_CALENDAR)
    148 }
    149 
    150 pub fn rsvp_to_wire_parts(
    151     rsvp: &AuthoredCalendarEventRsvp,
    152 ) -> Result<Nip01EventWireParts, EventEncodeError> {
    153     rsvp_to_wire_parts_with_kind(rsvp, KIND_CALENDAR_EVENT_RSVP)
    154 }
    155 
    156 pub fn date_to_wire_parts_with_kind(
    157     event: &AuthoredCalendarDateEvent,
    158     kind: u32,
    159 ) -> Result<Nip01EventWireParts, EventEncodeError> {
    160     if kind != KIND_CALENDAR_DATE_EVENT {
    161         return Err(EventEncodeError::InvalidKind(kind));
    162     }
    163     Ok(Nip01EventWireParts {
    164         kind,
    165         content: event.description().unwrap_or_default().to_string(),
    166         tags: calendar_date_event_build_tags(event)?,
    167     })
    168 }
    169 
    170 pub fn time_to_wire_parts_with_kind(
    171     event: &AuthoredCalendarTimeEvent,
    172     kind: u32,
    173 ) -> Result<Nip01EventWireParts, EventEncodeError> {
    174     if kind != KIND_CALENDAR_TIME_EVENT {
    175         return Err(EventEncodeError::InvalidKind(kind));
    176     }
    177     Ok(Nip01EventWireParts {
    178         kind,
    179         content: event.description().unwrap_or_default().to_string(),
    180         tags: calendar_time_event_build_tags(event)?,
    181     })
    182 }
    183 
    184 pub fn calendar_to_wire_parts_with_kind(
    185     calendar: &AuthoredCalendar,
    186     kind: u32,
    187 ) -> Result<Nip01EventWireParts, EventEncodeError> {
    188     if kind != KIND_CALENDAR {
    189         return Err(EventEncodeError::InvalidKind(kind));
    190     }
    191     Ok(Nip01EventWireParts {
    192         kind,
    193         content: calendar.content().to_string(),
    194         tags: calendar_collection_build_tags(calendar)?,
    195     })
    196 }
    197 
    198 pub fn rsvp_to_wire_parts_with_kind(
    199     rsvp: &AuthoredCalendarEventRsvp,
    200     kind: u32,
    201 ) -> Result<Nip01EventWireParts, EventEncodeError> {
    202     if kind != KIND_CALENDAR_EVENT_RSVP {
    203         return Err(EventEncodeError::InvalidKind(kind));
    204     }
    205     Ok(Nip01EventWireParts {
    206         kind,
    207         content: rsvp.note().unwrap_or_default().to_string(),
    208         tags: rsvp_build_tags(rsvp)?,
    209     })
    210 }
    211 
    212 fn validate_authored_date_event(
    213     _event: &AuthoredCalendarDateEvent,
    214 ) -> Result<(), EventEncodeError> {
    215     Ok(())
    216 }
    217 
    218 fn validate_authored_time_event(event: &AuthoredCalendarTimeEvent) -> Result<(), EventEncodeError> {
    219     covered_utc_days(event.start(), event.end())
    220         .map_err(|_| EventEncodeError::InvalidField("end"))?;
    221     Ok(())
    222 }
    223 
    224 #[allow(clippy::too_many_arguments)]
    225 fn push_authored_calendar_common_tags(
    226     tags: &mut Vec<Vec<String>>,
    227     locations: &[String],
    228     geohash: Option<&str>,
    229     summary: Option<&str>,
    230     image: Option<&str>,
    231     participants: Option<&Vec<CalendarParticipant>>,
    232     categories: &[String],
    233     references: &[CalendarUri],
    234     calendar_requests: &[CalendarRequest],
    235 ) {
    236     for location in locations {
    237         push_tag(tags, TAG_LOCATION, location);
    238     }
    239     push_optional_tag(tags, TAG_G, geohash);
    240     push_optional_tag(tags, TAG_SUMMARY, summary);
    241     push_optional_tag(tags, TAG_IMAGE, image);
    242     push_participants(tags, participants);
    243     for category in categories {
    244         push_tag(tags, TAG_T, category);
    245     }
    246     for reference in references {
    247         push_tag(tags, TAG_R, reference.as_str());
    248     }
    249     for request in calendar_requests {
    250         let mut tag = vec![TAG_A.to_string(), request.calendar().as_str().to_string()];
    251         if let Some(relay) = request.relay() {
    252             tag.push(relay.to_string());
    253         }
    254         tags.push(tag);
    255     }
    256 }
    257 
    258 fn push_calendar_event_reference(tags: &mut Vec<Vec<String>>, reference: &CalendarEventReference) {
    259     let mut tag = vec![
    260         TAG_A.to_string(),
    261         reference.coordinate().as_str().to_string(),
    262     ];
    263     if let Some(relay) = reference.relay() {
    264         tag.push(relay.to_string());
    265     }
    266     tags.push(tag);
    267 }
    268 
    269 fn push_calendar_revision_reference(
    270     tags: &mut Vec<Vec<String>>,
    271     reference: &CalendarEventRevisionReference,
    272 ) {
    273     let mut tag = vec![TAG_E.to_string(), reference.event_id().to_hex()];
    274     if let Some(relay) = reference.relay() {
    275         tag.push(relay.to_string());
    276     }
    277     tags.push(tag);
    278 }
    279 
    280 fn push_calendar_author_reference(
    281     tags: &mut Vec<Vec<String>>,
    282     reference: &CalendarEventAuthorReference,
    283 ) {
    284     let mut tag = vec![TAG_P.to_string(), reference.pubkey().to_hex()];
    285     if let Some(relay) = reference.relay() {
    286         tag.push(relay.to_string());
    287     }
    288     tags.push(tag);
    289 }
    290 
    291 fn rsvp_status_as_str(status: &CalendarEventRsvpStatus) -> &'static str {
    292     match status {
    293         CalendarEventRsvpStatus::Accepted => "accepted",
    294         CalendarEventRsvpStatus::Declined => "declined",
    295         CalendarEventRsvpStatus::Tentative => "tentative",
    296     }
    297 }
    298 
    299 fn free_busy_as_str(free_busy: &CalendarEventFreeBusy) -> &'static str {
    300     match free_busy {
    301         CalendarEventFreeBusy::Free => "free",
    302         CalendarEventFreeBusy::Busy => "busy",
    303     }
    304 }