Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
feat(iroh-relay): allow for extension of RelayMaps
  • Loading branch information
dignifiedquire committed Oct 23, 2025
commit 2920d1700d3679c807f24fa314de1dc7091ecf33
69 changes: 61 additions & 8 deletions iroh-relay/src/relay_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ impl PartialEq for RelayMap {
impl Eq for RelayMap {}

impl RelayMap {
/// Creates an empty relay map.
pub fn empty() -> Self {
Self {
relays: Default::default(),
}
}

/// Returns the URLs of all servers in this relay map.
///
/// This function is generic over the container to collect into. If you simply want a list
Expand All @@ -59,13 +66,6 @@ impl RelayMap {
.collect::<T>()
}

/// Creates an empty relay map.
pub fn empty() -> Self {
Self {
relays: Default::default(),
}
}

/// Returns a list with the [`RelayConfig`] for each relay in this relay map.
///
/// This function is generic over the container to collect into. If you simply want a list
Expand Down Expand Up @@ -111,14 +111,27 @@ impl RelayMap {
pub fn remove(&self, url: &RelayUrl) -> Option<Arc<RelayConfig>> {
self.relays.write().expect("poisoned").remove(url)
}

/// Extends this `RelayMap` with another one.
pub fn extend(&self, other: &RelayMap) {
let mut a = self.relays.write().expect("poisoned");
let b = other.relays.read().expect("poisoned");
a.extend(b.iter().map(|(a, b)| (a.clone(), b.clone())));
}
Comment on lines +116 to +120
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be impl Extend for RelayMap IMO.

Also: Why is there panicing expect inside of this function? This is not what a user expects from the documentation of the whole type!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After some discussion on your discord tho, using the Extend trait does not seem possible because of how the types are designed here.
And the std RwLock cannot easily be replaced by a tokio one 😢

}

impl FromIterator<RelayConfig> for RelayMap {
fn from_iter<T: IntoIterator<Item = RelayConfig>>(iter: T) -> Self {
Self::from_iter(iter.into_iter().map(Arc::new))
}
}

impl FromIterator<Arc<RelayConfig>> for RelayMap {
fn from_iter<T: IntoIterator<Item = Arc<RelayConfig>>>(iter: T) -> Self {
Self {
relays: Arc::new(RwLock::new(
iter.into_iter()
.map(|endpoint| (endpoint.url.clone(), Arc::new(endpoint)))
.map(|config| (config.url.clone(), config))
.collect(),
)),
}
Expand Down Expand Up @@ -220,3 +233,43 @@ impl fmt::Display for RelayConfig {
write!(f, "{}", self.url)
}
}

#[cfg(test)]
mod tests {
use std::str::FromStr;

use super::*;

#[test]
fn relay_map_extend() {
let urls1 = vec![
RelayUrl::from_str("https://hello-a-01.com").unwrap(),
RelayUrl::from_str("https://hello-b-01.com").unwrap(),
RelayUrl::from_str("https://hello-c-01-.com").unwrap(),
];

let urls2 = vec![
RelayUrl::from_str("https://hello-a-02.com").unwrap(),
RelayUrl::from_str("https://hello-b-02.com").unwrap(),
RelayUrl::from_str("https://hello-c-02-.com").unwrap(),
];

let map1 = RelayMap::from_iter(urls1.clone().into_iter().map(RelayConfig::from));
let map2 = RelayMap::from_iter(urls2.clone().into_iter().map(RelayConfig::from));

assert_ne!(map1, map2);

// combine

let map3 = RelayMap::from_iter(
map1.relays::<Vec<_>>()
.into_iter()
.chain(map2.relays::<Vec<_>>()),
);

assert_eq!(map3.len(), 6);

map1.extend(&map2);
assert_eq!(map3, map1);
}
}
Loading