diff options
Diffstat (limited to 'src/transport/identity.rs')
| -rw-r--r-- | src/transport/identity.rs | 93 |
1 files changed, 69 insertions, 24 deletions
diff --git a/src/transport/identity.rs b/src/transport/identity.rs index 2b9bf5a..abedd35 100644 --- a/src/transport/identity.rs +++ b/src/transport/identity.rs @@ -22,7 +22,9 @@ //! with only hints, those are asked WHO, and the send is refused until one answers //! (the node retries refused sends). //! -//! Addresses are `<scheme>:<transport identity>`, e.g. `mycelium:<public key>`. +//! Addresses are `<scheme>:<transport identity>`, e.g. `mycelium:<public key>`, or +//! `<scheme>:<location>` where a transport needs more than an identity to reach a node +//! (`Transport::locate`, `Transport::locations`); the books keep the identities. use std::collections::HashMap; use std::sync::{Arc, Mutex, MutexGuard}; @@ -231,12 +233,33 @@ impl Shared { self.book.lock_or_recover() } - /// The transport `address` is on, and the transport identity in it; None if no - /// transport of ours has its scheme. - fn split<'a>(&self, address: &'a str) -> Option<(&Link, &'a str)> { + /// The transport `address` is on, and the transport identity at it + /// (`Transport::locate`, which notes where that is if the address says); None if no + /// transport of ours has its scheme, or it isn't one of that transport's. + fn split(&self, address: &str) -> Option<(&Link, String)> { let (scheme, target) = address.split_once(':')?; let link = self.links.iter().find(|link| link.scheme == scheme)?; - link.inner.is_peer_id(target).then_some((link, target)) + let target = link.inner.locate(target)?; + Some((link, target)) + } + + /// `address` as the books keep it: `<scheme>:<transport identity>`. + fn canonical(&self, address: &str) -> Option<String> { + self.split(address) + .map(|(link, target)| link.address(&target)) + } + + /// Where the node at `address` (as the books keep it) is, as others can use it + /// (`Transport::locations`). + fn locations(&self, address: &str) -> Vec<String> { + let Some((link, target)) = self.split(address) else { + return Vec::new(); + }; + link.inner + .locations(&target) + .iter() + .map(|location| link.address(location)) + .collect() } /// Where `address`'s transport is in the order of preference (none of ours: last). @@ -301,11 +324,11 @@ impl Shared { return; }; let message = if kind == MessageKind::Who { - ParsedMessage::Who(self.proof(WHO_LABEL, link, target)) + ParsedMessage::Who(self.proof(WHO_LABEL, link, &target)) } else { - ParsedMessage::Me(self.proof(ME_LABEL, link, target)) + ParsedMessage::Me(self.proof(ME_LABEL, link, &target)) }; - let encoded = match link.inner.encode(target, &message) { + let encoded = match link.inner.encode(&target, &message) { Ok(encoded) => encoded, Err(error) => { debug!(to = %address, error = %format!("{error:#}"), "Couldn't encode an identity proof"); @@ -419,17 +442,39 @@ impl Transport for IdentityTransport { .unwrap_or_default() } + /// Each transport's (`Transport::local_addresses`), with its scheme. fn local_addresses(&self) -> Vec<String> { - self.shared.links.iter().map(Link::own_address).collect() + self.shared + .links + .iter() + .flat_map(|link| { + link.inner + .local_addresses() + .into_iter() + .map(|target| link.address(&target)) + }) + .collect() } + /// Where `peer` proved itself, else where it is said to be, as others can use it. fn addresses_of(&self, peer: &str) -> Vec<String> { - let book = self.shared.lock(); - book.proven - .get(peer) - .or_else(|| book.hints.get(peer)) - .cloned() - .unwrap_or_default() + let addresses = { + let book = self.shared.lock(); + book.proven + .get(peer) + .or_else(|| book.hints.get(peer)) + .cloned() + .unwrap_or_default() + }; + let mut locations = Vec::new(); + for address in addresses { + for location in self.shared.locations(&address) { + if !locations.contains(&location) { + locations.push(location); + } + } + } + locations } fn learn_addresses(&self, peer: &str, addresses: &[String]) { @@ -438,11 +483,11 @@ impl Transport for IdentityTransport { } let mut known: Vec<String> = Vec::new(); for address in addresses { - if self.shared.split(address).is_some() - && !self.shared.is_own(address) - && !known.contains(address) + if let Some(address) = self.shared.canonical(address) + && !self.shared.is_own(&address) + && !known.contains(&address) { - known.push(address.clone()); + known.push(address); } } known.truncate(MAX_HINTS); @@ -469,8 +514,8 @@ impl Transport for IdentityTransport { } bail!("a node ID alone doesn't say where that node is; give its address"); } - let address = match self.shared.split(seed) { - Some(_) => seed.to_owned(), + let address = match self.shared.canonical(seed) { + Some(address) => address, None => { let mut failures = Vec::new(); let mut resolved = None; @@ -521,7 +566,7 @@ impl Transport for IdentityTransport { let Some((link, target)) = self.shared.split(&address) else { bail!("no transport for {address}"); }; - let mut encoded = link.inner.encode(target, message)?; + let mut encoded = link.inner.encode(&target, message)?; encoded.peer = peer.to_owned(); encoded.address = address; Ok(encoded) @@ -550,8 +595,8 @@ impl Transport for IdentityTransport { bail!("no transport for {}", message.address); }; let mut inner = message.clone(); - inner.peer = target.to_owned(); - inner.address = target.to_owned(); + inner.peer = target.clone(); + inner.address = target; link.inner.send_encoded(&inner).await } |
