From 948fe972eb2bddf187b79f2673a091b6331cfd90 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Tue, 1 Apr 2025 14:31:34 +0100 Subject: chore: bump rust-nostr v0.37 ~> v0.40 and fix all of the breaking changes --- Cargo.lock | 179 +++++++----------------------- Cargo.toml | 11 +- src/bin/git_remote_nostr/fetch.rs | 2 +- src/bin/git_remote_nostr/main.rs | 4 +- src/bin/git_remote_nostr/push.rs | 17 ++- src/bin/ngit/sub_commands/init.rs | 21 ++-- src/bin/ngit/sub_commands/send.rs | 8 +- src/lib/client.rs | 223 +++++++++++++++++++++++--------------- src/lib/git/mod.rs | 2 +- src/lib/git/nostr_url.rs | 150 ++++++++++++++----------- src/lib/git_events.rs | 42 ++++--- src/lib/login/existing.rs | 2 +- src/lib/login/fresh.rs | 2 +- src/lib/login/key_encryption.rs | 2 +- src/lib/login/mod.rs | 4 +- src/lib/repo_ref.rs | 103 ++++++++++-------- test_utils/Cargo.toml | 8 +- test_utils/src/git.rs | 12 +- test_utils/src/lib.rs | 54 +++++---- test_utils/src/relay.rs | 27 ++--- tests/git_remote_nostr/main.rs | 12 +- tests/ngit_init.rs | 12 +- tests/ngit_list.rs | 15 ++- 23 files changed, 474 insertions(+), 438 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3155370..bcd1090 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,12 +47,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - [[package]] name = "anstream" version = "0.6.18" @@ -302,9 +296,9 @@ dependencies = [ [[package]] name = "async-utility" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a349201d80b4aa18d17a34a182bdd7f8ddf845e9e57d2ea130a12e10ef1e3a47" +checksum = "a34a3b57207a7a1007832416c3e4862378c8451b4e8e093e436f48c2d3d2c151" dependencies = [ "futures-util", "gloo-timers", @@ -314,9 +308,9 @@ dependencies = [ [[package]] name = "async-wsocket" -version = "0.10.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d50cb541e6d09e119e717c64c46ed33f49be7fa592fa805d56c11d6a7ff093c" +checksum = "9a7d8c7d34a225ba919dd9ba44d4b9106d20142da545e086be8ae21d1897e043" dependencies = [ "async-utility", "futures", @@ -325,7 +319,7 @@ dependencies = [ "tokio", "tokio-rustls", "tokio-socks", - "tokio-tungstenite 0.24.0", + "tokio-tungstenite 0.26.2", "url", "wasm-bindgen", "web-sys", @@ -333,12 +327,9 @@ dependencies = [ [[package]] name = "atomic-destructor" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d919cb60ba95c87ba42777e9e246c4e8d658057299b437b7512531ce0a09a23" -dependencies = [ - "tracing", -] +checksum = "ef49f5882e4b6afaac09ad239a4f8c70a24b8f2b0897edb1f706008efd109cf4" [[package]] name = "atomic-waker" @@ -378,16 +369,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "base58ck" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" -dependencies = [ - "bitcoin-internals 0.3.0", - "bitcoin_hashes 0.14.0", -] - [[package]] name = "base64" version = "0.22.1" @@ -417,62 +398,25 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "bitcoin" -version = "0.32.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6bc65742dea50536e35ad42492b234c27904a27f0abdcbce605015cb4ea026" -dependencies = [ - "base58ck", - "bech32", - "bitcoin-internals 0.3.0", - "bitcoin-io", - "bitcoin-units", - "bitcoin_hashes 0.14.0", - "hex-conservative 0.2.1", - "hex_lit", - "secp256k1", - "serde", -] - [[package]] name = "bitcoin-internals" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" -[[package]] -name = "bitcoin-internals" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" -dependencies = [ - "serde", -] - [[package]] name = "bitcoin-io" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" -[[package]] -name = "bitcoin-units" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" -dependencies = [ - "bitcoin-internals 0.3.0", - "serde", -] - [[package]] name = "bitcoin_hashes" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" dependencies = [ - "bitcoin-internals 0.2.0", + "bitcoin-internals", "hex-conservative 0.1.2", ] @@ -1037,12 +981,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1235,9 +1173,9 @@ dependencies = [ [[package]] name = "gloo-timers" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" dependencies = [ "futures-channel", "futures-core", @@ -1256,11 +1194,6 @@ name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash", -] [[package]] name = "heck" @@ -1341,12 +1274,6 @@ dependencies = [ "arrayvec", ] -[[package]] -name = "hex_lit" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" - [[package]] name = "hkdf" version = "0.12.4" @@ -1852,12 +1779,9 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lru" -version = "0.12.5" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" -dependencies = [ - "hashbrown 0.15.2", -] +checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" [[package]] name = "memchr" @@ -1953,9 +1877,9 @@ checksum = "e664971378a3987224f7a0e10059782035e89899ae403718ee07de85bec42afe" [[package]] name = "negentropy" -version = "0.4.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a88da9dd148bbcdce323dd6ac47d369b4769d4a3b78c6c52389b9269f77932" +checksum = "f0efe882e02d206d8d279c20eb40e03baf7cb5136a1476dc084a324fbc3ec42d" [[package]] name = "ngit" @@ -1980,6 +1904,7 @@ dependencies = [ "nostr-connect", "nostr-database", "nostr-lmdb", + "nostr-relay-pool", "nostr-sdk", "once_cell", "passwords", @@ -2026,26 +1951,24 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "nostr" -version = "0.37.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aad4b767bbed24ac5eb4465bfb83bc1210522eb99d67cf4e547ec2ec7e47786" +checksum = "2f900ddcdc28395759fcd44b18a03255e7deee8858551bfe5d5d5a07311d82ea" dependencies = [ "aes", - "async-trait", "base64", "bech32", "bip39", - "bitcoin", + "bitcoin_hashes 0.14.0", "cbc", "chacha20", "chacha20poly1305", "getrandom 0.2.15", "instant", - "negentropy 0.3.1", - "negentropy 0.4.3", - "once_cell", + "regex", "reqwest", "scrypt", + "secp256k1", "serde", "serde_json", "unicode-normalization", @@ -2054,79 +1977,71 @@ dependencies = [ [[package]] name = "nostr-connect" -version = "0.37.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b1bf2a6324d2c1739be462e83d27caa2c025fd7ca14b401b4bc4b7cac11d382" +checksum = "52a0479b5f2da48ddd36061281bc2b3738610a287ad485aae397c44c148b3c6d" dependencies = [ - "async-trait", "async-utility", "nostr", "nostr-relay-pool", - "thiserror 1.0.69", "tokio", "tracing", ] [[package]] name = "nostr-database" -version = "0.37.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23696338d51e45cd44e061823847f4b0d1d362eca80d5033facf9c184149f72f" +checksum = "714512e4653f4e7c4f4abb50a0ac82257541b22087dee780b9e3d787276e88d4" dependencies = [ - "async-trait", "flatbuffers", "lru", "nostr", - "thiserror 1.0.69", "tokio", - "tracing", ] [[package]] name = "nostr-lmdb" -version = "0.37.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70c97ff4e384735527af2dc74b6c8f0042f02daea476bad6c7bb56be32739250" +checksum = "0ca52683835f416e5d4699f19eb616a622de54b75adb954430b1190e94f4e5ca" dependencies = [ + "async-utility", "heed", "nostr", "nostr-database", - "thiserror 1.0.69", "tokio", "tracing", ] [[package]] name = "nostr-relay-pool" -version = "0.37.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15fcc6e3f0ca54d0fc779009bc5f2684cea9147be3b6aa68a7d301ea590f95f5" +checksum = "5bde07a729e0a1b306c9a07da81a0d1d55d0487316017090906f3b6660741b8d" dependencies = [ "async-utility", "async-wsocket", "atomic-destructor", + "lru", "negentropy 0.3.1", - "negentropy 0.4.3", + "negentropy 0.5.0", "nostr", "nostr-database", - "thiserror 1.0.69", "tokio", - "tokio-stream", "tracing", ] [[package]] name = "nostr-sdk" -version = "0.37.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "491221fc89b1aa189a0de640127127d68b4e7c5c1d44371b04d9a6d10694b5af" +checksum = "26238eee805d7dc3abcc8d570068c81cb4285b08e9db4d7999e54e20748c472e" dependencies = [ "async-utility", - "atomic-destructor", "nostr", "nostr-database", "nostr-relay-pool", - "thiserror 1.0.69", "tokio", "tracing", ] @@ -3023,7 +2938,6 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ - "bitcoin_hashes 0.14.0", "rand 0.8.5", "secp256k1-sys", "serde", @@ -3112,7 +3026,6 @@ version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ - "indexmap", "itoa", "memchr", "ryu", @@ -3537,17 +3450,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-stream" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-tungstenite" version = "0.20.1" @@ -3562,9 +3464,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.24.0" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" dependencies = [ "futures-util", "log", @@ -3572,7 +3474,7 @@ dependencies = [ "rustls-pki-types", "tokio", "tokio-rustls", - "tungstenite 0.24.0", + "tungstenite 0.26.2", "webpki-roots", ] @@ -3678,21 +3580,20 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.24.0" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" dependencies = [ - "byteorder", "bytes", "data-encoding", "http 1.3.1", "httparse", "log", - "rand 0.8.5", + "rand 0.9.0", "rustls", "rustls-pki-types", "sha1", - "thiserror 1.0.69", + "thiserror 2.0.12", "utf-8", ] diff --git a/Cargo.toml b/Cargo.toml index 14ef062..57cfb88 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,11 +24,12 @@ futures = "0.3.28" git2 = "0.19.0" indicatif = "0.17.7" keyring = "2.0.5" -nostr = { version = "0.37.0", features = ["nip05", "nip49"] } -nostr-connect = "0.37.0" -nostr-database = "0.37.0" -nostr-lmdb = "0.37.0" -nostr-sdk = "0.37.0" +nostr = { version = "0.40.0", features = ["nip05", "nip49"] } +nostr-connect = "0.40.0" +nostr-database = "0.40.0" +nostr-lmdb = "0.40.0" +nostr-relay-pool = "0.40.1" +nostr-sdk = "0.40.0" passwords = "3.1.13" qrcode = { version = "0.14.1", default-features = false } scrypt = "0.11.0" diff --git a/src/bin/git_remote_nostr/fetch.rs b/src/bin/git_remote_nostr/fetch.rs index 5ee4271..a7210d0 100644 --- a/src/bin/git_remote_nostr/fetch.rs +++ b/src/bin/git_remote_nostr/fetch.rs @@ -115,7 +115,7 @@ pub fn make_commits_for_proposal( author: Some(patch.pubkey), kind: Some(patch.kind), relays: if let Some(relay) = repo_ref.relays.first() { - vec![relay.to_string()] + vec![relay.to_owned()] } else { vec![] }, diff --git a/src/bin/git_remote_nostr/main.rs b/src/bin/git_remote_nostr/main.rs index 44359dd..daa924f 100644 --- a/src/bin/git_remote_nostr/main.rs +++ b/src/bin/git_remote_nostr/main.rs @@ -15,7 +15,7 @@ use anyhow::{Context, Result, bail}; use client::{Connect, consolidate_fetch_reports, get_repo_ref_from_cache}; use git::{RepoActions, nostr_url::NostrUrlDecoded}; use ngit::{client, git, login::existing::load_existing_login}; -use nostr::nips::nip01::Coordinate; +use nostr::nips::nip19::Nip19Coordinate; use utils::read_line; use crate::{client::Client, git::Repo}; @@ -148,7 +148,7 @@ async fn process_args() -> Result> { async fn fetching_with_report_for_helper( git_repo_path: &Path, client: &Client, - trusted_maintainer_coordinate: &Coordinate, + trusted_maintainer_coordinate: &Nip19Coordinate, ) -> Result<()> { let term = console::Term::stderr(); term.write_line("nostr: fetching...")?; diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs index c0085bd..15adc13 100644 --- a/src/bin/git_remote_nostr/push.rs +++ b/src/bin/git_remote_nostr/push.rs @@ -32,7 +32,7 @@ use ngit::{ }; use nostr::nips::nip10::Marker; use nostr_sdk::{ - Event, EventBuilder, EventId, Kind, NostrSigner, PublicKey, RelayUrl, Tag, + Event, EventBuilder, EventId, Kind, NostrSigner, PublicKey, RelayUrl, Tag, TagStandard, hashes::sha1::Hash as Sha1Hash, }; use repo_ref::RepoRef; @@ -1312,7 +1312,13 @@ async fn create_merge_status( repo_ref .coordinates() .iter() - .map(|c| Tag::coordinate(c.clone())) + .map(|c| { + Tag::from_standardized(TagStandard::Coordinate { + coordinate: c.coordinate.clone(), + relay_url: c.relays.first().cloned(), + uppercase: false, + }) + }) .collect::>(), vec![ Tag::from_standardized(nostr::TagStandard::Reference( @@ -1358,7 +1364,7 @@ async fn get_proposal_and_revision_root_from_patch( patch.clone() } else { let proposal_or_revision_id = EventId::parse( - if let Some(t) = patch.tags.iter().find(|t| t.is_root()) { + &if let Some(t) = patch.tags.iter().find(|t| t.is_root()) { t.clone() } else if let Some(t) = patch.tags.iter().find(|t| t.is_reply()) { t.clone() @@ -1389,13 +1395,12 @@ async fn get_proposal_and_revision_root_from_patch( { Ok(( EventId::parse( - proposal_or_revision + &proposal_or_revision .tags .iter() .find(|t| t.is_reply()) .unwrap() - .as_slice()[1] - .clone(), + .as_slice()[1], )?, Some(proposal_or_revision.id), )) diff --git a/src/bin/ngit/sub_commands/init.rs b/src/bin/ngit/sub_commands/init.rs index 4aa7ced..3731e3a 100644 --- a/src/bin/ngit/sub_commands/init.rs +++ b/src/bin/ngit/sub_commands/init.rs @@ -11,6 +11,7 @@ use nostr::{ nips::{ nip01::Coordinate, nip05::{self}, + nip19::Nip19Coordinate, }, }; use nostr_sdk::{Kind, RelayUrl}; @@ -437,10 +438,12 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { // TODO - does this git config item do more harm than good? git_repo.save_git_config_item( "nostr.repo", - &Coordinate { - kind: Kind::GitRepoAnnouncement, - public_key: user_ref.public_key, - identifier: identifier.clone(), + &Nip19Coordinate { + coordinate: Coordinate { + kind: Kind::GitRepoAnnouncement, + public_key: user_ref.public_key, + identifier: identifier.clone(), + }, relays: vec![], } .to_bech32()?, @@ -471,10 +474,12 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { repo_ref.set_nostr_git_url(NostrUrlDecoded { original_string: String::new(), nip05: Some(nip05.clone()), - coordinate: Coordinate { - kind: Kind::GitRepoAnnouncement, - public_key: user_ref.public_key, - identifier: repo_ref.identifier.clone(), + coordinate: Nip19Coordinate { + coordinate: Coordinate { + kind: Kind::GitRepoAnnouncement, + public_key: user_ref.public_key, + identifier: repo_ref.identifier.clone(), + }, relays: if inter.next().is_some() || relays.is_empty() { vec![] } else { diff --git a/src/bin/ngit/sub_commands/send.rs b/src/bin/ngit/sub_commands/send.rs index 7c898bc..9fc00d9 100644 --- a/src/bin/ngit/sub_commands/send.rs +++ b/src/bin/ngit/sub_commands/send.rs @@ -238,7 +238,13 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs, no_fetch: bool) -> Re if root_proposal_id.is_none() { if let Some(event) = events.first() { let event_bech32 = if let Some(relay) = repo_ref.relays.first() { - Nip19Event::new(event.id, vec![relay.to_string()]).to_bech32()? + Nip19Event { + event_id: event.id, + relays: vec![relay.clone()], + author: None, + kind: None, + } + .to_bech32()? } else { event.id.to_bech32()? }; diff --git a/src/lib/client.rs b/src/lib/client.rs index 59ec583..142df64 100644 --- a/src/lib/client.rs +++ b/src/lib/client.rs @@ -29,9 +29,14 @@ use futures::{ use indicatif::{MultiProgress, ProgressBar, ProgressDrawTarget, ProgressState, ProgressStyle}; #[cfg(test)] use mockall::*; -use nostr::{Event, nips::nip01::Coordinate, signer::SignerBackend}; -use nostr_database::NostrEventsDatabase; +use nostr::{ + Event, + nips::{nip01::Coordinate, nip19::Nip19Coordinate}, + signer::SignerBackend, +}; +use nostr_database::{NostrEventsDatabase, SaveEventStatus}; use nostr_lmdb::NostrLMDB; +use nostr_relay_pool::relay::ReqExitPolicy; use nostr_sdk::{ EventBuilder, EventId, Kind, NostrSigner, Options, PublicKey, RelayUrl, SingleLetterTag, Timestamp, prelude::RelayLimits, @@ -89,7 +94,7 @@ pub trait Connect { async fn fetch_all<'a>( &self, git_repo_path: Option<&'a Path>, - repo_coordinates: Option<&'a Coordinate>, + repo_coordinates: Option<&'a Nip19Coordinate>, user_profiles: &HashSet, ) -> Result<(Vec>, MultiProgress)>; async fn fetch_all_from_relay<'a>( @@ -182,8 +187,8 @@ impl Connect for Client { if !relay.is_connected() { #[allow(clippy::large_futures)] - relay - .connect(Some(std::time::Duration::from_secs(CONNECTION_TIMEOUT))) + let _ = relay + .try_connect(std::time::Duration::from_secs(CONNECTION_TIMEOUT)) .await; } @@ -194,7 +199,7 @@ impl Connect for Client { } async fn disconnect(&self) -> Result<()> { - self.client.disconnect().await?; + self.client.disconnect().await; Ok(()) } @@ -223,11 +228,7 @@ impl Connect for Client { self.client.add_relay(url).await?; #[allow(clippy::large_futures)] self.client.connect_relay(url).await?; - self.client - .relay(url) - .await? - .send_event(event.clone()) - .await?; + self.client.relay(url).await?.send_event(&event).await?; if let Some(git_repo_path) = git_repo_path { save_event_in_local_cache(git_repo_path, &event).await?; } @@ -329,7 +330,7 @@ impl Connect for Client { async fn fetch_all<'a>( &self, git_repo_path: Option<&'a Path>, - trusted_maintainer_coordinate: Option<&'a Coordinate>, + trusted_maintainer_coordinate: Option<&'a Nip19Coordinate>, user_profiles: &HashSet, ) -> Result<(Vec>, MultiProgress)> { let fallback_relays = &self @@ -504,7 +505,7 @@ impl Connect for Client { request: FetchRequest, pb: &Option, ) -> Result { - let mut fresh_coordinates: HashSet = HashSet::new(); + let mut fresh_coordinates: HashSet = HashSet::new(); for (c, _) in request.repo_coordinates_without_relays.clone() { fresh_coordinates.insert(c); } @@ -617,8 +618,8 @@ async fn get_events_of( if !relay.is_connected() { #[allow(clippy::large_futures)] - relay - .connect(Some(std::time::Duration::from_secs(CONNECTION_TIMEOUT))) + let _ = relay + .try_connect(std::time::Duration::from_secs(CONNECTION_TIMEOUT)) .await; } @@ -627,16 +628,27 @@ async fn get_events_of( } else if let Some(pb) = pb { pb.set_prefix(format!("connected {}", relay.url())); } - let events = relay - .fetch_events( - filters, - // 20 is nostr_sdk default - std::time::Duration::from_secs(GET_EVENTS_TIMEOUT), - nostr_sdk::FilterOptions::ExitOnEOSE, - ) - .await? - .to_vec(); - Ok(events) + + let events_res = join_all(filters.into_iter().map(|filter| async { + relay + .fetch_events( + filter, + // 20 is nostr_sdk default + std::time::Duration::from_secs(GET_EVENTS_TIMEOUT), + ReqExitPolicy::ExitOnEOSE, + ) + .await + })) + .await; + + // no Event is being mutated, just new items added to the set + #[allow(clippy::mutable_key_type)] + let mut events: HashSet = HashSet::new(); + + for res in events_res { + events.extend(res?); + } + Ok(events.into_iter().collect()) } #[derive(Default)] @@ -770,50 +782,81 @@ pub async fn get_events_from_local_cache( git_repo_path: &Path, filters: Vec, ) -> Result> { - Ok(get_local_cache_database(git_repo_path) - .await? - .query(filters.clone()) - .await - .context( - "failed to execute query on opened git repo nostr cache database .git/nostr-cache.lmdb", - )? - .to_vec()) + let db = get_local_cache_database(git_repo_path).await?; + + let query_results = join_all(filters.into_iter().map(|filter| async { + db.query(filter) + .await + .context("failed to execute query on opened ngit nostr cache database") + })) + .await; + + // no Event is being mutated, just new items added to the set + #[allow(clippy::mutable_key_type)] + let mut events: HashSet = HashSet::new(); + + for result in query_results { + events.extend(result?); + } + + Ok(events.into_iter().collect()) } pub async fn get_event_from_global_cache( git_repo_path: Option<&Path>, filters: Vec, ) -> Result> { - Ok(get_global_cache_database(git_repo_path) - .await? - .query(filters.clone()) - .await - .context("failed to execute query on opened ngit nostr cache database")? - .to_vec()) + let db = get_global_cache_database(git_repo_path).await?; + + let query_results = join_all(filters.into_iter().map(|filter| async { + db.query(filter) + .await + .context("failed to execute query on opened ngit nostr cache database") + })) + .await; + + // no Event is being mutated, just new items added to the set + #[allow(clippy::mutable_key_type)] + let mut events: HashSet = HashSet::new(); + + for result in query_results { + events.extend(result?); + } + + Ok(events.into_iter().collect()) } pub async fn save_event_in_local_cache(git_repo_path: &Path, event: &nostr::Event) -> Result { - get_local_cache_database(git_repo_path) + match get_local_cache_database(git_repo_path) .await? .save_event(event) .await - .context("failed to save event in local cache") + .context("failed to save event in local cache")? + { + SaveEventStatus::Success => Ok(true), + _ => Ok(false), + } } pub async fn save_event_in_global_cache( git_repo_path: Option<&Path>, event: &nostr::Event, ) -> Result { - get_global_cache_database(git_repo_path) + match get_global_cache_database(git_repo_path) .await? .save_event(event) .await .context("failed to save event in local cache") + { + Ok(SaveEventStatus::Success) => Ok(true), + Ok(_) => Ok(false), + Err(e) => Err(e).context("failed to save event in local cache"), + } } pub async fn get_repo_ref_from_cache( git_repo_path: Option<&Path>, - repo_coordinate: &Coordinate, + repo_coordinate: &Nip19Coordinate, ) -> Result { let mut maintainers = HashSet::new(); let mut new_coordinate: bool; @@ -824,10 +867,12 @@ pub async fn get_repo_ref_from_cache( new_coordinate = false; let repo_events_filter = get_filter_repo_events(&HashSet::from_iter(maintainers.iter().map(|m| { - Coordinate { - kind: Kind::GitRepoAnnouncement, - public_key: *m, - identifier: repo_coordinate.identifier.to_string(), + Nip19Coordinate { + coordinate: Coordinate { + kind: Kind::GitRepoAnnouncement, + public_key: *m, + identifier: repo_coordinate.identifier.to_string(), + }, relays: vec![], } }))); @@ -859,19 +904,21 @@ pub async fn get_repo_ref_from_cache( let repo_ref = RepoRef::try_from(( repo_events .first() - .context("no repo announcement event found at specified coordinates. if you are the repository maintainer consider running `ngit init` to create one")? + .context("no repo announcement event found at specified Nip19Coordinates. if you are the repository maintainer consider running `ngit init` to create one")? .clone(), Some(repo_coordinate.public_key), ))?; - let mut events: HashMap = HashMap::new(); + let mut events: HashMap = HashMap::new(); for m in &maintainers { if let Some(e) = repo_events.iter().find(|e| e.pubkey.eq(m)) { events.insert( - Coordinate { - kind: e.kind, - identifier: e.tags.identifier().unwrap().to_string(), - public_key: e.pubkey, + Nip19Coordinate { + coordinate: Coordinate { + kind: e.kind, + identifier: e.tags.identifier().unwrap().to_string(), + public_key: e.pubkey, + }, relays: vec![], }, e.clone(), @@ -912,7 +959,7 @@ pub async fn get_state_from_cache( #[allow(clippy::too_many_lines)] async fn create_relays_request( git_repo_path: Option<&Path>, - trusted_maintainer_coordinate: Option<&Coordinate>, + trusted_maintainer_coordinate: Option<&Nip19Coordinate>, user_profiles: &HashSet, fallback_relays: HashSet, ) -> Result { @@ -929,9 +976,9 @@ async fn create_relays_request( }; let repo_coordinates = { - // add coordinates of users listed in maintainers to explicitly specified - // coodinates - let mut set: HashSet = HashSet::new(); + // add Nip19Coordinates of users listed in maintainers to explicitly + // specified coodinates + let mut set: HashSet = HashSet::new(); if let Some(trusted_maintainer_coordinate) = trusted_maintainer_coordinate { set.insert(trusted_maintainer_coordinate.clone()); } @@ -951,10 +998,12 @@ async fn create_relays_request( let repo_coordinates_without_relays = { let mut set = HashSet::new(); for c in &repo_coordinates { - set.insert(Coordinate { - kind: c.kind, - identifier: c.identifier.clone(), - public_key: c.public_key, + set.insert(Nip19Coordinate { + coordinate: Coordinate { + kind: c.kind, + identifier: c.identifier.clone(), + public_key: c.public_key, + }, relays: vec![], }); } @@ -976,11 +1025,11 @@ async fn create_relays_request( for event in &get_events_from_local_cache(git_repo_path, vec![ nostr::Filter::default() .kinds(vec![Kind::GitPatch]) - .custom_tag( + .custom_tags( SingleLetterTag::lowercase(nostr_sdk::Alphabet::A), repo_coordinates_without_relays .iter() - .map(std::string::ToString::to_string) + .map(|c| c.coordinate.to_string()) .collect::>(), ), ]) @@ -1153,7 +1202,7 @@ async fn process_fetched_events( events: Vec, request: &FetchRequest, git_repo_path: Option<&Path>, - fresh_coordinates: &mut HashSet, + fresh_coordinates: &mut HashSet, fresh_proposal_roots: &mut HashSet, fresh_profiles: &mut HashSet, report: &mut FetchReport, @@ -1188,10 +1237,12 @@ async fn process_fetched_events( }); if update_to_existing { report.updated_repo_announcements.push(( - Coordinate { - kind: event.kind, - public_key: event.pubkey, - identifier: event.tags.identifier().unwrap().to_owned(), + Nip19Coordinate { + coordinate: Coordinate { + kind: event.kind, + public_key: event.pubkey, + identifier: event.tags.identifier().unwrap().to_owned(), + }, relays: vec![], }, event.created_at, @@ -1204,14 +1255,16 @@ async fn process_fetched_events( .repo_coordinates_without_relays // prexisting maintainers .iter() .map(|(c, _)| c.clone()) - .collect::>() + .collect::>() .union(&report.repo_coordinates_without_relays) // already added maintainers .any(|c| c.identifier.eq(&repo_ref.identifier) && m.eq(&c.public_key)) { - let c = Coordinate { - kind: event.kind, - public_key: *m, - identifier: repo_ref.identifier.clone(), + let c = Nip19Coordinate { + coordinate: Coordinate { + kind: event.kind, + public_key: *m, + identifier: repo_ref.identifier.clone(), + }, relays: vec![], }; fresh_coordinates.insert(c.clone()); @@ -1343,7 +1396,7 @@ pub fn consolidate_fetch_reports(reports: Vec>) -> FetchRepo report } pub fn get_fetch_filters( - repo_coordinates: &HashSet, + repo_coordinates: &HashSet, proposal_ids: &HashSet, required_profiles: &HashSet, ) -> Vec { @@ -1356,11 +1409,11 @@ pub fn get_fetch_filters( get_filter_repo_events(repo_coordinates), nostr::Filter::default() .kinds(vec![Kind::GitPatch, Kind::EventDeletion]) - .custom_tag( + .custom_tags( SingleLetterTag::lowercase(nostr_sdk::Alphabet::A), repo_coordinates .iter() - .map(std::string::ToString::to_string) + .map(|c| c.coordinate.to_string()) .collect::>(), ), ] @@ -1383,7 +1436,7 @@ pub fn get_fetch_filters( .concat() } -pub fn get_filter_repo_events(repo_coordinates: &HashSet) -> nostr::Filter { +pub fn get_filter_repo_events(repo_coordinates: &HashSet) -> nostr::Filter { nostr::Filter::default() .kind(Kind::GitRepoAnnouncement) .identifiers( @@ -1401,7 +1454,7 @@ pub fn get_filter_repo_events(repo_coordinates: &HashSet) -> nostr:: } pub static STATE_KIND: nostr::Kind = Kind::Custom(30618); -pub fn get_filter_state_events(repo_coordinates: &HashSet) -> nostr::Filter { +pub fn get_filter_state_events(repo_coordinates: &HashSet) -> nostr::Filter { nostr::Filter::default() .kind(STATE_KIND) .identifiers( @@ -1426,8 +1479,8 @@ pub fn get_filter_contributor_profiles(contributors: HashSet) -> nost #[derive(Default)] pub struct FetchReport { - repo_coordinates_without_relays: HashSet, - updated_repo_announcements: Vec<(Coordinate, Timestamp)>, + repo_coordinates_without_relays: HashSet, + updated_repo_announcements: Vec<(Nip19Coordinate, Timestamp)>, updated_state: Option<(Timestamp, EventId)>, proposals: HashSet, /// commits against existing propoals @@ -1518,7 +1571,7 @@ pub struct FetchRequest { repo_relays: HashSet, selected_relay: Option, relay_column_width: usize, - repo_coordinates_without_relays: Vec<(Coordinate, Option)>, + repo_coordinates_without_relays: Vec<(Nip19Coordinate, Option)>, state: Option<(Timestamp, EventId)>, proposals: HashSet, contributors: HashSet, @@ -1532,7 +1585,7 @@ pub async fn fetching_with_report( git_repo_path: &Path, #[cfg(test)] client: &crate::client::MockConnect, #[cfg(not(test))] client: &Client, - trusted_maintainer_coordinate: &Coordinate, + trusted_maintainer_coordinate: &Nip19Coordinate, ) -> Result { let term = console::Term::stderr(); term.write_line("fetching updates...")?; @@ -1557,16 +1610,16 @@ pub async fn fetching_with_report( pub async fn get_proposals_and_revisions_from_cache( git_repo_path: &Path, - repo_coordinates: HashSet, + repo_coordinates: HashSet, ) -> Result> { let mut proposals = get_events_from_local_cache(git_repo_path, vec![ nostr::Filter::default() .kind(nostr::Kind::GitPatch) - .custom_tag( + .custom_tags( nostr::SingleLetterTag::lowercase(nostr_sdk::Alphabet::A), repo_coordinates .iter() - .map(std::string::ToString::to_string) + .map(|c| c.coordinate.to_string()) .collect::>(), ), ]) diff --git a/src/lib/git/mod.rs b/src/lib/git/mod.rs index 2b78f38..1329820 100644 --- a/src/lib/git/mod.rs +++ b/src/lib/git/mod.rs @@ -1141,7 +1141,7 @@ mod tests { fn test(time: git2::Time) -> Result<()> { assert_eq!( extract_sig_from_patch_tags( - &Tags::new(vec![nostr::Tag::custom( + &Tags::from_list(vec![nostr::Tag::custom( nostr::TagKind::Custom("author".to_string().into()), prep(&time)?, )]), diff --git a/src/lib/git/nostr_url.rs b/src/lib/git/nostr_url.rs index ae0ac5f..54be292 100644 --- a/src/lib/git/nostr_url.rs +++ b/src/lib/git/nostr_url.rs @@ -2,8 +2,8 @@ use core::fmt; use std::{collections::HashMap, str::FromStr}; use anyhow::{Context, Error, Result, anyhow, bail}; -use nostr::nips::{nip01::Coordinate, nip05}; -use nostr_sdk::{PublicKey, RelayUrl, ToBech32, Url}; +use nostr::nips::{nip01::Coordinate, nip05, nip19::Nip19Coordinate}; +use nostr_sdk::{FromBech32, PublicKey, RelayUrl, ToBech32, Url}; use super::{Repo, get_git_config_item, save_git_config_item}; @@ -58,7 +58,7 @@ impl FromStr for ServerProtocol { #[derive(Debug, PartialEq, Clone)] pub struct NostrUrlDecoded { pub original_string: String, - pub coordinate: Coordinate, + pub coordinate: Nip19Coordinate, pub protocol: Option, pub user: Option, pub nip05: Option, @@ -166,7 +166,7 @@ impl NostrUrlDecoded { // extract naddr npub//identifer let part = parts.first().context(INCORRECT_NOSTR_URL_FORMAT_ERROR)?; // naddr used - let coordinate = if let Ok(coordinate) = Coordinate::parse(part) { + let coordinate = if let Ok(coordinate) = Nip19Coordinate::from_bech32(part) { if coordinate.kind.eq(&nostr_sdk::Kind::GitRepoAnnouncement) { coordinate } else { @@ -225,10 +225,12 @@ impl NostrUrlDecoded { } } }; - Coordinate { - identifier, - public_key, - kind: nostr_sdk::Kind::GitRepoAnnouncement, + Nip19Coordinate { + coordinate: Coordinate { + identifier, + public_key, + kind: nostr_sdk::Kind::GitRepoAnnouncement, + }, relays, } }; @@ -959,7 +961,7 @@ mod tests { } } mod nostr_git_url_format { - use nostr::nips::nip01::Coordinate; + use nostr::nips::nip19::Nip19Coordinate; use nostr_sdk::PublicKey; use super::*; @@ -970,13 +972,15 @@ mod tests { assert_eq!( format!("{}", NostrUrlDecoded { original_string: String::new(), - coordinate: Coordinate { - identifier: "ngit".to_string(), - public_key: PublicKey::parse( - "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", - ) - .unwrap(), - kind: nostr_sdk::Kind::GitRepoAnnouncement, + coordinate: Nip19Coordinate { + coordinate: Coordinate { + identifier: "ngit".to_string(), + public_key: PublicKey::parse( + "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", + ) + .unwrap(), + kind: nostr_sdk::Kind::GitRepoAnnouncement, + }, relays: vec![RelayUrl::parse("wss://nos.lol").unwrap()], }, protocol: None, @@ -993,13 +997,15 @@ mod tests { assert_eq!( format!("{}", NostrUrlDecoded { original_string: String::new(), - coordinate: Coordinate { - identifier: "ngit".to_string(), - public_key: PublicKey::parse( - "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", - ) - .unwrap(), - kind: nostr_sdk::Kind::GitRepoAnnouncement, + coordinate: Nip19Coordinate { + coordinate: Coordinate { + identifier: "ngit".to_string(), + public_key: PublicKey::parse( + "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", + ) + .unwrap(), + kind: nostr_sdk::Kind::GitRepoAnnouncement, + }, relays: vec![], }, protocol: None, @@ -1016,13 +1022,15 @@ mod tests { assert_eq!( format!("{}", NostrUrlDecoded { original_string: String::new(), - coordinate: Coordinate { - identifier: "ngit".to_string(), - public_key: PublicKey::parse( - "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", - ) - .unwrap(), - kind: nostr_sdk::Kind::GitRepoAnnouncement, + coordinate: Nip19Coordinate { + coordinate: Coordinate { + identifier: "ngit".to_string(), + public_key: PublicKey::parse( + "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", + ) + .unwrap(), + kind: nostr_sdk::Kind::GitRepoAnnouncement, + }, relays: vec![RelayUrl::parse("wss://nos.lol").unwrap()], }, protocol: Some(ServerProtocol::Ssh), @@ -1039,13 +1047,15 @@ mod tests { assert_eq!( format!("{}", NostrUrlDecoded { original_string: String::new(), - coordinate: Coordinate { - identifier: "ngit".to_string(), - public_key: PublicKey::parse( - "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", - ) - .unwrap(), - kind: nostr_sdk::Kind::GitRepoAnnouncement, + coordinate: Nip19Coordinate { + coordinate: Coordinate { + identifier: "ngit".to_string(), + public_key: PublicKey::parse( + "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", + ) + .unwrap(), + kind: nostr_sdk::Kind::GitRepoAnnouncement, + }, relays: vec![RelayUrl::parse("wss://nos.lol").unwrap()], }, protocol: Some(ServerProtocol::Ssh), @@ -1061,14 +1071,16 @@ mod tests { mod nostr_url_decoded_paramemters_from_str { use super::*; - fn get_model_coordinate(relays: bool) -> Coordinate { - Coordinate { - identifier: "ngit".to_string(), - public_key: PublicKey::parse( - "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", - ) - .unwrap(), - kind: nostr_sdk::Kind::GitRepoAnnouncement, + fn get_model_coordinate(relays: bool) -> Nip19Coordinate { + Nip19Coordinate { + coordinate: Coordinate { + identifier: "ngit".to_string(), + public_key: PublicKey::parse( + "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", + ) + .unwrap(), + kind: nostr_sdk::Kind::GitRepoAnnouncement, + }, relays: if relays { vec![RelayUrl::parse("wss://nos.lol").unwrap()] } else { @@ -1084,13 +1096,15 @@ mod tests { NostrUrlDecoded::parse_and_resolve(&url, &None).await?, NostrUrlDecoded { original_string: url.clone(), - coordinate: Coordinate { - identifier: "ngit".to_string(), - public_key: PublicKey::parse( - "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", - ) - .unwrap(), - kind: nostr_sdk::Kind::GitRepoAnnouncement, + coordinate: Nip19Coordinate { + coordinate: Coordinate { + identifier: "ngit".to_string(), + public_key: PublicKey::parse( + "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", + ) + .unwrap(), + kind: nostr_sdk::Kind::GitRepoAnnouncement, + }, relays: vec![RelayUrl::parse("wss://nos.lol").unwrap()], /* wont add the * slash */ }, @@ -1172,13 +1186,15 @@ mod tests { NostrUrlDecoded::parse_and_resolve(&url, &None).await?, NostrUrlDecoded { original_string: url.clone(), - coordinate: Coordinate { - identifier: "ngit".to_string(), - public_key: PublicKey::parse( - "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", - ) - .unwrap(), - kind: nostr_sdk::Kind::GitRepoAnnouncement, + coordinate: Nip19Coordinate { + coordinate: Coordinate { + identifier: "ngit".to_string(), + public_key: PublicKey::parse( + "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", + ) + .unwrap(), + kind: nostr_sdk::Kind::GitRepoAnnouncement, + }, relays: vec![ RelayUrl::parse("wss://nos.lol/").unwrap(), RelayUrl::parse("wss://relay.damus.io/").unwrap(), @@ -1274,13 +1290,15 @@ mod tests { NostrUrlDecoded::parse_and_resolve(&url, &None).await?, NostrUrlDecoded { original_string: url.clone(), - coordinate: Coordinate { - identifier: "ngit".to_string(), - public_key: PublicKey::parse( - "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", - ) - .unwrap(), - kind: nostr_sdk::Kind::GitRepoAnnouncement, + coordinate: Nip19Coordinate { + coordinate: Coordinate { + identifier: "ngit".to_string(), + public_key: PublicKey::parse( + "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", + ) + .unwrap(), + kind: nostr_sdk::Kind::GitRepoAnnouncement, + }, relays: vec![ RelayUrl::parse("wss://nos.lol/").unwrap(), RelayUrl::parse("wss://relay.damus.io/").unwrap(), diff --git a/src/lib/git_events.rs b/src/lib/git_events.rs index 559155a..2b3df42 100644 --- a/src/lib/git_events.rs +++ b/src/lib/git_events.rs @@ -3,7 +3,7 @@ use std::{str::FromStr, sync::Arc}; use anyhow::{Context, Result, bail}; use nostr::nips::{nip01::Coordinate, nip10::Marker, nip19::Nip19}; use nostr_sdk::{ - Event, EventBuilder, EventId, FromBech32, Kind, NostrSigner, PublicKey, RelayUrl, Tag, TagKind, + Event, EventBuilder, EventId, FromBech32, Kind, NostrSigner, PublicKey, Tag, TagKind, TagStandard, hashes::sha1::Hash as Sha1Hash, }; @@ -115,11 +115,14 @@ pub async fn generate_patch_event( .maintainers .iter() .map(|m| { - Tag::coordinate(Coordinate { - kind: nostr::Kind::GitRepoAnnouncement, - public_key: *m, - identifier: repo_ref.identifier.to_string(), - relays: repo_ref.relays.clone(), + Tag::from_standardized(TagStandard::Coordinate { + coordinate: Coordinate { + kind: nostr::Kind::GitRepoAnnouncement, + public_key: *m, + identifier: repo_ref.identifier.to_string(), + }, + relay_url: repo_ref.relays.first().cloned(), + uppercase: false, }) }) .collect::>(), @@ -257,12 +260,12 @@ pub fn event_tag_from_nip19_or_hex( PromptInputParms::default().with_prompt(format!("{reference_name} reference")), )?; } - if let Ok(nip19) = Nip19::from_bech32(bech32.clone()) { + if let Ok(nip19) = Nip19::from_bech32(&bech32) { match nip19 { Nip19::Event(n) => { break Ok(Tag::from_standardized(nostr_sdk::TagStandard::Event { event_id: n.event_id, - relay_url: n.relays.first().and_then(|url| RelayUrl::parse(url).ok()), + relay_url: n.relays.first().cloned(), marker: Some(marker), public_key: None, uppercase: false, @@ -278,7 +281,11 @@ pub fn event_tag_from_nip19_or_hex( })); } Nip19::Coordinate(coordinate) => { - break Ok(Tag::coordinate(coordinate)); + break Ok(Tag::from_standardized(TagStandard::Coordinate { + coordinate: coordinate.coordinate, + relay_url: coordinate.relays.first().cloned(), + uppercase: false, + })); } Nip19::Profile(profile) => { if allow_npub_reference { @@ -338,12 +345,17 @@ pub async fn generate_cover_letter_and_patch_events( )) .tags( [ - repo_ref.maintainers.iter().map(|m| Tag::coordinate(Coordinate { - kind: nostr::Kind::GitRepoAnnouncement, - public_key: *m, - identifier: repo_ref.identifier.to_string(), - relays: repo_ref.relays.clone(), - })).collect::>(), + repo_ref.maintainers.iter().map(|m| + Tag::from_standardized(TagStandard::Coordinate { + coordinate: Coordinate { + kind: nostr::Kind::GitRepoAnnouncement, + public_key: *m, + identifier: repo_ref.identifier.to_string(), + }, + relay_url: repo_ref.relays.first().cloned(), + uppercase: false, + }) + ).collect::>(), vec![ Tag::from_standardized(TagStandard::Reference(format!("{root_commit}"))), Tag::hashtag("cover-letter"), diff --git a/src/lib/login/existing.rs b/src/lib/login/existing.rs index efe187e..e60621d 100644 --- a/src/lib/login/existing.rs +++ b/src/lib/login/existing.rs @@ -208,7 +208,7 @@ async fn get_signer( Duration::from_secs(10 * 60), None, )?; - if let Some(public_key) = npub.clone().and_then(|npub| PublicKey::parse(npub).ok()) { + if let Some(public_key) = npub.clone().and_then(|npub| PublicKey::parse(&npub).ok()) { s.non_secure_set_user_public_key(public_key)?; let signer: Arc = Arc::new(s); Ok((signer, public_key)) diff --git a/src/lib/login/fresh.rs b/src/lib/login/fresh.rs index 635c0b3..76998ff 100644 --- a/src/lib/login/fresh.rs +++ b/src/lib/login/fresh.rs @@ -372,7 +372,7 @@ pub fn generate_nostr_connect_app( client .get_fallback_signer_relays() .iter() - .flat_map(RelayUrl::parse) + .flat_map(|s| RelayUrl::parse(s)) .collect::>() } else { vec![] diff --git a/src/lib/login/key_encryption.rs b/src/lib/login/key_encryption.rs index efb38d1..d57b3b5 100644 --- a/src/lib/login/key_encryption.rs +++ b/src/lib/login/key_encryption.rs @@ -7,7 +7,7 @@ pub fn decrypt_key(encrypted_key: &str, password: &str) -> Result { if encrypted_key.log_n() > 14 { println!("this may take a few seconds..."); } - Ok(nostr::Keys::new(encrypted_key.to_secret_key(password)?)) + Ok(nostr::Keys::new(encrypted_key.decrypt(password)?)) } #[cfg(test)] diff --git a/src/lib/login/mod.rs b/src/lib/login/mod.rs index a1c45d5..c37375f 100644 --- a/src/lib/login/mod.rs +++ b/src/lib/login/mod.rs @@ -93,7 +93,7 @@ pub async fn get_likely_logged_in_user(git_repo_path: &Path) -> Result Result Result> { Ok( if let Some(npub) = git_repo.get_git_config_item("nostr.npub", None)? { - if let Ok(public_key) = PublicKey::parse(npub) { + if let Ok(public_key) = PublicKey::parse(&npub) { Some(public_key) } else { None diff --git a/src/lib/repo_ref.rs b/src/lib/repo_ref.rs index 38f6774..b21a911 100644 --- a/src/lib/repo_ref.rs +++ b/src/lib/repo_ref.rs @@ -8,7 +8,10 @@ use std::{ use anyhow::{Context, Result, bail}; use console::Style; -use nostr::{FromBech32, PublicKey, Tag, TagStandard, ToBech32, nips::nip01::Coordinate}; +use nostr::{ + FromBech32, PublicKey, Tag, TagStandard, ToBech32, + nips::{nip01::Coordinate, nip19::Nip19Coordinate}, +}; use nostr_sdk::{Kind, NostrSigner, RelayUrl, Timestamp}; use serde::{Deserialize, Serialize}; @@ -37,7 +40,7 @@ pub struct RepoRef { pub relays: Vec, pub maintainers: Vec, pub trusted_maintainer: PublicKey, - pub events: HashMap, + pub events: HashMap, pub nostr_git_url: Option, } @@ -119,10 +122,12 @@ impl TryFrom<(nostr::Event, Option)> for RepoRef { } r.events = HashMap::new(); r.events.insert( - Coordinate { - kind: event.kind, - identifier: event.tags.identifier().unwrap().to_string(), - public_key: event.pubkey, + Nip19Coordinate { + coordinate: Coordinate { + kind: event.kind, + identifier: event.tags.identifier().unwrap().to_string(), + public_key: event.pubkey, + }, relays: vec![], }, event, @@ -195,20 +200,24 @@ impl RepoRef { .context("failed to create repository reference event") } /// coordinates without relay hints - pub fn coordinates(&self) -> HashSet { + pub fn coordinates(&self) -> HashSet { let mut res = HashSet::new(); - res.insert(Coordinate { - kind: Kind::GitRepoAnnouncement, - public_key: self.trusted_maintainer, - identifier: self.identifier.clone(), + res.insert(Nip19Coordinate { + coordinate: Coordinate { + kind: Kind::GitRepoAnnouncement, + public_key: self.trusted_maintainer, + identifier: self.identifier.clone(), + }, relays: vec![], }); for m in &self.maintainers { - res.insert(Coordinate { - kind: Kind::GitRepoAnnouncement, - public_key: *m, - identifier: self.identifier.clone(), + res.insert(Nip19Coordinate { + coordinate: Coordinate { + kind: Kind::GitRepoAnnouncement, + public_key: *m, + identifier: self.identifier.clone(), + }, relays: vec![], }); } @@ -216,11 +225,13 @@ impl RepoRef { } /// coordinates without relay hints - pub fn coordinate_with_hint(&self) -> Coordinate { - Coordinate { - kind: Kind::GitRepoAnnouncement, - public_key: self.trusted_maintainer, - identifier: self.identifier.clone(), + pub fn coordinate_with_hint(&self) -> Nip19Coordinate { + Nip19Coordinate { + coordinate: Coordinate { + kind: Kind::GitRepoAnnouncement, + public_key: self.trusted_maintainer, + identifier: self.identifier.clone(), + }, relays: if let Some(relay) = self.relays.first() { vec![relay.clone()] } else { @@ -230,11 +241,11 @@ impl RepoRef { } /// coordinates without relay hints - pub fn coordinates_with_timestamps(&self) -> Vec<(Coordinate, Option)> { + pub fn coordinates_with_timestamps(&self) -> Vec<(Nip19Coordinate, Option)> { self.coordinates() .iter() .map(|c| (c.clone(), self.events.get(c).map(|e| e.created_at))) - .collect::)>>() + .collect::)>>() } pub fn set_nostr_git_url(&mut self, nostr_git_url: NostrUrlDecoded) { @@ -264,7 +275,7 @@ pub async fn get_repo_coordinates_when_remote_unknown( git_repo: &Repo, #[cfg(test)] client: &crate::client::MockConnect, #[cfg(not(test))] client: &Client, -) -> Result { +) -> Result { if let Ok(c) = try_and_get_repo_coordinates_when_remote_unknown(git_repo).await { Ok(c) } else { @@ -274,7 +285,7 @@ pub async fn get_repo_coordinates_when_remote_unknown( pub async fn try_and_get_repo_coordinates_when_remote_unknown( git_repo: &Repo, -) -> Result { +) -> Result { let remote_coordinates = get_repo_coordinates_from_nostr_remotes(git_repo).await?; if remote_coordinates.is_empty() { if let Ok(c) = get_repo_coordinates_from_git_config(git_repo) { @@ -318,7 +329,7 @@ pub async fn try_and_get_repo_coordinates_when_remote_unknown( async fn get_nostr_git_remote_selection_labels( git_repo: &Repo, - remote_coordinates: &HashMap, + remote_coordinates: &HashMap, ) -> Result> { let mut res = vec![]; for (remote, c) in remote_coordinates { @@ -334,9 +345,9 @@ async fn get_nostr_git_remote_selection_labels( Ok(res) } -fn get_repo_coordinates_from_git_config(git_repo: &Repo) -> Result { - Coordinate::parse( - git_repo +fn get_repo_coordinates_from_git_config(git_repo: &Repo) -> Result { + Nip19Coordinate::from_bech32( + &git_repo .get_git_config_item("nostr.repo", Some(false))? .context("git config item \"nostr.repo\" is not set in local repository")?, ) @@ -345,7 +356,7 @@ fn get_repo_coordinates_from_git_config(git_repo: &Repo) -> Result { async fn get_repo_coordinates_from_nostr_remotes( git_repo: &Repo, -) -> Result> { +) -> Result> { let mut repo_coordinates = HashMap::new(); for remote_name in git_repo.git_repo.remotes()?.iter().flatten() { if let Some(remote_url) = git_repo.git_repo.find_remote(remote_name)?.url() { @@ -359,21 +370,23 @@ async fn get_repo_coordinates_from_nostr_remotes( Ok(repo_coordinates) } -async fn get_repo_coordinates_from_maintainers_yaml(git_repo: &Repo) -> Result { +async fn get_repo_coordinates_from_maintainers_yaml(git_repo: &Repo) -> Result { let repo_config = get_repo_config_from_yaml(git_repo)?; - Ok(Coordinate { - identifier: repo_config - .identifier - .context("maintainers.yaml doesnt list the identifier")?, - kind: Kind::GitRepoAnnouncement, - public_key: PublicKey::from_bech32( - repo_config - .maintainers - .first() - .context("maintainers.yaml doesnt list any maintainers")?, - ) - .context("maintainers.yaml doesn't list the first maintainer using a valid npub")?, + Ok(Nip19Coordinate { + coordinate: Coordinate { + identifier: repo_config + .identifier + .context("maintainers.yaml doesnt list the identifier")?, + kind: Kind::GitRepoAnnouncement, + public_key: PublicKey::from_bech32( + repo_config + .maintainers + .first() + .context("maintainers.yaml doesnt list any maintainers")?, + ) + .context("maintainers.yaml doesn't list the first maintainer using a valid npub")?, + }, relays: repo_config .relays .iter() @@ -386,7 +399,7 @@ async fn get_repo_coordinate_from_user_prompt( git_repo: &Repo, #[cfg(test)] client: &crate::client::MockConnect, #[cfg(not(test))] client: &Client, -) -> Result { +) -> Result { // TODO: present list of events filter by root_commit // TODO: fallback to search based on identifier let dim = Style::new().color256(247); @@ -401,7 +414,7 @@ async fn get_repo_coordinate_from_user_prompt( loop { let input = Interactor::default() .input(PromptInputParms::default().with_prompt("nostr repository"))?; - let coordinate = if let Ok(c) = Coordinate::parse(&input) { + let coordinate = if let Ok(c) = Nip19Coordinate::from_bech32(&input) { c } else if let Ok(nostr_url) = NostrUrlDecoded::parse_and_resolve(&input, &Some(git_repo)).await @@ -491,7 +504,7 @@ pub fn extract_pks(pk_strings: Vec) -> Result> { let mut pks: Vec = vec![]; for s in pk_strings { pks.push( - nostr_sdk::prelude::PublicKey::from_bech32(s.clone()).context(format!( + nostr_sdk::prelude::PublicKey::from_bech32(&s).context(format!( "failed to convert {s} into a valid nostr public key" ))?, ); diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index b354ff4..951bd39 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -10,10 +10,10 @@ dialoguer = "0.10.4" directories = "5.0.1" futures = "0.3.28" git2 = "0.19.0" -nostr = "0.37.0" -nostr-database = "0.37.0" -nostr-lmdb = "0.37.0" -nostr-sdk = "0.37.0" +nostr = "0.40.0" +nostr-database = "0.40.0" +nostr-lmdb = "0.40.0" +nostr-sdk = "0.40.0" once_cell = "1.18.0" rand = "0.8" rexpect = { git = "https://github.com/rust-cli/rexpect.git", rev = "9eb61dd" } diff --git a/test_utils/src/git.rs b/test_utils/src/git.rs index 474fc59..5942a54 100644 --- a/test_utils/src/git.rs +++ b/test_utils/src/git.rs @@ -9,7 +9,7 @@ use std::{ use anyhow::{Context, Result}; use git2::{Branch, Oid, RepositoryInitOptions, Signature, Time}; -use nostr::nips::nip01::Coordinate; +use nostr::nips::{nip01::Coordinate, nip19::Nip19Coordinate}; use nostr_sdk::{Kind, RelayUrl, ToBech32}; use crate::generate_repo_ref_event; @@ -23,10 +23,12 @@ pub struct GitTestRepo { impl Default for GitTestRepo { fn default() -> Self { let repo_event = generate_repo_ref_event(); - let coordinate = Coordinate { - kind: Kind::GitRepoAnnouncement, - public_key: repo_event.pubkey, - identifier: repo_event.tags.identifier().unwrap().to_string(), + let coordinate = Nip19Coordinate { + coordinate: Coordinate { + kind: Kind::GitRepoAnnouncement, + public_key: repo_event.pubkey, + identifier: repo_event.tags.identifier().unwrap().to_string(), + }, relays: vec![ RelayUrl::parse("ws://localhost:8055").unwrap(), RelayUrl::parse("ws://localhost:8056").unwrap(), diff --git a/test_utils/src/lib.rs b/test_utils/src/lib.rs index 5c8d7a5..66d0df5 100644 --- a/test_utils/src/lib.rs +++ b/test_utils/src/lib.rs @@ -1,4 +1,5 @@ use std::{ + collections::HashSet, ffi::OsStr, path::{Path, PathBuf}, str::FromStr, @@ -8,13 +9,13 @@ use std::{ use anyhow::{Context, Result, bail, ensure}; use dialoguer::theme::{ColorfulTheme, Theme}; -use futures::executor::block_on; +use futures::{executor::block_on, future::join_all}; use git::GitTestRepo; use git2::{Signature, Time}; use nostr::{self, Kind, Tag, nips::nip65::RelayMetadata}; use nostr_database::NostrEventsDatabase; use nostr_lmdb::NostrLMDB; -use nostr_sdk::{Client, NostrSigner, TagStandard, serde_json}; +use nostr_sdk::{Client, Event, NostrSigner, TagStandard, serde_json}; use once_cell::sync::Lazy; use rexpect::session::{Options, PtySession}; use strip_ansi_escapes::strip_str; @@ -139,7 +140,7 @@ pub fn make_event_old_or_change_user( &keys.public_key(), &unsigned.created_at, &unsigned.kind, - &unsigned.tags.clone().to_vec(), + &unsigned.tags.clone(), &unsigned.content, )); @@ -1107,14 +1108,24 @@ pub async fn get_events_from_cache( git_repo_path: &Path, filters: Vec, ) -> Result> { - Ok(get_local_cache_database(git_repo_path) - .await? - .query(filters.clone()) - .await - .context( + let db = get_local_cache_database(git_repo_path).await?; + + let query_results = join_all(filters.into_iter().map(|filter| async { + db.query(filter).await.context( "failed to execute query on opened git repo nostr cache database .git/nostr-cache.lmdb", - )? - .to_vec()) + ) + })) + .await; + + // no Event is being mutated, just new items added to the set + #[allow(clippy::mutable_key_type)] + let mut events: HashSet = HashSet::new(); + + for result in query_results { + events.extend(result?); + } + + Ok(events.into_iter().collect()) } pub fn get_proposal_branch_name( @@ -1436,19 +1447,18 @@ fn get_first_proposal_event_id() -> Result { Handle::current().block_on(client.add_relay("ws://localhost:8055"))?; Handle::current().block_on(client.connect_relay("ws://localhost:8055"))?; let proposals = Handle::current() - .block_on(client.fetch_events( - vec![ - nostr::Filter::default() - .kind(nostr::Kind::GitPatch) - .custom_tag( - nostr::SingleLetterTag::lowercase(nostr::Alphabet::T), - vec!["root"], - ), - ], - Some(Duration::from_millis(500)), - ))? + .block_on( + client.fetch_events( + nostr::Filter::default() + .kind(nostr::Kind::GitPatch) + .custom_tags(nostr::SingleLetterTag::lowercase(nostr::Alphabet::T), vec![ + "root", + ]), + Duration::from_millis(500), + ), + )? .to_vec(); - Handle::current().block_on(client.disconnect())?; + Handle::current().block_on(client.disconnect()); let proposal_1_id = proposals .iter() diff --git a/test_utils/src/relay.rs b/test_utils/src/relay.rs index 634b2d6..e820651 100644 --- a/test_utils/src/relay.rs +++ b/test_utils/src/relay.rs @@ -48,7 +48,7 @@ impl<'a> Relay<'a> { let ok_json = RelayMessage::Ok { event_id: event.id, status: error.is_none(), - message: error.unwrap_or("").to_string(), + message: error.unwrap_or("").to_string().into(), } .as_json(); // bail!(format!("{}", &ok_json)); @@ -63,7 +63,7 @@ impl<'a> Relay<'a> { let responder = self.clients.get(&client_id).unwrap(); Ok(responder.send(simple_websockets::Message::Text( - RelayMessage::EndOfStoredEvents(subscription_id).as_json(), + RelayMessage::EndOfStoredEvents(std::borrow::Cow::Borrowed(&subscription_id)).as_json(), ))) } @@ -79,8 +79,8 @@ impl<'a> Relay<'a> { for event in events { let res = responder.send(simple_websockets::Message::Text( RelayMessage::Event { - subscription_id: subscription_id.clone(), - event: Box::new(event.clone()), + subscription_id: std::borrow::Cow::Borrowed(subscription_id), + event: std::borrow::Cow::Borrowed(event), } .as_json(), )); @@ -156,12 +156,14 @@ impl<'a> Relay<'a> { } } - if let Ok((subscription_id, filters)) = get_nreq(&message) { - self.reqs.push(filters.clone()); + if let Ok((subscription_id, filter)) = get_nreq(&message) { + self.reqs.push(vec![filter.clone()]); if let Some(listner) = self.req_listener { - listner(self, client_id, subscription_id, filters)?; + listner(self, client_id, subscription_id, vec![filter.clone()])?; } else { - self.respond_standard_req(client_id, &subscription_id, &filters)?; + self.respond_standard_req(client_id, &subscription_id, &[ + filter.clone() + ])?; // self.respond_eose(client_id, subscription_id)?; } // respond with events @@ -198,8 +200,7 @@ fn get_nevent(message: &simple_websockets::Message) -> Result { if let simple_websockets::Message::Text(s) = message.clone() { let cm_result = ClientMessage::from_json(s); if let Ok(ClientMessage::Event(event)) = cm_result { - let e = *event; - return Ok(e.clone()); + return Ok(event.into_owned()); } } bail!("not nostr event") @@ -207,15 +208,15 @@ fn get_nevent(message: &simple_websockets::Message) -> Result { fn get_nreq( message: &simple_websockets::Message, -) -> Result<(nostr::SubscriptionId, Vec)> { +) -> Result<(nostr::SubscriptionId, nostr::Filter)> { if let simple_websockets::Message::Text(s) = message.clone() { let cm_result = ClientMessage::from_json(s); if let Ok(ClientMessage::Req { subscription_id, - filters, + filter, }) = cm_result { - return Ok((subscription_id, filters)); + return Ok((subscription_id.into_owned(), filter.into_owned())); } } bail!("not nostr event") diff --git a/tests/git_remote_nostr/main.rs b/tests/git_remote_nostr/main.rs index 686a5df..6b51825 100644 --- a/tests/git_remote_nostr/main.rs +++ b/tests/git_remote_nostr/main.rs @@ -3,7 +3,7 @@ use std::{collections::HashSet, env::current_dir}; use anyhow::{Context, Result}; use futures::join; use git2::Oid; -use nostr::nips::nip01::Coordinate; +use nostr::nips::{nip01::Coordinate, nip19::Nip19Coordinate}; use nostr_sdk::{Event, JsonUtil, Kind, RelayUrl, ToBech32, secp256k1::rand}; use relay::Relay; use serial_test::serial; @@ -18,10 +18,12 @@ static STATE_KIND: nostr::Kind = Kind::Custom(30618); fn get_nostr_remote_url() -> Result { let repo_event = generate_repo_ref_event(); - let naddr = Coordinate { - kind: Kind::GitRepoAnnouncement, - public_key: repo_event.pubkey, - identifier: repo_event.tags.identifier().unwrap().to_string(), + let naddr = Nip19Coordinate { + coordinate: Coordinate { + kind: Kind::GitRepoAnnouncement, + public_key: repo_event.pubkey, + identifier: repo_event.tags.identifier().unwrap().to_string(), + }, relays: vec![ RelayUrl::parse("ws://localhost:8055").unwrap(), RelayUrl::parse("ws://localhost:8056").unwrap(), diff --git a/tests/ngit_init.rs b/tests/ngit_init.rs index 4b61559..409bd51 100644 --- a/tests/ngit_init.rs +++ b/tests/ngit_init.rs @@ -194,7 +194,7 @@ mod when_repo_not_previously_claimed { mod git_config_updated { - use nostr::nips::nip01::Coordinate; + use nostr::nips::{nip01::Coordinate, nip19::Nip19Coordinate}; use nostr_sdk::ToBech32; use super::*; @@ -236,10 +236,12 @@ mod when_repo_not_previously_claimed { .get_entry("nostr.repo")? .value() .unwrap(), - Coordinate { - kind: nostr_sdk::Kind::GitRepoAnnouncement, - identifier: "example-identifier".to_string(), - public_key: TEST_KEY_1_KEYS.public_key(), + Nip19Coordinate { + coordinate: Coordinate { + kind: nostr_sdk::Kind::GitRepoAnnouncement, + identifier: "example-identifier".to_string(), + public_key: TEST_KEY_1_KEYS.public_key(), + }, relays: vec![], } .to_bech32()?, diff --git a/tests/ngit_list.rs b/tests/ngit_list.rs index 4a3aad5..bb742cf 100644 --- a/tests/ngit_list.rs +++ b/tests/ngit_list.rs @@ -49,7 +49,10 @@ async fn prep_proposals_repo_and_repo_with_proposal_pulled_and_checkedout( mod cannot_find_repo_event { use super::*; mod cli_prompts { - use nostr::{ToBech32, nips::nip01::Coordinate}; + use nostr::{ + ToBech32, + nips::{nip01::Coordinate, nip19::Nip19Coordinate}, + }; use nostr_sdk::RelayUrl; use super::*; @@ -87,10 +90,12 @@ mod cannot_find_repo_event { } if naddr { let mut input = p.expect_input("nostr repository")?; - let coordinate = Coordinate { - kind: nostr::Kind::GitRepoAnnouncement, - public_key: TEST_KEY_1_KEYS.public_key(), - identifier: repo_event.tags.identifier().unwrap().to_string(), + let coordinate = Nip19Coordinate { + coordinate: Coordinate { + kind: nostr::Kind::GitRepoAnnouncement, + public_key: TEST_KEY_1_KEYS.public_key(), + identifier: repo_event.tags.identifier().unwrap().to_string(), + }, relays: vec![RelayUrl::parse("ws://localhost:8056").unwrap()], }; input.succeeds_with(&coordinate.to_bech32()?)?; -- cgit v1.2.3