lib

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

decode.rs (13769B)


      1 #[cfg(not(feature = "std"))]
      2 use alloc::{string::ToString, vec::Vec};
      3 
      4 use radroots_events::{
      5     RadrootsNostrEvent,
      6     calendar::{
      7         RadrootsCalendar, RadrootsCalendarDateEvent, RadrootsCalendarEventRsvp,
      8         RadrootsCalendarTimeEvent,
      9     },
     10     kinds::{
     11         KIND_CALENDAR, KIND_CALENDAR_DATE_EVENT, KIND_CALENDAR_EVENT_RSVP, KIND_CALENDAR_TIME_EVENT,
     12     },
     13     social::{
     14         RadrootsCalendarDateValue, RadrootsCalendarEventFreeBusy, RadrootsCalendarEventRsvpStatus,
     15         RadrootsSocialTarget,
     16     },
     17     tags::{
     18         TAG_A, TAG_D, TAG_D_DAY, TAG_E, TAG_END, TAG_END_TZID, TAG_FREE_BUSY, TAG_IMAGE, TAG_START,
     19         TAG_START_TZID, TAG_STATUS, TAG_SUMMARY, TAG_TITLE,
     20     },
     21 };
     22 
     23 use crate::d_tag::validate_d_tag_tag;
     24 use crate::error::EventParseError;
     25 use crate::field_helpers::{
     26     optional_tag_value, parse_address_tag, required_tag_value, tag_values,
     27     validate_lowercase_hex_64_tag,
     28 };
     29 use crate::parsed::{RadrootsParsedData, RadrootsParsedEvent};
     30 use crate::social_helpers::{
     31     location_from_tags, participants_from_tags, validate_date_tag, validate_end_after_start,
     32 };
     33 
     34 const EXPECTED_DATE_KIND: &str = "31922";
     35 const EXPECTED_TIME_KIND: &str = "31923";
     36 const EXPECTED_CALENDAR_KIND: &str = "31924";
     37 const EXPECTED_RSVP_KIND: &str = "31925";
     38 
     39 pub fn calendar_date_event_from_event(
     40     kind: u32,
     41     tags: &[Vec<String>],
     42     content: &str,
     43 ) -> Result<RadrootsCalendarDateEvent, EventParseError> {
     44     if kind != KIND_CALENDAR_DATE_EVENT {
     45         return Err(EventParseError::InvalidKind {
     46             expected: EXPECTED_DATE_KIND,
     47             got: kind,
     48         });
     49     }
     50     let d_tag = required_tag_value(tags, TAG_D)?;
     51     validate_d_tag_tag(&d_tag, TAG_D)?;
     52     let title = required_tag_value(tags, TAG_TITLE)?;
     53     let start = required_tag_value(tags, TAG_START)?;
     54     validate_date_tag(&start, TAG_START)?;
     55     let end = optional_tag_value(tags, TAG_END)?;
     56     if let Some(end) = end.as_deref() {
     57         validate_date_tag(end, TAG_END)?;
     58         if end < start.as_str() {
     59             return Err(EventParseError::InvalidTag(TAG_END));
     60         }
     61     }
     62     let days = tag_values(tags, TAG_D_DAY)?
     63         .into_iter()
     64         .map(|value| {
     65             validate_date_tag(&value, TAG_D_DAY)?;
     66             Ok(RadrootsCalendarDateValue { value })
     67         })
     68         .collect::<Result<Vec<_>, EventParseError>>()?;
     69     Ok(RadrootsCalendarDateEvent {
     70         d_tag,
     71         title,
     72         start,
     73         description: optional_content(content),
     74         end,
     75         days: non_empty_vec(days),
     76         location: location_from_tags(tags),
     77         summary: optional_tag_value(tags, TAG_SUMMARY)?,
     78         image: optional_tag_value(tags, TAG_IMAGE)?,
     79         participants: participants_from_tags(tags),
     80     })
     81 }
     82 
     83 pub fn calendar_time_event_from_event(
     84     kind: u32,
     85     tags: &[Vec<String>],
     86     content: &str,
     87 ) -> Result<RadrootsCalendarTimeEvent, EventParseError> {
     88     if kind != KIND_CALENDAR_TIME_EVENT {
     89         return Err(EventParseError::InvalidKind {
     90             expected: EXPECTED_TIME_KIND,
     91             got: kind,
     92         });
     93     }
     94     let d_tag = required_tag_value(tags, TAG_D)?;
     95     validate_d_tag_tag(&d_tag, TAG_D)?;
     96     let title = required_tag_value(tags, TAG_TITLE)?;
     97     let start = parse_required_u64(tags, TAG_START)?;
     98     let end = parse_optional_u64(tags, TAG_END)?;
     99     validate_end_after_start(start, end, TAG_END)
    100         .map_err(|_| EventParseError::InvalidTag(TAG_END))?;
    101     let dates = tag_values(tags, TAG_D_DAY)?
    102         .into_iter()
    103         .map(|value| {
    104             validate_date_tag(&value, TAG_D_DAY)?;
    105             Ok(RadrootsCalendarDateValue { value })
    106         })
    107         .collect::<Result<Vec<_>, EventParseError>>()?;
    108     if dates.is_empty() {
    109         return Err(EventParseError::MissingTag(TAG_D_DAY));
    110     }
    111     Ok(RadrootsCalendarTimeEvent {
    112         d_tag,
    113         title,
    114         start,
    115         dates,
    116         description: optional_content(content),
    117         end,
    118         start_tzid: optional_tag_value(tags, TAG_START_TZID)?,
    119         end_tzid: optional_tag_value(tags, TAG_END_TZID)?,
    120         location: location_from_tags(tags),
    121         summary: optional_tag_value(tags, TAG_SUMMARY)?,
    122         image: optional_tag_value(tags, TAG_IMAGE)?,
    123         participants: participants_from_tags(tags),
    124     })
    125 }
    126 
    127 pub fn calendar_from_event(
    128     kind: u32,
    129     tags: &[Vec<String>],
    130     content: &str,
    131 ) -> Result<RadrootsCalendar, EventParseError> {
    132     if kind != KIND_CALENDAR {
    133         return Err(EventParseError::InvalidKind {
    134             expected: EXPECTED_CALENDAR_KIND,
    135             got: kind,
    136         });
    137     }
    138     let d_tag = required_tag_value(tags, TAG_D)?;
    139     validate_d_tag_tag(&d_tag, TAG_D)?;
    140     let title = required_tag_value(tags, TAG_TITLE)?;
    141     let events = calendar_event_targets_from_tags(tags)?;
    142     if events.is_empty() {
    143         return Err(EventParseError::MissingTag(TAG_A));
    144     }
    145     Ok(RadrootsCalendar {
    146         d_tag,
    147         title,
    148         events,
    149         description: optional_content(content),
    150         summary: optional_tag_value(tags, TAG_SUMMARY)?,
    151         image: optional_tag_value(tags, TAG_IMAGE)?,
    152     })
    153 }
    154 
    155 pub fn rsvp_from_event(
    156     kind: u32,
    157     tags: &[Vec<String>],
    158     content: &str,
    159 ) -> Result<RadrootsCalendarEventRsvp, EventParseError> {
    160     if kind != KIND_CALENDAR_EVENT_RSVP {
    161         return Err(EventParseError::InvalidKind {
    162             expected: EXPECTED_RSVP_KIND,
    163             got: kind,
    164         });
    165     }
    166     let d_tag = required_tag_value(tags, TAG_D)?;
    167     validate_d_tag_tag(&d_tag, TAG_D)?;
    168     let event = calendar_event_target_from_required_tag(tags)?;
    169     let event_id = optional_tag_value(tags, TAG_E)?;
    170     if let Some(event_id) = event_id.as_deref() {
    171         validate_lowercase_hex_64_tag(event_id, TAG_E)?;
    172     }
    173     let status = parse_rsvp_status(&required_tag_value(tags, TAG_STATUS)?)?;
    174     let free_busy = optional_tag_value(tags, TAG_FREE_BUSY)?
    175         .map(|value| parse_free_busy(&value))
    176         .transpose()?;
    177     Ok(RadrootsCalendarEventRsvp {
    178         d_tag,
    179         event,
    180         event_id,
    181         status,
    182         free_busy,
    183         note: if content.is_empty() {
    184             None
    185         } else {
    186             Some(content.to_string())
    187         },
    188         participants: participants_from_tags(tags),
    189     })
    190 }
    191 
    192 pub fn date_data_from_event(
    193     id: String,
    194     author: String,
    195     published_at: u32,
    196     kind: u32,
    197     content: String,
    198     tags: Vec<Vec<String>>,
    199 ) -> Result<RadrootsParsedData<RadrootsCalendarDateEvent>, EventParseError> {
    200     let event = calendar_date_event_from_event(kind, &tags, &content)?;
    201     Ok(RadrootsParsedData::new(
    202         id,
    203         author,
    204         published_at,
    205         kind,
    206         event,
    207     ))
    208 }
    209 
    210 pub fn time_data_from_event(
    211     id: String,
    212     author: String,
    213     published_at: u32,
    214     kind: u32,
    215     content: String,
    216     tags: Vec<Vec<String>>,
    217 ) -> Result<RadrootsParsedData<RadrootsCalendarTimeEvent>, EventParseError> {
    218     let event = calendar_time_event_from_event(kind, &tags, &content)?;
    219     Ok(RadrootsParsedData::new(
    220         id,
    221         author,
    222         published_at,
    223         kind,
    224         event,
    225     ))
    226 }
    227 
    228 pub fn calendar_data_from_event(
    229     id: String,
    230     author: String,
    231     published_at: u32,
    232     kind: u32,
    233     content: String,
    234     tags: Vec<Vec<String>>,
    235 ) -> Result<RadrootsParsedData<RadrootsCalendar>, EventParseError> {
    236     let calendar = calendar_from_event(kind, &tags, &content)?;
    237     Ok(RadrootsParsedData::new(
    238         id,
    239         author,
    240         published_at,
    241         kind,
    242         calendar,
    243     ))
    244 }
    245 
    246 pub fn rsvp_data_from_event(
    247     id: String,
    248     author: String,
    249     published_at: u32,
    250     kind: u32,
    251     content: String,
    252     tags: Vec<Vec<String>>,
    253 ) -> Result<RadrootsParsedData<RadrootsCalendarEventRsvp>, EventParseError> {
    254     let rsvp = rsvp_from_event(kind, &tags, &content)?;
    255     Ok(RadrootsParsedData::new(
    256         id,
    257         author,
    258         published_at,
    259         kind,
    260         rsvp,
    261     ))
    262 }
    263 
    264 pub fn date_parsed_from_event(
    265     id: String,
    266     author: String,
    267     published_at: u32,
    268     kind: u32,
    269     content: String,
    270     tags: Vec<Vec<String>>,
    271     sig: String,
    272 ) -> Result<RadrootsParsedEvent<RadrootsCalendarDateEvent>, EventParseError> {
    273     let data = date_data_from_event(
    274         id.clone(),
    275         author.clone(),
    276         published_at,
    277         kind,
    278         content.clone(),
    279         tags.clone(),
    280     )?;
    281     Ok(RadrootsParsedEvent {
    282         event: RadrootsNostrEvent {
    283             id,
    284             author,
    285             created_at: published_at,
    286             kind,
    287             content,
    288             tags,
    289             sig,
    290         },
    291         data,
    292     })
    293 }
    294 
    295 pub fn time_parsed_from_event(
    296     id: String,
    297     author: String,
    298     published_at: u32,
    299     kind: u32,
    300     content: String,
    301     tags: Vec<Vec<String>>,
    302     sig: String,
    303 ) -> Result<RadrootsParsedEvent<RadrootsCalendarTimeEvent>, EventParseError> {
    304     let data = time_data_from_event(
    305         id.clone(),
    306         author.clone(),
    307         published_at,
    308         kind,
    309         content.clone(),
    310         tags.clone(),
    311     )?;
    312     Ok(RadrootsParsedEvent {
    313         event: RadrootsNostrEvent {
    314             id,
    315             author,
    316             created_at: published_at,
    317             kind,
    318             content,
    319             tags,
    320             sig,
    321         },
    322         data,
    323     })
    324 }
    325 
    326 pub fn calendar_parsed_from_event(
    327     id: String,
    328     author: String,
    329     published_at: u32,
    330     kind: u32,
    331     content: String,
    332     tags: Vec<Vec<String>>,
    333     sig: String,
    334 ) -> Result<RadrootsParsedEvent<RadrootsCalendar>, EventParseError> {
    335     let data = calendar_data_from_event(
    336         id.clone(),
    337         author.clone(),
    338         published_at,
    339         kind,
    340         content.clone(),
    341         tags.clone(),
    342     )?;
    343     Ok(RadrootsParsedEvent {
    344         event: RadrootsNostrEvent {
    345             id,
    346             author,
    347             created_at: published_at,
    348             kind,
    349             content,
    350             tags,
    351             sig,
    352         },
    353         data,
    354     })
    355 }
    356 
    357 pub fn rsvp_parsed_from_event(
    358     id: String,
    359     author: String,
    360     published_at: u32,
    361     kind: u32,
    362     content: String,
    363     tags: Vec<Vec<String>>,
    364     sig: String,
    365 ) -> Result<RadrootsParsedEvent<RadrootsCalendarEventRsvp>, EventParseError> {
    366     let data = rsvp_data_from_event(
    367         id.clone(),
    368         author.clone(),
    369         published_at,
    370         kind,
    371         content.clone(),
    372         tags.clone(),
    373     )?;
    374     Ok(RadrootsParsedEvent {
    375         event: RadrootsNostrEvent {
    376             id,
    377             author,
    378             created_at: published_at,
    379             kind,
    380             content,
    381             tags,
    382             sig,
    383         },
    384         data,
    385     })
    386 }
    387 
    388 fn parse_required_u64(tags: &[Vec<String>], key: &'static str) -> Result<u64, EventParseError> {
    389     required_tag_value(tags, key)?
    390         .parse::<u64>()
    391         .map_err(|err| EventParseError::InvalidNumber(key, err))
    392 }
    393 
    394 fn parse_optional_u64(
    395     tags: &[Vec<String>],
    396     key: &'static str,
    397 ) -> Result<Option<u64>, EventParseError> {
    398     optional_tag_value(tags, key)?
    399         .map(|value| {
    400             value
    401                 .parse::<u64>()
    402                 .map_err(|err| EventParseError::InvalidNumber(key, err))
    403         })
    404         .transpose()
    405 }
    406 
    407 fn non_empty_vec<T>(values: Vec<T>) -> Option<Vec<T>> {
    408     if values.is_empty() {
    409         None
    410     } else {
    411         Some(values)
    412     }
    413 }
    414 
    415 fn optional_content(content: &str) -> Option<String> {
    416     if content.is_empty() {
    417         None
    418     } else {
    419         Some(content.to_string())
    420     }
    421 }
    422 
    423 fn calendar_event_targets_from_tags(
    424     tags: &[Vec<String>],
    425 ) -> Result<Vec<RadrootsSocialTarget>, EventParseError> {
    426     tags.iter()
    427         .filter(|tag| tag.first().map(|value| value.as_str()) == Some(TAG_A))
    428         .map(|tag| calendar_event_target_from_tag(tag))
    429         .collect()
    430 }
    431 
    432 fn calendar_event_target_from_required_tag(
    433     tags: &[Vec<String>],
    434 ) -> Result<RadrootsSocialTarget, EventParseError> {
    435     let tag = tags
    436         .iter()
    437         .find(|tag| tag.first().map(|value| value.as_str()) == Some(TAG_A))
    438         .ok_or(EventParseError::MissingTag(TAG_A))?;
    439     calendar_event_target_from_tag(tag)
    440 }
    441 
    442 fn calendar_event_target_from_tag(tag: &[String]) -> Result<RadrootsSocialTarget, EventParseError> {
    443     let value = tag
    444         .get(1)
    445         .cloned()
    446         .ok_or(EventParseError::InvalidTag(TAG_A))?;
    447     let address = parse_address_tag(&value, TAG_A)?;
    448     if !is_calendar_event_kind(address.kind) {
    449         return Err(EventParseError::InvalidTag(TAG_A));
    450     }
    451     Ok(RadrootsSocialTarget::Address {
    452         address: value,
    453         author: Some(address.pubkey),
    454         event_kind: Some(address.kind),
    455         relays: relays_from_tag(tag, 2),
    456     })
    457 }
    458 
    459 fn relays_from_tag(tag: &[String], start: usize) -> Option<Vec<String>> {
    460     let relays = tag
    461         .iter()
    462         .skip(start)
    463         .filter(|value| !value.trim().is_empty())
    464         .cloned()
    465         .collect::<Vec<_>>();
    466     if relays.is_empty() {
    467         None
    468     } else {
    469         Some(relays)
    470     }
    471 }
    472 
    473 fn is_calendar_event_kind(kind: u32) -> bool {
    474     matches!(kind, KIND_CALENDAR_DATE_EVENT | KIND_CALENDAR_TIME_EVENT)
    475 }
    476 
    477 fn parse_rsvp_status(value: &str) -> Result<RadrootsCalendarEventRsvpStatus, EventParseError> {
    478     match value {
    479         "accepted" => Ok(RadrootsCalendarEventRsvpStatus::Accepted),
    480         "declined" => Ok(RadrootsCalendarEventRsvpStatus::Declined),
    481         "tentative" => Ok(RadrootsCalendarEventRsvpStatus::Tentative),
    482         _ => Err(EventParseError::InvalidTag(TAG_STATUS)),
    483     }
    484 }
    485 
    486 fn parse_free_busy(value: &str) -> Result<RadrootsCalendarEventFreeBusy, EventParseError> {
    487     match value {
    488         "free" => Ok(RadrootsCalendarEventFreeBusy::Free),
    489         "busy" => Ok(RadrootsCalendarEventFreeBusy::Busy),
    490         _ => Err(EventParseError::InvalidTag(TAG_FREE_BUSY)),
    491     }
    492 }