Skip to content

Commit 1a91e22

Browse files
authored
Refactor/contact get relays of type (#301)
* feat(whitenoise/accounts/contacts): add get_relays_of_type method on contacts * refactor(whitenoise/accounts/groups): use contact#get_relays_of_type method for automatic default relay fallback
1 parent d620b8f commit 1a91e22

File tree

2 files changed

+151
-20
lines changed

2 files changed

+151
-20
lines changed

src/whitenoise/accounts/contacts.rs

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,33 @@ where
7070
}
7171
}
7272

73+
impl Contact {
74+
/// Returns the relays to use for this contact of the specified type
75+
/// If the contact has no relays of the specified type, it will fallback to nip65 relays
76+
/// If the contact has no nip65 relays, it will fallback to default relays
77+
pub fn get_relays_of_type(&self, relay_type: RelayType) -> DashSet<RelayUrl> {
78+
let relays = match relay_type {
79+
RelayType::Nostr => &self.nip65_relays,
80+
RelayType::Inbox => &self.inbox_relays,
81+
RelayType::KeyPackage => &self.key_package_relays,
82+
};
83+
84+
if relays.is_empty() {
85+
self.relay_fallback(relay_type)
86+
} else {
87+
relays.clone()
88+
}
89+
}
90+
91+
fn relay_fallback(&self, relay_type: RelayType) -> DashSet<RelayUrl> {
92+
match relay_type {
93+
RelayType::Nostr => Account::default_relays(),
94+
RelayType::Inbox => self.get_relays_of_type(RelayType::Nostr),
95+
RelayType::KeyPackage => self.get_relays_of_type(RelayType::Nostr),
96+
}
97+
}
98+
}
99+
73100
impl Whitenoise {
74101
// ============================================================================
75102
// CONTACT MANAGEMENT
@@ -700,4 +727,123 @@ mod tests {
700727
.get_nostr_keys_for_pubkey(&account.pubkey);
701728
assert!(signing_keys_result.is_err());
702729
}
730+
731+
#[tokio::test]
732+
async fn test_get_relays_of_type() {
733+
use crate::whitenoise::Whitenoise;
734+
use crate::RelayType;
735+
use dashmap::DashSet;
736+
use nostr_sdk::RelayUrl;
737+
738+
// Create test relay URLs
739+
let nip65_relay = RelayUrl::parse("wss://relay.damus.io").unwrap();
740+
let inbox_relay = RelayUrl::parse("wss://inbox.relay.com").unwrap();
741+
let key_package_relay = RelayUrl::parse("wss://keypackage.relay.com").unwrap();
742+
743+
// Create contact with different relay types
744+
let contact = super::Contact {
745+
pubkey: create_test_keys().public_key(),
746+
metadata: None,
747+
nip65_relays: {
748+
let set = DashSet::new();
749+
set.insert(nip65_relay.clone());
750+
set
751+
},
752+
inbox_relays: {
753+
let set = DashSet::new();
754+
set.insert(inbox_relay.clone());
755+
set
756+
},
757+
key_package_relays: {
758+
let set = DashSet::new();
759+
set.insert(key_package_relay.clone());
760+
set
761+
},
762+
};
763+
764+
// Test getting each relay type
765+
let nip65_relays = contact.get_relays_of_type(RelayType::Nostr);
766+
assert!(Whitenoise::relayurl_dashset_eq(
767+
nip65_relays,
768+
DashSet::from_iter([nip65_relay])
769+
));
770+
771+
let inbox_relays = contact.get_relays_of_type(RelayType::Inbox);
772+
assert!(Whitenoise::relayurl_dashset_eq(
773+
inbox_relays,
774+
DashSet::from_iter([inbox_relay])
775+
));
776+
777+
let key_package_relays = contact.get_relays_of_type(RelayType::KeyPackage);
778+
assert!(Whitenoise::relayurl_dashset_eq(
779+
key_package_relays,
780+
DashSet::from_iter([key_package_relay])
781+
));
782+
}
783+
784+
#[tokio::test]
785+
async fn test_get_relays_of_type_empty_fallback() {
786+
use crate::whitenoise::accounts::Account;
787+
use crate::whitenoise::Whitenoise;
788+
use crate::RelayType;
789+
use dashmap::DashSet;
790+
791+
// Create contact with empty relay sets
792+
let contact = super::Contact {
793+
pubkey: create_test_keys().public_key(),
794+
metadata: None,
795+
nip65_relays: DashSet::new(),
796+
inbox_relays: DashSet::new(),
797+
key_package_relays: DashSet::new(),
798+
};
799+
800+
// Test that empty relays fallback to default_relays
801+
let nip65_relays = contact.get_relays_of_type(RelayType::Nostr);
802+
let default_relays = Account::default_relays();
803+
assert!(Whitenoise::relayurl_dashset_eq(
804+
nip65_relays,
805+
default_relays.clone()
806+
));
807+
808+
let inbox_relays = contact.get_relays_of_type(RelayType::Inbox);
809+
assert!(Whitenoise::relayurl_dashset_eq(
810+
inbox_relays,
811+
default_relays.clone()
812+
));
813+
814+
let key_package_relays = contact.get_relays_of_type(RelayType::KeyPackage);
815+
assert!(Whitenoise::relayurl_dashset_eq(
816+
key_package_relays,
817+
default_relays
818+
));
819+
}
820+
821+
#[tokio::test]
822+
async fn test_get_relays_of_type_fallback_goes_to_nip65_if_available() {
823+
use crate::whitenoise::Whitenoise;
824+
use crate::RelayType;
825+
use dashmap::DashSet;
826+
827+
let nip65_relay = RelayUrl::parse("wss://relay.damus.io").unwrap();
828+
829+
let contact = super::Contact {
830+
pubkey: create_test_keys().public_key(),
831+
metadata: None,
832+
nip65_relays: DashSet::from_iter([nip65_relay.clone()]),
833+
inbox_relays: DashSet::new(),
834+
key_package_relays: DashSet::new(),
835+
};
836+
837+
let inbox_relays = contact.get_relays_of_type(RelayType::Inbox);
838+
assert!(Whitenoise::relayurl_dashset_eq(
839+
inbox_relays,
840+
DashSet::from_iter([nip65_relay.clone()])
841+
));
842+
843+
let key_package_relays = contact.get_relays_of_type(RelayType::KeyPackage);
844+
assert!(Whitenoise::relayurl_dashset_eq(
845+
key_package_relays,
846+
DashSet::from_iter([nip65_relay])
847+
));
848+
}
703849
}

