#[derive(std::fmt::Debug, Clone, PartialEq, Eq)]
pub enum Pointer {
Profile(ProfilePointer),
Event(EventPointer),
Address(AddressPointer),
}
#[derive(thiserror::Error, std::fmt::Debug)]
pub enum Error {
#[error("tag should have at least 2 elements")]
ShortTag,
#[error("something is invalid")]
Invalid,
}
#[derive(std::fmt::Debug, Clone, PartialEq, Eq)]
pub struct ProfilePointer {
pub pubkey: crate::PubKey,
pub relays: Vec<String>,
}
impl ProfilePointer {
pub fn from_tag(tag: &crate::Tag) -> Result<Self, Error> {
if tag.len() < 2 {
return Err(Error::ShortTag);
}
let pubkey: crate::PubKey = tag[1].parse().map_err(|_| Error::Invalid)?;
let relays = if tag.len() > 2 && crate::helpers::is_valid_relay_url(&tag[2]) {
vec![tag[2].clone()]
} else {
vec![]
};
Ok(Self { pubkey, relays })
}
}
#[derive(std::fmt::Debug, Clone, PartialEq, Eq)]
pub struct EventPointer {
pub id: crate::ID,
pub relays: Vec<String>,
pub author: Option<crate::PubKey>,
pub kind: Option<crate::Kind>,
}
impl EventPointer {
pub fn from_tag(tag: &crate::Tag) -> Result<Self, Error> {
if tag.len() < 2 {
return Err(Error::ShortTag);
}
let id = crate::ID::from_hex(&tag[1]).map_err(|_| Error::Invalid)?;
let relays = if tag.len() > 2 && crate::helpers::is_valid_relay_url(&tag[2]) {
vec![tag[2].clone()]
} else {
vec![]
};
let author = if tag.len() > 3 {
tag[3].parse().ok()
} else {
None
};
Ok(Self {
id,
relays,
author,
kind: None,
})
}
}
#[derive(std::fmt::Debug, Clone, PartialEq, Eq)]
pub struct AddressPointer {
pub pubkey: crate::PubKey,
pub kind: crate::Kind,
pub identifier: String,
pub relays: Vec<String>,
}
impl AddressPointer {
pub fn from_tag(tag: &crate::Tag) -> Result<Self, Error> {
if tag.len() < 2 {
return Err(Error::ShortTag);
}
let parts: Vec<&str> = tag[1].splitn(3, ':').collect();
if parts.len() != 3 {
return Err(Error::Invalid);
}
let kind: u16 = parts[0].parse().map_err(|_| Error::Invalid)?;
let pubkey: crate::PubKey = parts[1].parse().map_err(|_| Error::Invalid)?;
let identifier = parts[2].to_string();
let relays = if tag.len() > 2 && crate::helpers::is_valid_relay_url(&tag[2]) {
vec![tag[2].clone()]
} else {
vec![]
};
Ok(Self {
kind: crate::Kind(kind),
relays,
pubkey,
identifier,
})
}
}
impl Pointer {
pub fn as_tag_reference(&self) -> String {
match self {
Pointer::Profile(p) => p.pubkey.to_hex(),
Pointer::Event(p) => p.id.to_hex(),
Pointer::Address(p) => format!("{}:{}:{}", p.kind, p.pubkey.to_hex(), p.identifier),
}
}
pub fn as_tag(&self) -> crate::Tag {
match self {
Pointer::Profile(p) => {
let mut tag = vec!["p".to_string(), p.pubkey.to_hex()];
if !p.relays.is_empty() {
tag.push(p.relays[0].clone());
}
tag
}
Pointer::Event(p) => {
let mut tag = vec!["e".to_string(), p.id.to_hex()];
if !p.relays.is_empty() {
tag.push(p.relays[0].clone());
if let Some(author) = &p.author {
tag.push(author.to_hex());
}
}
tag
}
Pointer::Address(p) => {
let mut tag = vec!["a".to_string(), self.as_tag_reference()];
if !p.relays.is_empty() {
tag.push(p.relays[0].clone());
}
tag
}
}
}
pub fn as_filter(&self) -> crate::Filter {
match self {
Pointer::Profile(p) => crate::Filter {
authors: Some(vec![p.pubkey]),
..Default::default()
},
Pointer::Event(p) => crate::Filter {
ids: Some(vec![p.id]),
..Default::default()
},
Pointer::Address(p) => crate::Filter {
kinds: Some(vec![p.kind]),
authors: Some(vec![p.pubkey]),
tags: Some(vec![crate::filter::TagQuery(
"d".to_string(),
vec![p.identifier.clone()],
)]),
..Default::default()
},
}
}
pub fn matches_event(&self, event: &crate::Event) -> bool {
match self {
Pointer::Profile(_) => false,
Pointer::Event(p) => event.id == p.id,
Pointer::Address(p) => {
event.pubkey == p.pubkey
&& event.kind == p.kind
&& event.tags.get_d() == p.identifier
}
}
}
}