use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::fmt;
use core::str::FromStr;
use bitcoin::secp256k1::schnorr::Signature;
use crate::{ImageDimensions, PublicKey, Tag, Timestamp, UncheckedUrl};
#[derive(Debug)]
pub enum Error {
UnknownLiveEventMarker(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UnknownLiveEventMarker(u) => write!(f, "Unknown live event marker: {u}"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum LiveEventMarker {
Host,
Speaker,
Participant,
}
impl fmt::Display for LiveEventMarker {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Host => write!(f, "Host"),
Self::Speaker => write!(f, "Speaker"),
Self::Participant => write!(f, "Participant"),
}
}
}
impl FromStr for LiveEventMarker {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Host" => Ok(Self::Host),
"Speaker" => Ok(Self::Speaker),
"Participant" => Ok(Self::Participant),
s => Err(Error::UnknownLiveEventMarker(s.to_string())),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum LiveEventStatus {
Planned,
Live,
Ended,
Custom(String),
}
impl fmt::Display for LiveEventStatus {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Planned => write!(f, "planned"),
Self::Live => write!(f, "live"),
Self::Ended => write!(f, "ended"),
Self::Custom(s) => write!(f, "{s}"),
}
}
}
impl<S> From<S> for LiveEventStatus
where
S: Into<String>,
{
fn from(s: S) -> Self {
let s: String = s.into();
match s.as_str() {
"planned" => Self::Planned,
"live" => Self::Live,
"ended" => Self::Ended,
_ => Self::Custom(s),
}
}
}
#[derive(Clone)]
pub struct LiveEventHost {
pub public_key: PublicKey,
pub relay_url: Option<UncheckedUrl>,
pub proof: Option<Signature>,
}
pub struct LiveEvent {
pub id: String,
pub title: Option<String>,
pub summary: Option<String>,
pub image: Option<(UncheckedUrl, Option<ImageDimensions>)>,
pub hashtags: Vec<String>,
pub streaming: Option<UncheckedUrl>,
pub recording: Option<UncheckedUrl>,
pub starts: Option<Timestamp>,
pub ends: Option<Timestamp>,
pub status: Option<LiveEventStatus>,
pub current_participants: Option<u64>,
pub total_participants: Option<u64>,
pub relays: Vec<UncheckedUrl>,
pub host: Option<LiveEventHost>,
pub speakers: Vec<(PublicKey, Option<UncheckedUrl>)>,
pub participants: Vec<(PublicKey, Option<UncheckedUrl>)>,
}
impl From<LiveEvent> for Vec<Tag> {
fn from(live_event: LiveEvent) -> Self {
let mut tags = Vec::new();
let LiveEvent {
id,
title,
summary,
image,
hashtags,
streaming,
recording,
starts,
ends,
status,
current_participants,
total_participants,
relays,
host,
speakers,
participants,
} = live_event;
tags.push(Tag::Identifier(id));
if let Some(title) = title {
tags.push(Tag::Title(title));
}
if let Some(summary) = summary {
tags.push(Tag::Summary(summary));
}
if let Some(streaming) = streaming {
tags.push(Tag::Streaming(streaming));
}
if let Some(status) = status {
tags.push(Tag::LiveEventStatus(status));
}
if let Some(LiveEventHost {
public_key,
relay_url,
proof,
}) = host
{
tags.push(Tag::PubKeyLiveEvent {
public_key,
relay_url,
marker: LiveEventMarker::Host,
proof,
});
}
for (public_key, relay_url) in speakers.into_iter() {
tags.push(Tag::PubKeyLiveEvent {
public_key,
relay_url,
marker: LiveEventMarker::Speaker,
proof: None,
});
}
for (public_key, relay_url) in participants.into_iter() {
tags.push(Tag::PubKeyLiveEvent {
public_key,
relay_url,
marker: LiveEventMarker::Participant,
proof: None,
});
}
if let Some((image, dim)) = image {
tags.push(Tag::Image(image, dim));
}
for hashtag in hashtags.into_iter() {
tags.push(Tag::Hashtag(hashtag));
}
if let Some(recording) = recording {
tags.push(Tag::Recording(recording));
}
if let Some(starts) = starts {
tags.push(Tag::Starts(starts));
}
if let Some(ends) = ends {
tags.push(Tag::Ends(ends));
}
if let Some(current_participants) = current_participants {
tags.push(Tag::CurrentParticipants(current_participants));
}
if let Some(total_participants) = total_participants {
tags.push(Tag::TotalParticipants(total_participants));
}
if !relays.is_empty() {
tags.push(Tag::Relays(relays));
}
tags
}
}