summaryrefslogtreecommitdiffstats
path: root/src/transport/identity.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-28 02:11:42 +0100
committertv <tv@krebsco.de>2026-10-28 02:11:42 +0100
commit3c56f0df5c23b5c8d4bc4cc748cbd18812910ffe (patch)
tree1ea9d6ee06c84bc57952c7983d34173f1ee46b50 /src/transport/identity.rs
parentf7c22a02f6619ed5b6469bb660f33ced7e6a2b3e (diff)
failover between transports
Diffstat (limited to 'src/transport/identity.rs')
-rw-r--r--src/transport/identity.rs60
1 files changed, 33 insertions, 27 deletions
diff --git a/src/transport/identity.rs b/src/transport/identity.rs
index 7633ac1..dd3950b 100644
--- a/src/transport/identity.rs
+++ b/src/transport/identity.rs
@@ -17,10 +17,10 @@
//! * A seed (`resolve_seed`) is an address, or something one of the transports resolves
//! to one; it is asked WHO, and its ME says which node is there.
//! * Where other nodes are comes from the member list and HELLO_REPLYs
-//! (`learn_addresses`): hints, not proofs. A message to a node goes to an address it
-//! proved itself at (on the first transport in the configured order that has one);
-//! with only hints, those are asked WHO, and the send is refused until one answers
-//! (the node retries refused sends).
+//! (`learn_addresses`): hints, not proofs. A message to a node goes to the addresses
+//! it proved itself at, best first (`Paths::rank`, `Paths::send_first`: the next
+//! when a send fails); with only hints, those are asked WHO, and the send is refused
+//! until one answers (the node retries refused sends).
//!
//! Addresses and the transports behind them are the paths layer's
//! (`transport::paths`): the books keep addresses as paths keep them.
@@ -354,15 +354,22 @@ impl Shared {
/// Where to send to `peer`: an address it proved itself at, else one it is said to
/// be at; the most preferred transport's first.
fn destination(&self, peer: &str) -> Option<String> {
- let book = self.lock();
- let pick = |addresses: Option<&Vec<String>>| {
- addresses?
- .iter()
- .filter(|address| self.paths.usable(address))
- .min_by_key(|address| self.paths.preference(address))
- .cloned()
- };
- pick(book.proven.get(peer)).or_else(|| pick(book.hints.get(peer)))
+ self.proven_at(peer)
+ .into_iter()
+ .next()
+ .or_else(|| self.hinted_at(peer).into_iter().next())
+ }
+
+ /// The addresses `peer` proved itself at, best first (`Paths::rank`).
+ fn proven_at(&self, peer: &str) -> Vec<String> {
+ let proven = self.lock().proven.get(peer).cloned().unwrap_or_default();
+ self.paths.rank(&proven)
+ }
+
+ /// Where `peer` is said to be, best first.
+ fn hinted_at(&self, peer: &str) -> Vec<String> {
+ let hints = self.lock().hints.get(peer).cloned().unwrap_or_default();
+ self.paths.rank(&hints)
}
}
@@ -518,27 +525,26 @@ impl Transport for IdentityTransport {
Ok(encoded)
}
+ /// To the addresses `peer` proved itself at, best first, the next when a send
+ /// fails (`Paths::send_first`); refused if it proved itself nowhere yet.
async fn send_encoded(&self, message: &EncodedMessage) -> Result<()> {
- let hints = {
- let mut book = self.shared.lock();
- let proven = book
- .proven
- .get(&message.peer)
- .is_some_and(|addresses| addresses.contains(&message.address));
- if proven {
- None
- } else {
+ let proven = self.shared.proven_at(&message.peer);
+ if proven.is_empty() {
+ let hints = {
+ let mut book = self.shared.lock();
book.counts.refused_unproven += 1;
- Some(book.hints.get(&message.peer).cloned().unwrap_or_default())
- }
- };
- if let Some(hints) = hints {
+ book.hints.get(&message.peer).cloned().unwrap_or_default()
+ };
for address in hints {
self.shared.ask(&address, false);
}
return Err(NotProven(message.peer.clone()).into());
}
- self.shared.paths.send(message).await
+ self.shared
+ .paths
+ .send_first(message, &proven)
+ .await
+ .map(|_| ())
}
/// Every transport's consumer (`Paths::start_consumer`); returns when the first