use http::Uri;
use nostr_sdk::prelude::*;
use std::collections::{HashMap, HashSet};
use std::error::Error;
use std::str::FromStr;
use std::time::Duration;
use url::Url;
use crate::hookstr::DEFAULT_RELAYS;
pub async fn get_user_metadata(
client: &Client,
pubkey: PublicKey,
) -> Option<Metadata> {
let filter_meta = Filter::new().author(pubkey).kind(Kind::Metadata);
match client.database().query(filter_meta).await {
Ok(mevents) => {
if !mevents.is_empty() {
match Metadata::from_json(&mevents.first().unwrap().content) {
Ok(usermeta) => return Some(usermeta.clone()),
Err(_err) => return None,
}
}
}
Err(_err) => {
return None;
}
}
None
}
pub async fn fetch_user_metadata(
client: &Client,
pubk: PublicKey,
) -> Option<Metadata> {
if let Ok(Some(metadata)) =
client.fetch_metadata(pubk, Duration::from_secs(5)).await
{
Some(metadata)
} else {
None
}
}
pub async fn advertise_relay_list(
client: &Client,
) -> Result<(), Box<dyn Error>> {
let mut relay_metadata: HashMap<RelayUrl, Option<RelayMetadata>> =
HashMap::new();
for (rurl, _relay) in client.pool().relays_with_flag(RelayServiceFlags::WRITE, FlagCheck::Any).await {
relay_metadata.insert(rurl, Some(RelayMetadata::Write));
}
let evb_meta = EventBuilder::relay_list(relay_metadata);
client.send_event_builder_to(DEFAULT_RELAYS.into_iter().map(|u| RelayUrl::parse(u).unwrap()), evb_meta).await?;
let inboxr: Vec<&str> =
vec!["wss://relay.damus.io", "wss://nostr.bitcoiner.social"];
let evb_ir = EventBuilder::new(Kind::InboxRelays, "")
.tags(inboxr.into_iter().map(|ir| Tag::custom(TagKind::Relay, vec![ir])));
client.send_event_builder(evb_ir).await?;
Ok(())
}
pub fn notes_filter(limit: usize) -> Filter {
Filter::new().kind(Kind::TextNote).kind(Kind::LongFormTextNote).limit(limit)
}
pub fn parse_note_urls(event: &Event) -> Vec<(Uri, Uri)> {
let mut vec: Vec<(Uri, Uri)> = Vec::new();
for elem in event.content.split_whitespace() {
if let Ok(url) = Url::parse(elem) {
let scheme = url.scheme();
let Ok(orig_uri) = Uri::from_str(url.as_str()) else {
continue;
};
match scheme {
"nostr" => {
let path = url.path();
if path.is_empty() {
continue;
}
let uri: Uri = if path.starts_with("nevent") {
Uri::builder()
.path_and_query(format!("/note/{}/thread", path))
.build()
.unwrap()
} else {
Uri::from_str(url.as_str()).unwrap()
};
vec.push((orig_uri, uri));
}
_ => {
vec.push((orig_uri.clone(), orig_uri.clone()));
continue;
}
}
}
}
vec
}
pub fn parse_note_ids(event: &Event) -> (Vec<EventId>, Vec<PublicKey>) {
let mut vec_evid: Vec<EventId> = Vec::new();
let mut vec_pk: Vec<PublicKey> = Vec::new();
for elem in event.content.split_whitespace() {
let Ok(url) = Url::parse(elem) else { continue };
let scheme = url.scheme();
match scheme {
"nostr" => {
let urls = url.as_str();
let path = url.path();
if path.starts_with("nevent") {
let Ok(res) = Nip19Event::from_nostr_uri(urls) else {
continue;
};
vec_evid.push(res.event_id);
}
if path.starts_with("npub") {
let Ok(pk) = PublicKey::parse(path) else {
continue;
};
vec_pk.push(pk);
}
}
_ => {
continue;
}
}
}
(vec_evid, vec_pk)
}
pub fn reactions_summary(reaction_events: &Events) -> String {
let mut summary = String::new();
let rlist: HashSet<_> =
reaction_events.iter().map(|e| e.content.clone()).collect();
for emoji in rlist {
let count = reaction_events
.iter()
.filter(|e| e.content == emoji)
.count();
let emojis = if emoji == "+" { "\u{1F44D}" } else { &emoji };
summary.push_str(&format!("{} {} ", count, emojis));
}
summary
}