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 }