diff options
| author | tv <tv@krebsco.de> | 2026-10-28 02:11:42 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-10-28 02:11:42 +0100 |
| commit | 3c56f0df5c23b5c8d4bc4cc748cbd18812910ffe (patch) | |
| tree | 1ea9d6ee06c84bc57952c7983d34173f1ee46b50 /src/transport/identity.rs | |
| parent | f7c22a02f6619ed5b6469bb660f33ced7e6a2b3e (diff) | |
failover between transports
Diffstat (limited to 'src/transport/identity.rs')
| -rw-r--r-- | src/transport/identity.rs | 60 |
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 |
