diff --git a/crates/dht/src/dht.rs b/crates/dht/src/dht.rs index 98ff51b..c255e75 100644 --- a/crates/dht/src/dht.rs +++ b/crates/dht/src/dht.rs @@ -971,9 +971,10 @@ impl DhtWorker { loop { interval.tick().await; let mut found = 0; + let now = Instant::now(); for node in self.dht.routing_table.read().iter() { if matches!( - node.status(), + node.status(now), NodeStatus::Questionable | NodeStatus::Unknown ) { found += 1; diff --git a/crates/dht/src/routing_table.rs b/crates/dht/src/routing_table.rs index 8189618..55b0c3f 100644 --- a/crates/dht/src/routing_table.rs +++ b/crates/dht/src/routing_table.rs @@ -286,10 +286,11 @@ impl BucketTree { }; // Try replace a bad node + let now = Instant::now(); if let Some(bad_node) = nodes .nodes .iter_mut() - .find(|r| matches!(r.status(), NodeStatus::Bad)) + .find(|r| matches!(r.status(now), NodeStatus::Bad)) { std::mem::swap(bad_node, &mut new_node); nodes.nodes.sort_by_key(|n| n.id); @@ -395,7 +396,7 @@ impl Serialize for RoutingTableNode { let mut s = serializer.serialize_struct("RoutingTableNode", 3)?; s.serialize_field("id", &self.id.as_string())?; s.serialize_field("addr", &self.addr)?; - s.serialize_field("status", &self.status())?; + s.serialize_field("status", &self.status(Instant::now()))?; if let Some(l) = self.last_request { s.serialize_field("last_request_ago", &l.elapsed())?; } @@ -425,7 +426,7 @@ impl RoutingTableNode { pub fn addr(&self) -> SocketAddr { self.addr } - pub fn status(&self) -> NodeStatus { + pub fn status(&self, now: Instant) -> NodeStatus { match (self.last_request, self.last_response, self.last_query) { // Nodes become bad when they fail to respond to multiple queries in a row. (Some(_), _, _) if self.errors_in_a_row >= 2 => NodeStatus::Bad, @@ -434,7 +435,7 @@ impl RoutingTableNode { // A node is also good if it has ever responded to one of our queries and has sent // us a query within the last 15 minutes. (Some(_), Some(last_incoming), _) | (Some(_), Some(_), Some(last_incoming)) - if last_incoming.elapsed() < INACTIVITY_TIMEOUT => + if now - last_incoming < INACTIVITY_TIMEOUT => { NodeStatus::Good } @@ -442,9 +443,9 @@ impl RoutingTableNode { // After 15 minutes of inactivity, a node becomes questionable. // The moment we send a request to it, it stops becoming questionable and becomes Unknown / Bad. (last_outgoing, _, Some(last_incoming)) | (last_outgoing, Some(last_incoming), _) - if last_incoming.elapsed() > INACTIVITY_TIMEOUT + if now - last_incoming > INACTIVITY_TIMEOUT && last_outgoing - .map(|e| e.elapsed() > INACTIVITY_TIMEOUT) + .map(|e| now - e > INACTIVITY_TIMEOUT) .unwrap_or(true) => { NodeStatus::Questionable @@ -504,11 +505,12 @@ impl RoutingTable { for node in self.buckets.iter() { result.push(node); } + let now = Instant::now(); result.sort_by_key(|n| { // Query decent nodes first. - let status = match n.status() { + let status = match n.status(now) { NodeStatus::Good => 0, - NodeStatus::Questionable => 0, + NodeStatus::Questionable => 1, NodeStatus::Unknown => 2, NodeStatus::Bad => 3, }; diff --git a/crates/librqbit_core/src/hash_id.rs b/crates/librqbit_core/src/hash_id.rs index 08ae619..927def8 100644 --- a/crates/librqbit_core/src/hash_id.rs +++ b/crates/librqbit_core/src/hash_id.rs @@ -1,8 +1,8 @@ use data_encoding::BASE32; use serde::{Deserialize, Deserializer, Serialize}; -use std::{cmp::Ordering, str::FromStr}; +use std::str::FromStr; -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Id(pub [u8; N]); impl Id { @@ -166,25 +166,6 @@ impl<'de, const N: usize> Deserialize<'de> for Id { } } -impl PartialOrd> for Id { - fn partial_cmp(&self, other: &Id) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Id { - fn cmp(&self, other: &Id) -> Ordering { - for (s, o) in self.0.iter().copied().zip(other.0.iter().copied()) { - match s.cmp(&o) { - Ordering::Less => return Ordering::Less, - Ordering::Equal => continue, - Ordering::Greater => return Ordering::Greater, - } - } - Ordering::Equal - } -} - /// A 20-byte hash used throughout librqbit, for torrent info hashes, peer ids etc. pub type Id20 = Id<20>; /// A 32-byte hash used in Bittorrent V2, for torrent info hashes, piece hashing, etc.