upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/client.rs73
-rw-r--r--src/lib/git/nostr_url.rs31
-rw-r--r--src/lib/git_events.rs19
-rw-r--r--src/lib/login/fresh.rs12
-rw-r--r--src/lib/repo_ref.rs29
5 files changed, 89 insertions, 75 deletions
diff --git a/src/lib/client.rs b/src/lib/client.rs
index 7093dd5..051aa3d 100644
--- a/src/lib/client.rs
+++ b/src/lib/client.rs
@@ -30,11 +30,11 @@ use indicatif::{MultiProgress, ProgressBar, ProgressDrawTarget, ProgressState, P
30#[cfg(test)] 30#[cfg(test)]
31use mockall::*; 31use mockall::*;
32use nostr::{nips::nip01::Coordinate, Event}; 32use nostr::{nips::nip01::Coordinate, Event};
33use nostr_database::NostrDatabase; 33use nostr_database::NostrEventsDatabase;
34use nostr_lmdb::NostrLMDB; 34use nostr_lmdb::NostrLMDB;
35use nostr_sdk::{ 35use nostr_sdk::{
36 prelude::RelayLimits, EventBuilder, EventId, Kind, NostrSigner, Options, PublicKey, 36 prelude::RelayLimits, EventBuilder, EventId, Kind, NostrSigner, Options, PublicKey, RelayUrl,
37 SingleLetterTag, Timestamp, Url, 37 SingleLetterTag, Timestamp,
38}; 38};
39 39
40use crate::{ 40use crate::{
@@ -63,7 +63,7 @@ pub trait Connect {
63 fn default() -> Self; 63 fn default() -> Self;
64 fn new(opts: Params) -> Self; 64 fn new(opts: Params) -> Self;
65 async fn set_signer(&mut self, signer: Arc<dyn NostrSigner>); 65 async fn set_signer(&mut self, signer: Arc<dyn NostrSigner>);
66 async fn connect(&self, relay_url: &Url) -> Result<()>; 66 async fn connect(&self, relay_url: &RelayUrl) -> Result<()>;
67 async fn disconnect(&self) -> Result<()>; 67 async fn disconnect(&self) -> Result<()>;
68 fn get_fallback_relays(&self) -> &Vec<String>; 68 fn get_fallback_relays(&self) -> &Vec<String>;
69 fn get_more_fallback_relays(&self) -> &Vec<String>; 69 fn get_more_fallback_relays(&self) -> &Vec<String>;
@@ -82,7 +82,7 @@ pub trait Connect {
82 ) -> Result<Vec<nostr::Event>>; 82 ) -> Result<Vec<nostr::Event>>;
83 async fn get_events_per_relay( 83 async fn get_events_per_relay(
84 &self, 84 &self,
85 relays: Vec<Url>, 85 relays: Vec<RelayUrl>,
86 filters: Vec<nostr::Filter>, 86 filters: Vec<nostr::Filter>,
87 progress_reporter: MultiProgress, 87 progress_reporter: MultiProgress,
88 ) -> Result<(Vec<Result<Vec<nostr::Event>>>, MultiProgress)>; 88 ) -> Result<(Vec<Result<Vec<nostr::Event>>>, MultiProgress)>;
@@ -172,7 +172,7 @@ impl Connect for Client {
172 self.client.set_signer(signer).await; 172 self.client.set_signer(signer).await;
173 } 173 }
174 174
175 async fn connect(&self, relay_url: &Url) -> Result<()> { 175 async fn connect(&self, relay_url: &RelayUrl) -> Result<()> {
176 self.client 176 self.client
177 .add_relay(relay_url) 177 .add_relay(relay_url)
178 .await 178 .await
@@ -244,7 +244,7 @@ impl Connect for Client {
244 ) -> Result<Vec<nostr::Event>> { 244 ) -> Result<Vec<nostr::Event>> {
245 let (relay_results, _) = self 245 let (relay_results, _) = self
246 .get_events_per_relay( 246 .get_events_per_relay(
247 relays.iter().map(|r| Url::parse(r).unwrap()).collect(), 247 relays.iter().map(|r| RelayUrl::parse(r).unwrap()).collect(),
248 filters, 248 filters,
249 MultiProgress::new(), 249 MultiProgress::new(),
250 ) 250 )
@@ -254,7 +254,7 @@ impl Connect for Client {
254 254
255 async fn get_events_per_relay( 255 async fn get_events_per_relay(
256 &self, 256 &self,
257 relays: Vec<Url>, 257 relays: Vec<RelayUrl>,
258 filters: Vec<nostr::Filter>, 258 filters: Vec<nostr::Filter>,
259 progress_reporter: MultiProgress, 259 progress_reporter: MultiProgress,
260 ) -> Result<(Vec<Result<Vec<nostr::Event>>>, MultiProgress)> { 260 ) -> Result<(Vec<Result<Vec<nostr::Event>>>, MultiProgress)> {
@@ -335,8 +335,8 @@ impl Connect for Client {
335 let fallback_relays = &self 335 let fallback_relays = &self
336 .fallback_relays 336 .fallback_relays
337 .iter() 337 .iter()
338 .filter_map(|r| Url::parse(r).ok()) 338 .filter_map(|r| RelayUrl::parse(r).ok())
339 .collect::<HashSet<Url>>(); 339 .collect::<HashSet<RelayUrl>>();
340 340
341 let mut request = create_relays_request( 341 let mut request = create_relays_request(
342 git_repo_path, 342 git_repo_path,
@@ -359,17 +359,17 @@ impl Connect for Client {
359 // don't look for events on blaster 359 // don't look for events on blaster
360 .filter(|&r| !r.as_str().contains("nostr.mutinywallet.com")) 360 .filter(|&r| !r.as_str().contains("nostr.mutinywallet.com"))
361 .cloned() 361 .cloned()
362 .collect::<HashSet<Url>>() 362 .collect::<HashSet<RelayUrl>>()
363 .difference(&processed_relays) 363 .difference(&processed_relays)
364 .cloned() 364 .cloned()
365 .collect::<HashSet<Url>>(); 365 .collect::<HashSet<RelayUrl>>();
366 if relays.is_empty() { 366 if relays.is_empty() {
367 break; 367 break;
368 } 368 }
369 let profile_relays_only = request 369 let profile_relays_only = request
370 .user_relays_for_profiles 370 .user_relays_for_profiles
371 .difference(&request.repo_relays) 371 .difference(&request.repo_relays)
372 .collect::<HashSet<&Url>>(); 372 .collect::<HashSet<&RelayUrl>>();
373 for relay in &request.repo_relays { 373 for relay in &request.repo_relays {
374 self.client 374 self.client
375 .add_relay(relay.as_str()) 375 .add_relay(relay.as_str())
@@ -469,11 +469,7 @@ impl Connect for Client {
469 processed_relays.extend(relays.clone()); 469 processed_relays.extend(relays.clone());
470 470
471 if let Ok(repo_ref) = get_repo_ref_from_cache(git_repo_path, repo_coordinates).await { 471 if let Ok(repo_ref) = get_repo_ref_from_cache(git_repo_path, repo_coordinates).await {
472 request.repo_relays = repo_ref 472 request.repo_relays = repo_ref.relays.iter().cloned().collect();
473 .relays
474 .iter()
475 .filter_map(|r| Url::parse(r).ok())
476 .collect();
477 } 473 }
478 474
479 request.user_relays_for_profiles = { 475 request.user_relays_for_profiles = {
@@ -486,7 +482,7 @@ impl Connect for Client {
486 { 482 {
487 if let Ok(user_ref) = get_user_ref_from_cache(git_repo_path, user).await { 483 if let Ok(user_ref) = get_user_ref_from_cache(git_repo_path, user).await {
488 for r in user_ref.relays.write() { 484 for r in user_ref.relays.write() {
489 if let Ok(url) = Url::parse(&r) { 485 if let Ok(url) = RelayUrl::parse(&r) {
490 set.insert(url); 486 set.insert(url);
491 } 487 }
492 } 488 }
@@ -905,7 +901,7 @@ async fn create_relays_request(
905 git_repo_path: Option<&Path>, 901 git_repo_path: Option<&Path>,
906 repo_coordinates: &HashSet<Coordinate>, 902 repo_coordinates: &HashSet<Coordinate>,
907 user_profiles: &HashSet<PublicKey>, 903 user_profiles: &HashSet<PublicKey>,
908 fallback_relays: HashSet<Url>, 904 fallback_relays: HashSet<RelayUrl>,
909) -> Result<FetchRequest> { 905) -> Result<FetchRequest> {
910 let repo_ref = get_repo_ref_from_cache(git_repo_path, repo_coordinates).await; 906 let repo_ref = get_repo_ref_from_cache(git_repo_path, repo_coordinates).await;
911 907
@@ -1026,7 +1022,7 @@ async fn create_relays_request(
1026 { 1022 {
1027 if let Ok(user_ref) = get_user_ref_from_cache(git_repo_path, user).await { 1023 if let Ok(user_ref) = get_user_ref_from_cache(git_repo_path, user).await {
1028 for r in user_ref.relays.write() { 1024 for r in user_ref.relays.write() {
1029 if let Ok(url) = Url::parse(&r) { 1025 if let Ok(url) = RelayUrl::parse(&r) {
1030 set.insert(url); 1026 set.insert(url);
1031 } 1027 }
1032 } 1028 }
@@ -1068,17 +1064,13 @@ async fn create_relays_request(
1068 let relays = { 1064 let relays = {
1069 let mut relays = fallback_relays; 1065 let mut relays = fallback_relays;
1070 if let Ok(repo_ref) = &repo_ref { 1066 if let Ok(repo_ref) = &repo_ref {
1071 for r in &repo_ref.relays { 1067 for r in repo_ref.relays.clone() {
1072 if let Ok(url) = Url::parse(r) { 1068 relays.insert(r);
1073 relays.insert(url);
1074 }
1075 } 1069 }
1076 } 1070 }
1077 for c in repo_coordinates { 1071 for c in repo_coordinates {
1078 for r in &c.relays { 1072 for r in &c.relays {
1079 if let Ok(url) = Url::parse(r) { 1073 relays.insert(r.clone());
1080 relays.insert(url);
1081 }
1082 } 1074 }
1083 } 1075 }
1084 relays 1076 relays
@@ -1500,8 +1492,8 @@ impl Display for FetchReport {
1500 1492
1501#[derive(Default, Clone)] 1493#[derive(Default, Clone)]
1502pub struct FetchRequest { 1494pub struct FetchRequest {
1503 repo_relays: HashSet<Url>, 1495 repo_relays: HashSet<RelayUrl>,
1504 selected_relay: Option<Url>, 1496 selected_relay: Option<RelayUrl>,
1505 relay_column_width: usize, 1497 relay_column_width: usize,
1506 repo_coordinates_without_relays: Vec<(Coordinate, Option<Timestamp>)>, 1498 repo_coordinates_without_relays: Vec<(Coordinate, Option<Timestamp>)>,
1507 state: Option<(Timestamp, EventId)>, 1499 state: Option<(Timestamp, EventId)>,
@@ -1510,7 +1502,7 @@ pub struct FetchRequest {
1510 missing_contributor_profiles: HashSet<PublicKey>, 1502 missing_contributor_profiles: HashSet<PublicKey>,
1511 existing_events: HashSet<EventId>, 1503 existing_events: HashSet<EventId>,
1512 profiles_to_fetch_from_user_relays: HashMap<PublicKey, (Timestamp, Timestamp)>, 1504 profiles_to_fetch_from_user_relays: HashMap<PublicKey, (Timestamp, Timestamp)>,
1513 user_relays_for_profiles: HashSet<Url>, 1505 user_relays_for_profiles: HashSet<RelayUrl>,
1514} 1506}
1515 1507
1516pub async fn fetching_with_report( 1508pub async fn fetching_with_report(
@@ -1646,7 +1638,7 @@ pub async fn send_events(
1646 git_repo_path: Option<&Path>, 1638 git_repo_path: Option<&Path>,
1647 events: Vec<nostr::Event>, 1639 events: Vec<nostr::Event>,
1648 my_write_relays: Vec<String>, 1640 my_write_relays: Vec<String>,
1649 repo_read_relays: Vec<String>, 1641 repo_read_relays: Vec<RelayUrl>,
1650 animate: bool, 1642 animate: bool,
1651 silent: bool, 1643 silent: bool,
1652) -> Result<()> { 1644) -> Result<()> {
@@ -1659,7 +1651,12 @@ pub async fn send_events(
1659 }, 1651 },
1660 ] 1652 ]
1661 .concat(); 1653 .concat();
1662 let mut relays: Vec<&String> = vec![]; 1654 let mut relays: Vec<&str> = vec![];
1655
1656 let repo_read_relays = repo_read_relays
1657 .iter()
1658 .map(|r| r.to_string())
1659 .collect::<Vec<String>>();
1663 1660
1664 let all = &[ 1661 let all = &[
1665 repo_read_relays.clone(), 1662 repo_read_relays.clone(),
@@ -1722,7 +1719,7 @@ pub async fn send_events(
1722 1719
1723 #[allow(clippy::borrow_deref_ref)] 1720 #[allow(clippy::borrow_deref_ref)]
1724 join_all(relays.iter().map(|&relay| async { 1721 join_all(relays.iter().map(|&relay| async {
1725 let relay_clean = remove_trailing_slash(&*relay); 1722 let relay_clean = remove_trailing_slash(relay);
1726 let details = format!( 1723 let details = format!(
1727 "{}{}{} {}", 1724 "{}{}{} {}",
1728 if my_write_relays 1725 if my_write_relays
@@ -1735,7 +1732,7 @@ pub async fn send_events(
1735 }, 1732 },
1736 if repo_read_relays 1733 if repo_read_relays
1737 .iter() 1734 .iter()
1738 .any(|r| relay_clean.eq(&remove_trailing_slash(r))) 1735 .any(|r| relay_clean.eq(&remove_trailing_slash(&r.to_string())))
1739 { 1736 {
1740 " [repo-relay]" 1737 " [repo-relay]"
1741 } else { 1738 } else {
@@ -1763,7 +1760,7 @@ pub async fn send_events(
1763 let mut failed = false; 1760 let mut failed = false;
1764 for event in &events { 1761 for event in &events {
1765 match client 1762 match client
1766 .send_event_to(git_repo_path, relay.as_str(), event.clone()) 1763 .send_event_to(git_repo_path, relay, event.clone())
1767 .await 1764 .await
1768 { 1765 {
1769 Ok(_) => pb.inc(1), 1766 Ok(_) => pb.inc(1),
@@ -1793,8 +1790,8 @@ pub async fn send_events(
1793 Ok(()) 1790 Ok(())
1794} 1791}
1795 1792
1796fn remove_trailing_slash(s: &String) -> String { 1793fn remove_trailing_slash(s: &str) -> String {
1797 match s.as_str().strip_suffix('/') { 1794 match s.strip_suffix('/') {
1798 Some(s) => s, 1795 Some(s) => s,
1799 None => s, 1796 None => s,
1800 } 1797 }
diff --git a/src/lib/git/nostr_url.rs b/src/lib/git/nostr_url.rs
index b310782..e4b6825 100644
--- a/src/lib/git/nostr_url.rs
+++ b/src/lib/git/nostr_url.rs
@@ -3,7 +3,7 @@ use std::{collections::HashSet, str::FromStr};
3 3
4use anyhow::{anyhow, bail, Context, Error, Result}; 4use anyhow::{anyhow, bail, Context, Error, Result};
5use nostr::nips::nip01::Coordinate; 5use nostr::nips::nip01::Coordinate;
6use nostr_sdk::{PublicKey, Url}; 6use nostr_sdk::{PublicKey, RelayUrl, Url};
7 7
8#[derive(Debug, PartialEq, Default, Clone)] 8#[derive(Debug, PartialEq, Default, Clone)]
9pub enum ServerProtocol { 9pub enum ServerProtocol {
@@ -85,8 +85,8 @@ impl std::str::FromStr for NostrUrlDecoded {
85 decoded = format!("wss://{decoded}"); 85 decoded = format!("wss://{decoded}");
86 } 86 }
87 let url = 87 let url =
88 Url::parse(&decoded).context("could not parse relays in nostr git url")?; 88 RelayUrl::parse(&decoded).context("could not parse relays in nostr git url")?;
89 relays.push(url.to_string()); 89 relays.push(url);
90 } else if name == "protocol" { 90 } else if name == "protocol" {
91 protocol = match value.as_ref() { 91 protocol = match value.as_ref() {
92 "ssh" => Some(ServerProtocol::Ssh), 92 "ssh" => Some(ServerProtocol::Ssh),
@@ -151,8 +151,8 @@ impl std::str::FromStr for NostrUrlDecoded {
151 decoded = format!("wss://{decoded}"); 151 decoded = format!("wss://{decoded}");
152 } 152 }
153 let url = 153 let url =
154 Url::parse(&decoded).context("could not parse relays in nostr git url")?; 154 RelayUrl::parse(&decoded).context("could not parse relays in nostr git url")?;
155 relays.push(url.to_string()); 155 relays.push(url);
156 } 156 }
157 coordinates.insert(Coordinate { 157 coordinates.insert(Coordinate {
158 identifier, 158 identifier,
@@ -852,7 +852,7 @@ mod tests {
852 .unwrap(), 852 .unwrap(),
853 kind: nostr_sdk::Kind::GitRepoAnnouncement, 853 kind: nostr_sdk::Kind::GitRepoAnnouncement,
854 relays: if relays { 854 relays: if relays {
855 vec!["wss://nos.lol/".to_string()] 855 vec![RelayUrl::parse("wss://nos.lol").unwrap()]
856 } else { 856 } else {
857 vec![] 857 vec![]
858 }, 858 },
@@ -873,7 +873,8 @@ mod tests {
873 ) 873 )
874 .unwrap(), 874 .unwrap(),
875 kind: nostr_sdk::Kind::GitRepoAnnouncement, 875 kind: nostr_sdk::Kind::GitRepoAnnouncement,
876 relays: vec!["wss://nos.lol".to_string()], // wont add the slash 876 relays: vec![RelayUrl::parse("wss://nos.lol").unwrap()], /* wont add the
877 * slash */
877 }]), 878 }]),
878 protocol: None, 879 protocol: None,
879 user: None, 880 user: None,
@@ -942,8 +943,8 @@ mod tests {
942 fn with_multiple_encoded_relays() -> Result<()> { 943 fn with_multiple_encoded_relays() -> Result<()> {
943 let url = format!( 944 let url = format!(
944 "nostr://npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit?relay={}&relay1={}", 945 "nostr://npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit?relay={}&relay1={}",
945 urlencoding::encode("wss://nos.lol"), 946 urlencoding::encode("wss://nos.lol/"),
946 urlencoding::encode("wss://relay.damus.io"), 947 urlencoding::encode("wss://relay.damus.io/"),
947 ); 948 );
948 assert_eq!( 949 assert_eq!(
949 NostrUrlDecoded::from_str(&url)?, 950 NostrUrlDecoded::from_str(&url)?,
@@ -957,8 +958,8 @@ mod tests {
957 .unwrap(), 958 .unwrap(),
958 kind: nostr_sdk::Kind::GitRepoAnnouncement, 959 kind: nostr_sdk::Kind::GitRepoAnnouncement,
959 relays: vec![ 960 relays: vec![
960 "wss://nos.lol/".to_string(), 961 RelayUrl::parse("wss://nos.lol/").unwrap(),
961 "wss://relay.damus.io/".to_string(), 962 RelayUrl::parse("wss://relay.damus.io/").unwrap(),
962 ], 963 ],
963 }]), 964 }]),
964 protocol: None, 965 protocol: None,
@@ -1039,8 +1040,8 @@ mod tests {
1039 fn with_multiple_encoded_relays() -> Result<()> { 1040 fn with_multiple_encoded_relays() -> Result<()> {
1040 let url = format!( 1041 let url = format!(
1041 "nostr://npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/{}/{}/ngit", 1042 "nostr://npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/{}/{}/ngit",
1042 urlencoding::encode("wss://nos.lol"), 1043 urlencoding::encode("wss://nos.lol/"),
1043 urlencoding::encode("wss://relay.damus.io"), 1044 urlencoding::encode("wss://relay.damus.io/"),
1044 ); 1045 );
1045 assert_eq!( 1046 assert_eq!(
1046 NostrUrlDecoded::from_str(&url)?, 1047 NostrUrlDecoded::from_str(&url)?,
@@ -1054,8 +1055,8 @@ mod tests {
1054 .unwrap(), 1055 .unwrap(),
1055 kind: nostr_sdk::Kind::GitRepoAnnouncement, 1056 kind: nostr_sdk::Kind::GitRepoAnnouncement,
1056 relays: vec![ 1057 relays: vec![
1057 "wss://nos.lol/".to_string(), 1058 RelayUrl::parse("wss://nos.lol/").unwrap(),
1058 "wss://relay.damus.io/".to_string(), 1059 RelayUrl::parse("wss://relay.damus.io/").unwrap(),
1059 ], 1060 ],
1060 }]), 1061 }]),
1061 protocol: None, 1062 protocol: None,
diff --git a/src/lib/git_events.rs b/src/lib/git_events.rs
index bfe5b30..c4d6770 100644
--- a/src/lib/git_events.rs
+++ b/src/lib/git_events.rs
@@ -4,7 +4,7 @@ use anyhow::{bail, Context, Result};
4use nostr::nips::{nip01::Coordinate, nip10::Marker, nip19::Nip19}; 4use nostr::nips::{nip01::Coordinate, nip10::Marker, nip19::Nip19};
5use nostr_sdk::{ 5use nostr_sdk::{
6 hashes::sha1::Hash as Sha1Hash, Event, EventBuilder, EventId, FromBech32, Kind, NostrSigner, 6 hashes::sha1::Hash as Sha1Hash, Event, EventBuilder, EventId, FromBech32, Kind, NostrSigner,
7 PublicKey, Tag, TagKind, TagStandard, UncheckedUrl, 7 PublicKey, RelayUrl, Tag, TagKind, TagStandard,
8}; 8};
9 9
10use crate::{ 10use crate::{
@@ -96,7 +96,7 @@ pub async fn generate_patch_event(
96 let commit_parent = git_repo 96 let commit_parent = git_repo
97 .get_commit_parent(commit) 97 .get_commit_parent(commit)
98 .context("failed to get parent commit")?; 98 .context("failed to get parent commit")?;
99 let relay_hint = repo_ref.relays.first().map(nostr::UncheckedUrl::from); 99 let relay_hint = repo_ref.relays.first().cloned();
100 100
101 sign_event( 101 sign_event(
102 EventBuilder::new( 102 EventBuilder::new(
@@ -104,6 +104,8 @@ pub async fn generate_patch_event(
104 git_repo 104 git_repo
105 .make_patch_from_commit(commit, &series_count) 105 .make_patch_from_commit(commit, &series_count)
106 .context(format!("failed to make patch for commit {commit}"))?, 106 .context(format!("failed to make patch for commit {commit}"))?,
107 )
108 .tags(
107 [ 109 [
108 repo_ref 110 repo_ref
109 .maintainers 111 .maintainers
@@ -141,6 +143,7 @@ pub async fn generate_patch_event(
141 relay_url: relay_hint.clone(), 143 relay_url: relay_hint.clone(),
142 marker: Some(Marker::Root), 144 marker: Some(Marker::Root),
143 public_key: None, 145 public_key: None,
146 uppercase: false,
144 })] 147 })]
145 } else if let Some(event_ref) = root_proposal_id.clone() { 148 } else if let Some(event_ref) = root_proposal_id.clone() {
146 vec![ 149 vec![
@@ -165,6 +168,7 @@ pub async fn generate_patch_event(
165 relay_url: relay_hint.clone(), 168 relay_url: relay_hint.clone(),
166 marker: Some(Marker::Reply), 169 marker: Some(Marker::Reply),
167 public_key: None, 170 public_key: None,
171 uppercase: false,
168 })] 172 })]
169 } else { 173 } else {
170 vec![] 174 vec![]
@@ -256,9 +260,10 @@ pub fn event_tag_from_nip19_or_hex(
256 Nip19::Event(n) => { 260 Nip19::Event(n) => {
257 break Ok(Tag::from_standardized(nostr_sdk::TagStandard::Event { 261 break Ok(Tag::from_standardized(nostr_sdk::TagStandard::Event {
258 event_id: n.event_id, 262 event_id: n.event_id,
259 relay_url: n.relays.first().map(UncheckedUrl::new), 263 relay_url: n.relays.first().and_then(|url| RelayUrl::parse(url).ok()),
260 marker: Some(marker), 264 marker: Some(marker),
261 public_key: None, 265 public_key: None,
266 uppercase: false,
262 })); 267 }));
263 } 268 }
264 Nip19::EventId(id) => { 269 Nip19::EventId(id) => {
@@ -267,6 +272,7 @@ pub fn event_tag_from_nip19_or_hex(
267 relay_url: None, 272 relay_url: None,
268 marker: Some(marker), 273 marker: Some(marker),
269 public_key: None, 274 public_key: None,
275 uppercase: false,
270 })); 276 }));
271 } 277 }
272 Nip19::Coordinate(coordinate) => { 278 Nip19::Coordinate(coordinate) => {
@@ -291,6 +297,7 @@ pub fn event_tag_from_nip19_or_hex(
291 relay_url: None, 297 relay_url: None,
292 marker: Some(marker), 298 marker: Some(marker),
293 public_key: None, 299 public_key: None,
300 uppercase: false,
294 })); 301 }));
295 } 302 }
296 if prompt_for_correction { 303 if prompt_for_correction {
@@ -326,7 +333,8 @@ pub async fn generate_cover_letter_and_patch_events(
326 "From {} Mon Sep 17 00:00:00 2001\nSubject: [PATCH 0/{}] {title}\n\n{description}", 333 "From {} Mon Sep 17 00:00:00 2001\nSubject: [PATCH 0/{}] {title}\n\n{description}",
327 commits.last().unwrap(), 334 commits.last().unwrap(),
328 commits.len() 335 commits.len()
329 ), 336 ))
337 .tags(
330 [ 338 [
331 repo_ref.maintainers.iter().map(|m| Tag::coordinate(Coordinate { 339 repo_ref.maintainers.iter().map(|m| Tag::coordinate(Coordinate {
332 kind: nostr::Kind::GitRepoAnnouncement, 340 kind: nostr::Kind::GitRepoAnnouncement,
@@ -618,7 +626,8 @@ mod tests {
618 Ok(nostr::event::EventBuilder::new( 626 Ok(nostr::event::EventBuilder::new(
619 nostr::event::Kind::GitPatch, 627 nostr::event::Kind::GitPatch,
620 format!("From ea897e987ea9a7a98e7a987e97987ea98e7a3334 Mon Sep 17 00:00:00 2001\nSubject: [PATCH 0/2] {title}\n\n{description}"), 628 format!("From ea897e987ea9a7a98e7a987e97987ea98e7a3334 Mon Sep 17 00:00:00 2001\nSubject: [PATCH 0/2] {title}\n\n{description}"),
621 [ 629 )
630 .tags([
622 Tag::hashtag("cover-letter"), 631 Tag::hashtag("cover-letter"),
623 Tag::hashtag("root"), 632 Tag::hashtag("root"),
624 ], 633 ],
diff --git a/src/lib/login/fresh.rs b/src/lib/login/fresh.rs
index 23c4bdc..615c0a6 100644
--- a/src/lib/login/fresh.rs
+++ b/src/lib/login/fresh.rs
@@ -5,7 +5,7 @@ use console::Style;
5use dialoguer::theme::{ColorfulTheme, Theme}; 5use dialoguer::theme::{ColorfulTheme, Theme};
6use nostr::nips::{nip05, nip46::NostrConnectURI}; 6use nostr::nips::{nip05, nip46::NostrConnectURI};
7use nostr_connect::client::NostrConnect; 7use nostr_connect::client::NostrConnect;
8use nostr_sdk::{EventBuilder, Keys, Metadata, NostrSigner, PublicKey, ToBech32, Url}; 8use nostr_sdk::{EventBuilder, Keys, Metadata, NostrSigner, PublicKey, RelayUrl, ToBech32};
9use qrcode::QrCode; 9use qrcode::QrCode;
10use tokio::{signal, sync::Mutex}; 10use tokio::{signal, sync::Mutex};
11 11
@@ -370,8 +370,8 @@ pub fn generate_nostr_connect_app(
370 client 370 client
371 .get_fallback_signer_relays() 371 .get_fallback_signer_relays()
372 .iter() 372 .iter()
373 .flat_map(|s| Url::parse(s)) 373 .flat_map(RelayUrl::parse)
374 .collect::<Vec<Url>>() 374 .collect::<Vec<RelayUrl>>()
375 } else { 375 } else {
376 vec![] 376 vec![]
377 }; 377 };
@@ -438,8 +438,8 @@ pub async fn listen_for_remote_signer(
438 let bunker_url = NostrConnectURI::Bunker { 438 let bunker_url = NostrConnectURI::Bunker {
439 // TODO the remote signer pubkey may not be the user pubkey 439 // TODO the remote signer pubkey may not be the user pubkey
440 remote_signer_public_key: public_key, 440 remote_signer_public_key: public_key,
441 relays: nostr_connect_url.relays(), 441 relays: nostr_connect_url.relays().to_vec(),
442 secret: nostr_connect_url.secret(), 442 secret: nostr_connect_url.secret().map(String::from),
443 }; 443 };
444 Ok((signer, public_key, bunker_url)) 444 Ok((signer, public_key, bunker_url))
445 } else { 445 } else {
@@ -727,7 +727,7 @@ async fn signup(
727 client 727 client
728 .get_fallback_relays() 728 .get_fallback_relays()
729 .iter() 729 .iter()
730 .map(|s| (Url::parse(s).unwrap(), None)), 730 .map(|s| (RelayUrl::parse(s).unwrap(), None)),
731 ) 731 )
732 .sign_with_keys(&keys)?; 732 .sign_with_keys(&keys)?;
733 eprintln!("publishing user profile to relays"); 733 eprintln!("publishing user profile to relays");
diff --git a/src/lib/repo_ref.rs b/src/lib/repo_ref.rs
index 05234e2..8319c78 100644
--- a/src/lib/repo_ref.rs
+++ b/src/lib/repo_ref.rs
@@ -9,7 +9,7 @@ use std::{
9use anyhow::{bail, Context, Result}; 9use anyhow::{bail, Context, Result};
10use console::Style; 10use console::Style;
11use nostr::{nips::nip01::Coordinate, FromBech32, PublicKey, Tag, TagStandard, ToBech32}; 11use nostr::{nips::nip01::Coordinate, FromBech32, PublicKey, Tag, TagStandard, ToBech32};
12use nostr_sdk::{Kind, NostrSigner, Timestamp}; 12use nostr_sdk::{Kind, NostrSigner, RelayUrl, Timestamp};
13use serde::{Deserialize, Serialize}; 13use serde::{Deserialize, Serialize};
14 14
15#[cfg(not(test))] 15#[cfg(not(test))]
@@ -28,7 +28,7 @@ pub struct RepoRef {
28 pub root_commit: String, 28 pub root_commit: String,
29 pub git_server: Vec<String>, 29 pub git_server: Vec<String>,
30 pub web: Vec<String>, 30 pub web: Vec<String>,
31 pub relays: Vec<String>, 31 pub relays: Vec<RelayUrl>,
32 pub maintainers: Vec<PublicKey>, 32 pub maintainers: Vec<PublicKey>,
33 pub events: HashMap<Coordinate, nostr::Event>, 33 pub events: HashMap<Coordinate, nostr::Event>,
34 // code languages and hashtags 34 // code languages and hashtags
@@ -78,8 +78,11 @@ impl TryFrom<nostr::Event> for RepoRef {
78 } 78 }
79 79
80 if let Some(t) = event.tags.iter().find(|t| t.as_slice()[0].eq("relays")) { 80 if let Some(t) = event.tags.iter().find(|t| t.as_slice()[0].eq("relays")) {
81 r.relays = t.clone().to_vec(); 81 for relay in t.clone().to_vec() {
82 r.relays.remove(0); 82 if let Ok(relay) = RelayUrl::parse(relay) {
83 r.relays.push(relay);
84 }
85 }
83 } 86 }
84 87
85 if let Some(t) = event 88 if let Some(t) = event
@@ -119,9 +122,7 @@ impl TryFrom<nostr::Event> for RepoRef {
119impl RepoRef { 122impl RepoRef {
120 pub async fn to_event(&self, signer: &Arc<dyn NostrSigner>) -> Result<nostr::Event> { 123 pub async fn to_event(&self, signer: &Arc<dyn NostrSigner>) -> Result<nostr::Event> {
121 sign_event( 124 sign_event(
122 nostr_sdk::EventBuilder::new( 125 nostr_sdk::EventBuilder::new(nostr::event::Kind::GitRepoAnnouncement, "").tags(
123 nostr::event::Kind::GitRepoAnnouncement,
124 "",
125 [ 126 [
126 vec![ 127 vec![
127 Tag::identifier(if self.identifier.to_string().is_empty() { 128 Tag::identifier(if self.identifier.to_string().is_empty() {
@@ -158,7 +159,7 @@ impl RepoRef {
158 ), 159 ),
159 Tag::custom( 160 Tag::custom(
160 nostr::TagKind::Custom(std::borrow::Cow::Borrowed("relays")), 161 nostr::TagKind::Custom(std::borrow::Cow::Borrowed("relays")),
161 self.relays.clone(), 162 self.relays.iter().map(|r| r.to_string()),
162 ), 163 ),
163 Tag::custom( 164 Tag::custom(
164 nostr::TagKind::Custom(std::borrow::Cow::Borrowed("maintainers")), 165 nostr::TagKind::Custom(std::borrow::Cow::Borrowed("maintainers")),
@@ -206,7 +207,7 @@ impl RepoRef {
206 .unwrap(), 207 .unwrap(),
207 identifier: self.identifier.clone(), 208 identifier: self.identifier.clone(),
208 relays: if let Some(relay) = self.relays.first() { 209 relays: if let Some(relay) = self.relays.first() {
209 vec![relay.to_string()] 210 vec![relay.clone()]
210 } else { 211 } else {
211 vec![] 212 vec![]
212 }, 213 },
@@ -481,7 +482,10 @@ mod tests {
481 "https://exampleproject.xyz".to_string(), 482 "https://exampleproject.xyz".to_string(),
482 "https://gitworkshop.dev/123".to_string(), 483 "https://gitworkshop.dev/123".to_string(),
483 ], 484 ],
484 relays: vec!["ws://relay1.io".to_string(), "ws://relay2.io".to_string()], 485 relays: vec![
486 RelayUrl::parse("ws://relay1.io").unwrap(),
487 RelayUrl::parse("ws://relay2.io").unwrap(),
488 ],
485 maintainers: vec![TEST_KEY_1_KEYS.public_key(), TEST_KEY_2_KEYS.public_key()], 489 maintainers: vec![TEST_KEY_1_KEYS.public_key(), TEST_KEY_2_KEYS.public_key()],
486 events: HashMap::new(), 490 events: HashMap::new(),
487 } 491 }
@@ -592,7 +596,10 @@ mod tests {
592 async fn relays() { 596 async fn relays() {
593 assert_eq!( 597 assert_eq!(
594 RepoRef::try_from(create().await).unwrap().relays, 598 RepoRef::try_from(create().await).unwrap().relays,
595 vec!["ws://relay1.io".to_string(), "ws://relay2.io".to_string()], 599 vec![
600 RelayUrl::parse("ws://relay1.io").unwrap(),
601 RelayUrl::parse("ws://relay2.io").unwrap(),
602 ],
596 ) 603 )
597 } 604 }
598 605