src/whitenoise/accounts/groups.rs

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::whitenoise::accounts::Account;
22
use crate::whitenoise::error::{Result, WhitenoiseError};
33
use crate::whitenoise::Whitenoise;
4+
use crate::RelayType;
45
use nostr_mls::prelude::*;
56
use std::time::Duration;
67

@@ -46,11 +47,7 @@ impl Whitenoise {
4647

4748
for pk in member_pubkeys.iter() {
4849
let contact = self.load_contact(pk).await?;
49-
let relays_to_use = if contact.key_package_relays.is_empty() {
50-
Account::default_relays()
51-
} else {
52-
contact.key_package_relays.clone()
53-
};
50+
let relays_to_use = contact.get_relays_of_type(RelayType::KeyPackage);
5451
let some_event = self
5552
.fetch_key_package_event_from(relays_to_use, *pk)
5653
.await?;
@@ -121,11 +118,7 @@ impl Whitenoise {
121118
// Create a timestamp 1 month in the future
122119
use std::ops::Add;
123120
let one_month_future = Timestamp::now().add(30 * 24 * 60 * 60);
124-
let relays_to_use = if contact.inbox_relays.is_empty() {
125-
Account::default_relays()
126-
} else {
127-
contact.inbox_relays.clone()
128-
};
121+
let relays_to_use = contact.get_relays_of_type(RelayType::Inbox);
129122

130123
self.nostr
131124
.publish_gift_wrap_with_signer(
@@ -255,11 +248,7 @@ impl Whitenoise {
255248
// Fetch key packages for all members
256249
for pk in members.iter() {
257250
let contact = self.load_contact(pk).await?;
258-
let relays_to_use = if contact.key_package_relays.is_empty() {
259-
Account::default_relays()
260-
} else {
261-
contact.key_package_relays.clone()
262-
};
251+
let relays_to_use = contact.get_relays_of_type(RelayType::KeyPackage);
263252
let some_event = self
264253
.fetch_key_package_event_from(relays_to_use, *pk)
265254
.await?;
@@ -357,11 +346,7 @@ impl Whitenoise {
357346
let one_month_future = Timestamp::now() + Duration::from_secs(30 * 24 * 60 * 60);
358347

359348
// Use fallback relays if contact has no inbox relays configured
360-
let relays_to_use = if contact.inbox_relays.is_empty() {
361-
Account::default_relays()
362-
} else {
363-
contact.inbox_relays
364-
};
349+
let relays_to_use = contact.get_relays_of_type(RelayType::Inbox);
365350

366351
self.nostr
367352
.publish_gift_wrap_with_signer(

0 commit comments

Comments
 (0)