From 6f66fab0b5bab74e63c790d8964a0e6b4982000e Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Thu, 18 Jul 2024 12:14:09 +0100 Subject: refactor: fetch some profiles from user relays add the ability to fetch more than just the current user from their user write relays --- src/client.rs | 102 +++++++++++++++++++++++++++++++++++------------------ src/login.rs | 111 +++++++++++++++++++++++++++++----------------------------- 2 files changed, 123 insertions(+), 90 deletions(-) (limited to 'src') diff --git a/src/client.rs b/src/client.rs index b50ccf2..1fdc3d8 100644 --- a/src/client.rs +++ b/src/client.rs @@ -35,7 +35,7 @@ use nostr_sqlite::SQLiteDatabase; use crate::{ config::get_dirs, - login::get_logged_in_user_and_relays_from_cache, + login::{get_logged_in_user, get_user_ref_from_cache}, repo_ref::{RepoRef, REPO_REF_KIND}, sub_commands::{ list::status_kinds, @@ -313,8 +313,8 @@ impl Connect for Client { loop { let relays = request - .relays - .union(&request.current_user_write_relays) + .repo_relays + .union(&request.user_relays_for_profiles) // don't look for events on blaster .filter(|&r| !r.as_str().contains("nostr.mutinywallet.com")) .cloned() @@ -325,11 +325,11 @@ impl Connect for Client { if relays.is_empty() { break; } - let only_user_relays = request - .current_user_write_relays - .difference(&request.relays) + let profile_relays_only = request + .user_relays_for_profiles + .difference(&request.repo_relays) .collect::>(); - for relay in &request.relays { + for relay in &request.repo_relays { self.client .add_relay(relay.as_str()) .await @@ -341,15 +341,17 @@ impl Connect for Client { let futures: Vec<_> = relays .iter() .map(|r| { - if only_user_relays.contains(r) { - // if user write relay isn't a repo relay, just filter for user profile + if profile_relays_only.contains(r) { + // if relay isn't a repo relay, just filter for user profile FetchRequest { selected_relay: Some(r.to_owned()), repo_coordinates: vec![], proposals: HashSet::new(), - missing_contributor_profiles: HashSet::from_iter(vec![ - request.current_user.unwrap(), - ]), + missing_contributor_profiles: request + .missing_contributor_profiles + .union(&request.profiles_to_fetch_from_user_relays) + .copied() + .collect(), ..request.clone() } } else { @@ -420,15 +422,26 @@ impl Connect for Client { processed_relays.extend(relays.clone()); if let Ok(repo_ref) = get_repo_ref_from_cache(git_repo_path, repo_coordinates).await { - request.relays = repo_ref + request.repo_relays = repo_ref .relays .iter() .filter_map(|r| Url::parse(r).ok()) .collect(); } - let (_, current_user_write_relays) = - get_logged_in_user_and_relays_from_cache(git_repo_path).await?; - request.current_user_write_relays = current_user_write_relays; + + request.user_relays_for_profiles = { + let mut set = HashSet::new(); + for user in &request.profiles_to_fetch_from_user_relays { + if let Ok(user_ref) = get_user_ref_from_cache(git_repo_path, user).await { + for r in user_ref.relays.write() { + if let Ok(url) = Url::parse(&r) { + set.insert(url); + } + } + } + } + set + }; } Ok((relay_reports, progress_reporter)) } @@ -444,10 +457,11 @@ impl Connect for Client { fresh_coordinates.insert(c); } let mut fresh_proposal_roots = request.proposals.clone(); - let mut fresh_contributors = request.missing_contributor_profiles.clone(); - if let Some(user) = request.current_user { - fresh_contributors.insert(user); - } + let mut fresh_contributors = request + .missing_contributor_profiles + .union(&request.profiles_to_fetch_from_user_relays) + .copied() + .collect(); let mut report = FetchReport::default(); @@ -870,19 +884,39 @@ async fn create_relays_request( } } - let (current_user, current_user_write_relays) = - get_logged_in_user_and_relays_from_cache(git_repo_path).await?; - if let Some(current_user) = current_user { - missing_contributor_profiles.insert(current_user); - } - missing_contributor_profiles.extend(user_profiles); + let profiles_to_fetch_from_user_relays = { + let mut set = user_profiles.clone(); + if let Ok(Some(current_user)) = get_logged_in_user(git_repo_path).await { + set.insert(current_user); + } + set + }; + + let user_relays_for_profiles = { + let mut set = HashSet::new(); + for user in &profiles_to_fetch_from_user_relays { + if let Ok(user_ref) = get_user_ref_from_cache(git_repo_path, user).await { + for r in user_ref.relays.write() { + if let Ok(url) = Url::parse(&r) { + set.insert(url); + } + } + } else { + missing_contributor_profiles.insert(user.to_owned()); + } + } + set + }; let existing_events: HashSet = { let mut existing_events: HashSet = HashSet::new(); for filter in get_fetch_filters( &repo_coordinates_without_relays, &proposals, - &missing_contributor_profiles, + &missing_contributor_profiles + .union(&profiles_to_fetch_from_user_relays) + .copied() + .collect(), ) { for (id, _) in get_local_cache_database(git_repo_path) .await? @@ -915,7 +949,7 @@ async fn create_relays_request( }; let relay_column_width = relays - .union(¤t_user_write_relays) + .union(&user_relays_for_profiles) .reduce(|a, r| { if r.to_string() .chars() @@ -935,7 +969,7 @@ async fn create_relays_request( Ok(FetchRequest { selected_relay: None, - relays, + repo_relays: relays, relay_column_width, repo_coordinates: if let Ok(repo_ref) = repo_ref { repo_ref.coordinates_with_timestamps() @@ -949,8 +983,8 @@ async fn create_relays_request( contributors, missing_contributor_profiles, existing_events, - current_user, - current_user_write_relays, + profiles_to_fetch_from_user_relays, + user_relays_for_profiles, }) } @@ -1226,7 +1260,7 @@ impl Display for FetchReport { #[derive(Default, Clone)] pub struct FetchRequest { - relays: HashSet, + repo_relays: HashSet, selected_relay: Option, relay_column_width: usize, repo_coordinates: Vec<(Coordinate, Option)>, @@ -1234,6 +1268,6 @@ pub struct FetchRequest { contributors: HashSet, missing_contributor_profiles: HashSet, existing_events: HashSet, - current_user: Option, - current_user_write_relays: HashSet, + profiles_to_fetch_from_user_relays: HashSet, + user_relays_for_profiles: HashSet, } diff --git a/src/login.rs b/src/login.rs index 6c3acfa..aac0141 100644 --- a/src/login.rs +++ b/src/login.rs @@ -6,7 +6,7 @@ use nostr::{ PublicKey, }; use nostr_sdk::{ - Alphabet, FromBech32, JsonUtil, Keys, Kind, NostrSigner, SingleLetterTag, ToBech32, Url, + Alphabet, FromBech32, JsonUtil, Keys, Kind, NostrSigner, SingleLetterTag, ToBech32, }; use nostr_signer::Nip46Signer; @@ -57,7 +57,8 @@ pub async fn launch( get_config_item(git_repo, "nostr.npub") .unwrap_or("unknown ncryptsec".to_string()), ) { - if let Ok(user_ref) = get_user_details(&public_key, client, git_repo).await + if let Ok(user_ref) = + get_user_details(&public_key, client, git_repo.get_path()?).await { user_ref.metadata.name } else { @@ -92,7 +93,7 @@ pub async fn launch( .await .context("cannot get public key from signer")?, client, - git_repo, + git_repo.get_path()?, ) .await?; print_logged_in_as(&user_ref, client.is_none())?; @@ -395,7 +396,7 @@ async fn fresh_login( signer.public_key().await? }; // lookup profile - let user_ref = get_user_details(&public_key, client, git_repo).await?; + let user_ref = get_user_details(&public_key, client, git_repo.get_path()?).await?; print_logged_in_as(&user_ref, client.is_none())?; Ok((signer, user_ref)) } @@ -610,77 +611,75 @@ async fn get_user_details( public_key: &PublicKey, #[cfg(test)] client: Option<&crate::client::MockConnect>, #[cfg(not(test))] client: Option<&Client>, - git_repo: &Repo, + git_repo_path: &Path, ) -> Result { - let filters = vec![ - nostr::Filter::default() - .author(*public_key) - .kind(Kind::Metadata), - nostr::Filter::default() - .author(*public_key) - .kind(Kind::RelayList), - ]; - - let mut events = get_event_from_global_cache(git_repo.get_path()?, filters.clone()).await?; + if let Ok(user_ref) = get_user_ref_from_cache(git_repo_path, public_key).await { + Ok(user_ref) + } else { + let empty = UserRef { + public_key: public_key.to_owned(), + metadata: extract_user_metadata(public_key, &[])?, + relays: extract_user_relays(public_key, &[]), + }; - if let Some(client) = client { - if events.is_empty() { + if let Some(client) = client { let term = console::Term::stderr(); term.write_line("searching for profile...")?; let (_, progress_reporter) = client .fetch_all( - git_repo.get_path()?, + git_repo_path, &HashSet::new(), &HashSet::from_iter(vec![*public_key]), ) .await?; - events = get_event_from_global_cache(git_repo.get_path()?, filters).await?; - if !events.is_empty() { + if let Ok(user_ref) = get_user_ref_from_cache(git_repo_path, public_key).await { progress_reporter.clear()?; // term.clear_last_lines(1)?; + Ok(user_ref) + } else { + Ok(empty) } + } else { + Ok(empty) } } +} +pub async fn get_logged_in_user(git_repo_path: &Path) -> Result> { + let git_repo = Repo::from_path(&git_repo_path.to_path_buf())?; + Ok( + if let Some(npub) = git_repo.get_git_config_item("nostr.npub", None)? { + if let Ok(pubic_key) = PublicKey::parse(npub) { + Some(pubic_key) + } else { + None + } + } else { + None + }, + ) +} + +pub async fn get_user_ref_from_cache( + git_repo_path: &Path, + public_key: &PublicKey, +) -> Result { + let filters = vec![ + nostr::Filter::default() + .author(*public_key) + .kind(Kind::Metadata), + nostr::Filter::default() + .author(*public_key) + .kind(Kind::RelayList), + ]; + + let events = get_event_from_global_cache(git_repo_path, filters.clone()).await?; + if events.is_empty() { + bail!("no metadata and profile list in cache for selected public key"); + } Ok(UserRef { public_key: public_key.to_owned(), metadata: extract_user_metadata(public_key, &events)?, relays: extract_user_relays(public_key, &events), }) } - -pub async fn get_logged_in_user_and_relays_from_cache( - git_repo_path: &Path, -) -> Result<(Option, HashSet)> { - let git_repo = Repo::from_path(&git_repo_path.to_path_buf())?; - let current_user = if let Some(npub) = git_repo.get_git_config_item("nostr.npub", None)? { - if let Ok(pubic_key) = PublicKey::parse(npub) { - Some(pubic_key) - } else { - None - } - } else { - None - }; - let relays = if let Some(current_user) = current_user { - extract_user_relays( - ¤t_user, - &get_event_from_global_cache( - git_repo.get_path()?, - vec![ - nostr::Filter::default() - .author((*current_user).into()) - .kind(Kind::RelayList), - ], - ) - .await?, - ) - .write() - .iter() - .filter_map(|r| Url::parse(r).ok()) - .collect::>() - } else { - HashSet::new() - }; - Ok((current_user, relays)) -} -- cgit v1.2.3